如何配置 Swashbuckle 以忽略模型上的 属性
How to configure Swashbuckle to ignore property on model
我正在使用 Swashbuckle 为 webapi2 项目生成 swagger documentation\UI。我们的模型与一些遗留接口共享,因此我想在模型上忽略几个属性。我不能使用 JsonIgnore 属性,因为遗留接口也需要序列化为 JSON 所以我不想全局忽略这些属性,只是在 Swashbuckle 配置中。
我在此处找到了执行此操作的方法:
https://github.com/domaindrivendev/Swashbuckle/issues/73
但这对于当前的 Swashbuckle 版本来说似乎已经过时了。
推荐用于旧版本 Swashbuckle 的方法是使用 IModelFilter 实现,如下所示:
public class OmitIgnoredProperties : IModelFilter
{
public void Apply(DataType model, DataTypeRegistry dataTypeRegistry, Type type)
{
var ignoredProperties = … // use reflection to find any properties on
// type decorated with the ignore attributes
foreach (var prop in ignoredProperties)
model.Properties.Remove(prop.Name);
}
}
SwaggerSpecConfig.Customize(c => c.ModelFilter<OmitIgnoredProperties>());
但我不确定如何配置 Swashbuckle 以在当前版本中使用 IModelFilter?我正在使用 Swashbuckle 5.5.3。
好吧,经过一番摸索,我找到了使用 ISchemaFilter 执行此操作的方法:
public class ApplyCustomSchemaFilters : ISchemaFilter
{
public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type)
{
var excludeProperties = new[] {"myProp1", "myProp2", "myProp3"};
foreach(var prop in excludeProperties)
if (schema.properties.ContainsKey(prop))
schema.properties.Remove(prop);
}
}
然后在调用 httpConfiguration.EnableSwagger
时,我将 SwaggerDocsConfig
设置为使用此 SchemaFilter,如下所示:
c.SchemaFilter<ApplyCustomSchemaFilters>();
希望这对某人有所帮助。不过,我仍然很好奇是否可以以某种方式使用 IModelFilter。
(.)
我添加了另一行以避免 NullReferenceException
出现问题。
public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type)
{
var excludeProperties = new[] { "myProp1", "myProp2, myProp3"};
foreach (var prop in excludeProperties)
<b><i> if(schema.properties != null) // This line</i></b>
if (schema.properties.ContainsKey(prop))
schema.properties.Remove(prop);
}
如果要删除所有架构
public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type)
{
schema.properties = null;
}
这是我在 Newtonsoft.Json.JsonIgnoreAttribute 中使用的内容:
internal class ApplySchemaVendorExtensions : Swashbuckle.Swagger.ISchemaFilter
{
public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type)
{
foreach (var prop in type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)
.Where(p => p.GetCustomAttributes(typeof(Newtonsoft.Json.JsonIgnoreAttribute), true)?.Any() == true))
if (schema?.properties?.ContainsKey(prop.Name) == true)
schema?.properties?.Remove(prop.Name);
}
}
如果您将 field/property 标记为 internal
或 protected
或 private
,它会被 swagger 文档中的 swashbuckle 自动忽略。
更新:显然,那些 properties/fields 不会填充到 request/response.
如果您需要这样做但不使用 JsonIgnore(也许您仍然需要 serialize/deserialize 属性),那么只需创建一个自定义属性即可。
[AttributeUsage(AttributeTargets.Property)]
public class SwaggerExcludeAttribute : Attribute
{
}
然后是类似于
的架构过滤器
public class SwaggerExcludeFilter : ISchemaFilter
{
#region ISchemaFilter Members
public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type)
{
if (schema?.properties == null || type == null)
return;
var excludedProperties = type.GetProperties()
.Where(t =>
t.GetCustomAttribute<SwaggerExcludeAttribute>()
!= null);
foreach (var excludedProperty in excludedProperties)
{
if (schema.properties.ContainsKey(excludedProperty.Name))
schema.properties.Remove(excludedProperty.Name);
}
}
#endregion
}
别忘了注册过滤器
c.SchemaFilter<SwaggerExcludeFilter>();
AspNetCore
解决方案如下所示:
public class SwaggerExcludeSchemaFilter : ISchemaFilter
{
public void Apply(Schema schema, SchemaFilterContext context)
{
if (schema?.Properties == null)
{
return;
}
var excludedProperties = context.SystemType.GetProperties().Where(t => t.GetCustomAttribute<SwaggerExcludeAttribute>() != null);
foreach (PropertyInfo excludedProperty in excludedProperties)
{
if (schema.Properties.ContainsKey(excludedProperty.Name))
{
schema.Properties.Remove(excludedProperty.Name);
}
}
}
}
用于标记要从 Swagger 文档中排除的属性的属性。
[AttributeUsage(AttributeTargets.Property)]
public class SwaggerExcludeAttribute : Attribute
{
}
从 Swagger 文档中排除属性的过滤器。
public class SwaggerExcludeSchemaFilter : ISchemaFilter
{
public void Apply(Schema schema, SchemaFilterContext context)
{
if (schema?.Properties == null)
{
return;
}
var excludedProperties =
context.SystemType.GetProperties().Where(
t => t.GetCustomAttribute<SwaggerExcludeAttribute>() != null);
foreach (var excludedProperty in excludedProperties)
{
var propertyToRemove =
schema.Properties.Keys.SingleOrDefault(
x => x.ToLower() == excludedProperty.Name.ToLower());
if (propertyToRemove != null)
{
schema.Properties.Remove(propertyToRemove);
}
}
}
}
schema.Properties.Keys
是 camelCase
,而属性本身是 PascalCase
。调整方法以将两者都转换为小写并进行比较以查看应排除的内容。
对于像我这样使用 .Net Core 并使用 app.UseSwaggerUi3WithApiExplorer()
中的构建的人
使用 [JsonIgnore]
标签使用 Newtonsoft.Json;
public class Project
{
[Required]
public string ProjectName { get; set; }
[JsonIgnore]
public string SomeValueYouWantToIgnore { get; set; }
}
它将从您的文档中排除。
下面的代码很大程度上基于@Richard 的回答,但我将它作为一个新答案包括在内,因为它具有我添加的三个全新的、有用的功能:
- 在最新版本的 Swashbuckle (v5) 上的 .NET Core 上运行
- 允许
SwaggerIgnore
属性应用于字段而不仅仅是属性
- 处理 属性 和字段名称可能已使用
JsonProperty
属性覆盖的事实
- 编辑:现在可以正确处理原始 TitleCased 字段或属性的驼峰式大小写(@mattruma 的回答提示)
所以修改后的代码是:
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class SwaggerIgnoreAttribute : Attribute
{
}
internal static class StringExtensions
{
internal static string ToCamelCase(this string value)
{
if (string.IsNullOrEmpty(value)) return value;
return char.ToLowerInvariant(value[0]) + value.Substring(1);
}
}
public class SwaggerIgnoreFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext schemaFilterContext)
{
if (schema.Properties.Count == 0)
return;
const BindingFlags bindingFlags = BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance;
var memberList = schemaFilterContext.SystemType // In v5.3.3+ use Type instead
.GetFields(bindingFlags).Cast<MemberInfo>()
.Concat(schemaFilterContext.SystemType // In v5.3.3+ use Type instead
.GetProperties(bindingFlags));
var excludedList = memberList.Where(m =>
m.GetCustomAttribute<SwaggerIgnoreAttribute>()
!= null)
.Select(m =>
(m.GetCustomAttribute<JsonPropertyAttribute>()
?.PropertyName
?? m.Name.ToCamelCase()));
foreach (var excludedName in excludedList)
{
if (schema.Properties.ContainsKey(excludedName))
schema.Properties.Remove(excludedName);
}
}
}
并在 Startup.cs
中:
services.AddSwaggerGen(c =>
{
...
c.SchemaFilter<SwaggerIgnoreFilter>();
...
});
我这里有一个使用 DotNetCore 3 和 Swashbuckle 5 的工作示例。我花了几个小时才准备好它,所以我想回到这个对我有帮助但没有解决我的问题的线程。
创建虚拟自定义属性:
[AttributeUsage(AttributeTargets.Property)]
public class SwaggerExcludeAttribute : Attribute { }
创建一个 SchemaFilter,swagger 将使用它来生成 API 模型架构
public class SwaggerExcludeFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (!(context.ApiModel is ApiObject))
{
return;
}
var model = context.ApiModel as ApiObject;
if (schema?.Properties == null || model?.ApiProperties == null)
{
return;
}
var excludedProperties = model.Type
.GetProperties()
.Where(
t => t.GetCustomAttribute<SwaggerExcludeAttribute>() != null
);
var excludedSchemaProperties = model.ApiProperties
.Where(
ap => excludedProperties.Any(
pi => pi.Name == ap.MemberInfo.Name
)
);
foreach (var propertyToExclude in excludedSchemaProperties)
{
schema.Properties.Remove(propertyToExclude.ApiName);
}
}
}
然后,在 Startup.cs
文件中将其添加到 swagger 配置中
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
c.SchemaFilter<SwaggerExcludeFilter>();
});
您现在可以在要从 API 模式 Shema 中排除的 属性 使用自定义属性
public class MyApiModel
{
[SwaggerExclude]
public Guid Token { get; set; }
public int Id { get; set; }
public string Name { get; set; }
}
参考答案,创建过滤器只需使用以下代码:
public class SwaggerExcludeFilter : ISchemaFilter
{
public void Apply(OpenApiSchema model, SchemaFilterContext context)
{
var excludeProperties = context.ApiModel.Type?.GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(SwaggerExcludeAttribute)));
if (excludeProperties != null)
{
foreach (var property in excludeProperties)
{
// Because swagger uses camel casing
var propertyName = $"{ToLowerInvariant(property.Name[0])}{property.Name.Substring(1)}";
if (model.Properties.ContainsKey(propertyName))
{
model.Properties.Remove(propertyName);
}
}
}
}
}
.NET Core 3.1 和 .NET Standard 2.1 的解决方案:
使用 System.Text.Json.Serialization
命名空间中的 JsonIgnore
。
(Newtonsoft.Json
中的 JsonIgnore
将不起作用)
public class Test
{
[System.Text.Json.Serialization.JsonIgnore]
public int HiddenProperty { get; set; }
public int VisibleProperty { get; set; }
}
Swashbuckle 现在支持 Newtonsoft。
https://github.com/domaindrivendev/Swashbuckle.AspNetCore#systemtextjson-stj-vs-newtonsoft
dotnet add package --version 5.3.1 Swashbuckle.AspNetCore.Newtonsoft
`services.AddSwaggerGenNewtonsoftSupport(); // explicit opt-in - needs tobe placed after AddSwaggerGen();`
在我的例子中,我想保持我的应用层 DTO 干净(没有像 JsonIngore 这样的任何注释)但仍然能够在我的控制器 Web APIs 中使用它们。
所以,在我的应用程序层中,我有一个这样的 DTO:
public class CreateItemCommand {
public Guid ContainerId { get; set; }
public string Name { get; set; }
}
我的 API 创建项目的设计是这样的:
POST /containers/{containerId}/items
由于 ContainerId 来自 api 路由,我不希望 asp.net 核心试图将它绑定到命令 DTO 中,我也不希望 swashbuckle 列出它。
所以我的解决方案是像这样继承API层中的原始DTO:
public class CreateItemCommandMod : CreateItemCommand {
#pragma warning disable IDE0051
private new ContainerID { get; }
#pragma warning restore IDE0051
}
...
[HttpPost("{containerId}/items}")]
public Task Create(
[FromRoute] Guid containerId,
[FromBody] CreateItemCommandMod command,
) => useCase.Create(command.Apply(r => r.ContainerId = containerId));
- ApplicationLayer 中的 useCase.Create 需要基础 class CreateItemCommand。
- .apply只是我做的一个很简单的扩展方法,可以方便的将路由参数值设置到对应的dto中属性.
我从 Ignoring properties from controller action model in Swagger using JsonIgnore 的博客中得到启发。
我正在使用 .net core 2.1
和 Swashbuckle.AspNetCore 5.3.1
。
下面的代码解决了这个问题。
添加新过滤器
public class SwaggerJsonIgnoreFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var ignoredProperties = context.MethodInfo.GetParameters()
.SelectMany(p => p.ParameterType.GetProperties()
.Where(prop => prop.GetCustomAttribute<JsonIgnoreAttribute>() != null))
.ToList();
if (!ignoredProperties.Any()) return;
foreach (var property in ignoredProperties)
{
operation.Parameters = operation.Parameters
.Where(p => (!p.Name.Equals(property.Name, StringComparison.InvariantCulture)))
.ToList();
}
}
}
使用 Startup.cs
中的过滤器
public void ConfigureServices(IServiceCollection services)
{
......
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo { Title = "CustomApi", Version = "v1" });
options.OperationFilter<SwaggerJsonIgnoreFilter>();
});
......
}
这是一个较旧的问题,但此后在 Swashbuckle 中提供了一种省力的中间解决方案。
从文档中隐藏遗留属性并不会阻止对这些属性的使用——它只会延迟发现。毕竟,它们仍然是模型的一部分。事实上,让它们没有记录意味着消费者无法知道他们不应该使用它们!
与其让它们无文档记录,不如简单地考虑将它们标记为 [Obsolete]
。
Swashbuckle 将在 swagger.json 中将它们标记为已弃用。在 UI 中,这会将它们隐藏在“示例值”部分中,而在“架构”部分中,它们将显示为灰色,并在名称上添加删除线。
如果您仍然希望它们在文档中完全隐藏,您可以在 SwaggerGeneratorOptions.IgnoreObsoleteProperties = true
.
中设置
最初提出此问题时,这不是可行的解决方案。 已弃用 标志是 OpenAPI v3 的一项功能,直到 2017 年才发布。
你可以使用Swashbuckle.AspNetCore.Annotations
包,它允许你标记一些属性只在输入参数中显示,一些属性只在输出中显示。
例如,如果你想隐藏post的输入参数中的AlertId
,你只需要通过[SwaggerSchema]
:
public class Alert
{
[SwaggerSchema(ReadOnly = true)]
public string AlertId { get; set; }
public string Type { get; set; }
}
中查看更多信息
我需要更多的控制来删除在别处声明的属性,并且不能轻易使用删除属性。
创建的过滤器删除了它从我的 excludes
列表中遇到的所有项目:
public class SwaggerExcludeFilter : ISchemaFilter
{
private static readonly List<string> excludes = new List<string>()
{
"StoredProcedureName", "ValidationErrors", "changeTracker",
"code", "customerId", "IsDebug",
};
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (schema?.Properties == null || context == null)
return;
// Find all properties by name which need to be removed
// and not shown on the swagger spec.
schema.Properties
.Where(prp => excludes.Any(exc => string.Equals(exc, prp.Key, StringComparison.OrdinalIgnoreCase)))
.Select(prExclude => prExclude.Key)
.ToList()
.ForEach(key => schema.Properties.Remove(key));
}
}
正在启动或 program.cs .Net 6 粉丝。
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info
{
Version = "2.5",
Title = "My Swagger Doc G",
});
c.SchemaFilter<SwaggerExcludeFilter>();
...
我正在使用 Swashbuckle 为 webapi2 项目生成 swagger documentation\UI。我们的模型与一些遗留接口共享,因此我想在模型上忽略几个属性。我不能使用 JsonIgnore 属性,因为遗留接口也需要序列化为 JSON 所以我不想全局忽略这些属性,只是在 Swashbuckle 配置中。
我在此处找到了执行此操作的方法:
https://github.com/domaindrivendev/Swashbuckle/issues/73
但这对于当前的 Swashbuckle 版本来说似乎已经过时了。
推荐用于旧版本 Swashbuckle 的方法是使用 IModelFilter 实现,如下所示:
public class OmitIgnoredProperties : IModelFilter
{
public void Apply(DataType model, DataTypeRegistry dataTypeRegistry, Type type)
{
var ignoredProperties = … // use reflection to find any properties on
// type decorated with the ignore attributes
foreach (var prop in ignoredProperties)
model.Properties.Remove(prop.Name);
}
}
SwaggerSpecConfig.Customize(c => c.ModelFilter<OmitIgnoredProperties>());
但我不确定如何配置 Swashbuckle 以在当前版本中使用 IModelFilter?我正在使用 Swashbuckle 5.5.3。
好吧,经过一番摸索,我找到了使用 ISchemaFilter 执行此操作的方法:
public class ApplyCustomSchemaFilters : ISchemaFilter
{
public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type)
{
var excludeProperties = new[] {"myProp1", "myProp2", "myProp3"};
foreach(var prop in excludeProperties)
if (schema.properties.ContainsKey(prop))
schema.properties.Remove(prop);
}
}
然后在调用 httpConfiguration.EnableSwagger
时,我将 SwaggerDocsConfig
设置为使用此 SchemaFilter,如下所示:
c.SchemaFilter<ApplyCustomSchemaFilters>();
希望这对某人有所帮助。不过,我仍然很好奇是否可以以某种方式使用 IModelFilter。
(
我添加了另一行以避免 NullReferenceException
出现问题。
public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type)
{
var excludeProperties = new[] { "myProp1", "myProp2, myProp3"};
foreach (var prop in excludeProperties)
<b><i> if(schema.properties != null) // This line</i></b>
if (schema.properties.ContainsKey(prop))
schema.properties.Remove(prop);
}
如果要删除所有架构
public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type)
{
schema.properties = null;
}
这是我在 Newtonsoft.Json.JsonIgnoreAttribute 中使用的内容:
internal class ApplySchemaVendorExtensions : Swashbuckle.Swagger.ISchemaFilter
{
public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type)
{
foreach (var prop in type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)
.Where(p => p.GetCustomAttributes(typeof(Newtonsoft.Json.JsonIgnoreAttribute), true)?.Any() == true))
if (schema?.properties?.ContainsKey(prop.Name) == true)
schema?.properties?.Remove(prop.Name);
}
}
如果您将 field/property 标记为 internal
或 protected
或 private
,它会被 swagger 文档中的 swashbuckle 自动忽略。
更新:显然,那些 properties/fields 不会填充到 request/response.
如果您需要这样做但不使用 JsonIgnore(也许您仍然需要 serialize/deserialize 属性),那么只需创建一个自定义属性即可。
[AttributeUsage(AttributeTargets.Property)]
public class SwaggerExcludeAttribute : Attribute
{
}
然后是类似于
public class SwaggerExcludeFilter : ISchemaFilter
{
#region ISchemaFilter Members
public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type)
{
if (schema?.properties == null || type == null)
return;
var excludedProperties = type.GetProperties()
.Where(t =>
t.GetCustomAttribute<SwaggerExcludeAttribute>()
!= null);
foreach (var excludedProperty in excludedProperties)
{
if (schema.properties.ContainsKey(excludedProperty.Name))
schema.properties.Remove(excludedProperty.Name);
}
}
#endregion
}
别忘了注册过滤器
c.SchemaFilter<SwaggerExcludeFilter>();
AspNetCore
解决方案如下所示:
public class SwaggerExcludeSchemaFilter : ISchemaFilter
{
public void Apply(Schema schema, SchemaFilterContext context)
{
if (schema?.Properties == null)
{
return;
}
var excludedProperties = context.SystemType.GetProperties().Where(t => t.GetCustomAttribute<SwaggerExcludeAttribute>() != null);
foreach (PropertyInfo excludedProperty in excludedProperties)
{
if (schema.Properties.ContainsKey(excludedProperty.Name))
{
schema.Properties.Remove(excludedProperty.Name);
}
}
}
}
用于标记要从 Swagger 文档中排除的属性的属性。
[AttributeUsage(AttributeTargets.Property)]
public class SwaggerExcludeAttribute : Attribute
{
}
从 Swagger 文档中排除属性的过滤器。
public class SwaggerExcludeSchemaFilter : ISchemaFilter
{
public void Apply(Schema schema, SchemaFilterContext context)
{
if (schema?.Properties == null)
{
return;
}
var excludedProperties =
context.SystemType.GetProperties().Where(
t => t.GetCustomAttribute<SwaggerExcludeAttribute>() != null);
foreach (var excludedProperty in excludedProperties)
{
var propertyToRemove =
schema.Properties.Keys.SingleOrDefault(
x => x.ToLower() == excludedProperty.Name.ToLower());
if (propertyToRemove != null)
{
schema.Properties.Remove(propertyToRemove);
}
}
}
}
schema.Properties.Keys
是 camelCase
,而属性本身是 PascalCase
。调整方法以将两者都转换为小写并进行比较以查看应排除的内容。
对于像我这样使用 .Net Core 并使用 app.UseSwaggerUi3WithApiExplorer()
使用 [JsonIgnore]
标签使用 Newtonsoft.Json;
public class Project
{
[Required]
public string ProjectName { get; set; }
[JsonIgnore]
public string SomeValueYouWantToIgnore { get; set; }
}
它将从您的文档中排除。
下面的代码很大程度上基于@Richard 的回答,但我将它作为一个新答案包括在内,因为它具有我添加的三个全新的、有用的功能:
- 在最新版本的 Swashbuckle (v5) 上的 .NET Core 上运行
- 允许
SwaggerIgnore
属性应用于字段而不仅仅是属性 - 处理 属性 和字段名称可能已使用
JsonProperty
属性覆盖的事实 - 编辑:现在可以正确处理原始 TitleCased 字段或属性的驼峰式大小写(@mattruma 的回答提示)
所以修改后的代码是:
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class SwaggerIgnoreAttribute : Attribute
{
}
internal static class StringExtensions
{
internal static string ToCamelCase(this string value)
{
if (string.IsNullOrEmpty(value)) return value;
return char.ToLowerInvariant(value[0]) + value.Substring(1);
}
}
public class SwaggerIgnoreFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext schemaFilterContext)
{
if (schema.Properties.Count == 0)
return;
const BindingFlags bindingFlags = BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance;
var memberList = schemaFilterContext.SystemType // In v5.3.3+ use Type instead
.GetFields(bindingFlags).Cast<MemberInfo>()
.Concat(schemaFilterContext.SystemType // In v5.3.3+ use Type instead
.GetProperties(bindingFlags));
var excludedList = memberList.Where(m =>
m.GetCustomAttribute<SwaggerIgnoreAttribute>()
!= null)
.Select(m =>
(m.GetCustomAttribute<JsonPropertyAttribute>()
?.PropertyName
?? m.Name.ToCamelCase()));
foreach (var excludedName in excludedList)
{
if (schema.Properties.ContainsKey(excludedName))
schema.Properties.Remove(excludedName);
}
}
}
并在 Startup.cs
中:
services.AddSwaggerGen(c =>
{
...
c.SchemaFilter<SwaggerIgnoreFilter>();
...
});
我这里有一个使用 DotNetCore 3 和 Swashbuckle 5 的工作示例。我花了几个小时才准备好它,所以我想回到这个对我有帮助但没有解决我的问题的线程。
创建虚拟自定义属性:
[AttributeUsage(AttributeTargets.Property)]
public class SwaggerExcludeAttribute : Attribute { }
创建一个 SchemaFilter,swagger 将使用它来生成 API 模型架构
public class SwaggerExcludeFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (!(context.ApiModel is ApiObject))
{
return;
}
var model = context.ApiModel as ApiObject;
if (schema?.Properties == null || model?.ApiProperties == null)
{
return;
}
var excludedProperties = model.Type
.GetProperties()
.Where(
t => t.GetCustomAttribute<SwaggerExcludeAttribute>() != null
);
var excludedSchemaProperties = model.ApiProperties
.Where(
ap => excludedProperties.Any(
pi => pi.Name == ap.MemberInfo.Name
)
);
foreach (var propertyToExclude in excludedSchemaProperties)
{
schema.Properties.Remove(propertyToExclude.ApiName);
}
}
}
然后,在 Startup.cs
文件中将其添加到 swagger 配置中
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
c.SchemaFilter<SwaggerExcludeFilter>();
});
您现在可以在要从 API 模式 Shema 中排除的 属性 使用自定义属性
public class MyApiModel
{
[SwaggerExclude]
public Guid Token { get; set; }
public int Id { get; set; }
public string Name { get; set; }
}
参考
public class SwaggerExcludeFilter : ISchemaFilter
{
public void Apply(OpenApiSchema model, SchemaFilterContext context)
{
var excludeProperties = context.ApiModel.Type?.GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(SwaggerExcludeAttribute)));
if (excludeProperties != null)
{
foreach (var property in excludeProperties)
{
// Because swagger uses camel casing
var propertyName = $"{ToLowerInvariant(property.Name[0])}{property.Name.Substring(1)}";
if (model.Properties.ContainsKey(propertyName))
{
model.Properties.Remove(propertyName);
}
}
}
}
}
.NET Core 3.1 和 .NET Standard 2.1 的解决方案:
使用 System.Text.Json.Serialization
命名空间中的 JsonIgnore
。
(Newtonsoft.Json
中的 JsonIgnore
将不起作用)
public class Test
{
[System.Text.Json.Serialization.JsonIgnore]
public int HiddenProperty { get; set; }
public int VisibleProperty { get; set; }
}
Swashbuckle 现在支持 Newtonsoft。 https://github.com/domaindrivendev/Swashbuckle.AspNetCore#systemtextjson-stj-vs-newtonsoft
dotnet add package --version 5.3.1 Swashbuckle.AspNetCore.Newtonsoft
`services.AddSwaggerGenNewtonsoftSupport(); // explicit opt-in - needs tobe placed after AddSwaggerGen();`
在我的例子中,我想保持我的应用层 DTO 干净(没有像 JsonIngore 这样的任何注释)但仍然能够在我的控制器 Web APIs 中使用它们。
所以,在我的应用程序层中,我有一个这样的 DTO:
public class CreateItemCommand {
public Guid ContainerId { get; set; }
public string Name { get; set; }
}
我的 API 创建项目的设计是这样的:
POST /containers/{containerId}/items
由于 ContainerId 来自 api 路由,我不希望 asp.net 核心试图将它绑定到命令 DTO 中,我也不希望 swashbuckle 列出它。
所以我的解决方案是像这样继承API层中的原始DTO:
public class CreateItemCommandMod : CreateItemCommand {
#pragma warning disable IDE0051
private new ContainerID { get; }
#pragma warning restore IDE0051
}
...
[HttpPost("{containerId}/items}")]
public Task Create(
[FromRoute] Guid containerId,
[FromBody] CreateItemCommandMod command,
) => useCase.Create(command.Apply(r => r.ContainerId = containerId));
- ApplicationLayer 中的 useCase.Create 需要基础 class CreateItemCommand。
- .apply只是我做的一个很简单的扩展方法,可以方便的将路由参数值设置到对应的dto中属性.
我从 Ignoring properties from controller action model in Swagger using JsonIgnore 的博客中得到启发。
我正在使用 .net core 2.1
和 Swashbuckle.AspNetCore 5.3.1
。
下面的代码解决了这个问题。
添加新过滤器
public class SwaggerJsonIgnoreFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var ignoredProperties = context.MethodInfo.GetParameters()
.SelectMany(p => p.ParameterType.GetProperties()
.Where(prop => prop.GetCustomAttribute<JsonIgnoreAttribute>() != null))
.ToList();
if (!ignoredProperties.Any()) return;
foreach (var property in ignoredProperties)
{
operation.Parameters = operation.Parameters
.Where(p => (!p.Name.Equals(property.Name, StringComparison.InvariantCulture)))
.ToList();
}
}
}
使用 Startup.cs
中的过滤器public void ConfigureServices(IServiceCollection services)
{
......
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo { Title = "CustomApi", Version = "v1" });
options.OperationFilter<SwaggerJsonIgnoreFilter>();
});
......
}
这是一个较旧的问题,但此后在 Swashbuckle 中提供了一种省力的中间解决方案。
从文档中隐藏遗留属性并不会阻止对这些属性的使用——它只会延迟发现。毕竟,它们仍然是模型的一部分。事实上,让它们没有记录意味着消费者无法知道他们不应该使用它们!
与其让它们无文档记录,不如简单地考虑将它们标记为 [Obsolete]
。
Swashbuckle 将在 swagger.json 中将它们标记为已弃用。在 UI 中,这会将它们隐藏在“示例值”部分中,而在“架构”部分中,它们将显示为灰色,并在名称上添加删除线。
如果您仍然希望它们在文档中完全隐藏,您可以在 SwaggerGeneratorOptions.IgnoreObsoleteProperties = true
.
最初提出此问题时,这不是可行的解决方案。 已弃用 标志是 OpenAPI v3 的一项功能,直到 2017 年才发布。
你可以使用Swashbuckle.AspNetCore.Annotations
包,它允许你标记一些属性只在输入参数中显示,一些属性只在输出中显示。
例如,如果你想隐藏post的输入参数中的AlertId
,你只需要通过[SwaggerSchema]
:
public class Alert
{
[SwaggerSchema(ReadOnly = true)]
public string AlertId { get; set; }
public string Type { get; set; }
}
中查看更多信息
我需要更多的控制来删除在别处声明的属性,并且不能轻易使用删除属性。
创建的过滤器删除了它从我的 excludes
列表中遇到的所有项目:
public class SwaggerExcludeFilter : ISchemaFilter
{
private static readonly List<string> excludes = new List<string>()
{
"StoredProcedureName", "ValidationErrors", "changeTracker",
"code", "customerId", "IsDebug",
};
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (schema?.Properties == null || context == null)
return;
// Find all properties by name which need to be removed
// and not shown on the swagger spec.
schema.Properties
.Where(prp => excludes.Any(exc => string.Equals(exc, prp.Key, StringComparison.OrdinalIgnoreCase)))
.Select(prExclude => prExclude.Key)
.ToList()
.ForEach(key => schema.Properties.Remove(key));
}
}
正在启动或 program.cs .Net 6 粉丝。
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info
{
Version = "2.5",
Title = "My Swagger Doc G",
});
c.SchemaFilter<SwaggerExcludeFilter>();
...