如何配置Swashbuckle忽略模型上的属性

mut*_*tex 32 c# asp.net-web-api swagger swashbuckle

我正在使用Swashbuckle为webapi2项目生成swagger文档\ 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>());
Run Code Online (Sandbox Code Playgroud)

但我不确定如何配置Swashbuckle在当前版本中使用IModelFilter?我正在使用Swashbuckle 5.5.3.

Ric*_*ard 35

如果你需要做到这一点,但没有使用JsonIgnore(也许你还需要序列化/反序列化属性),那么只需要创建一个自定义属性.

[AttributeUsage(AttributeTargets.Property)]
public class SwaggerExcludeAttribute : Attribute
{
}
Run Code Online (Sandbox Code Playgroud)

然后是类似于Johng的模式过滤器

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
}
Run Code Online (Sandbox Code Playgroud)

不要忘记注册过滤器

c.SchemaFilter<SwaggerExcludeFilter>();
Run Code Online (Sandbox Code Playgroud)

  • 使用这种区分大小写的解决方案时,我遇到了一个问题。我的POCO中的属性名称位于PascalCase中,而序列化对象的名称位于camelCase中,因此,代替ContainsKey,检查var foundKey = schema.properties.Keys.FirstOrDefault(x =&gt; string.Equals(x ,excludeProperty.Name,StringComparison.CurrentCultureIgnoreCase)); (3认同)
  • 看来这仅适用于输出模型?当我将此代码应用于输入模型(由GET使用)时,找不到该模型吗? (2认同)
  • Swashbuckle.AspNetCore.SwaggerGen.ISchemaFilter 没有类型参数。那里怎么解决? (2认同)
  • @Richard我在asp.net core 3.1上尝试了这个解决方案,它似乎是自定义属性,而不是选择 `ar exceptedProperties = context.Type.GetProperties() .Where(t =&gt; t.GetCustomAttribute(typeof(SwaggerExcludeAttribute), true) != null );` 行总是空的,有什么想法吗? (2认同)

Veg*_*ter 30

.NET Core 3.1.NET Standard 2.1 的解决方案:

JsonIgnoreSystem.Text.Json.Serialization命名空间使用。

JsonIgnoreNewtonsoft.Json不起作用)

public class Test
{
    [System.Text.Json.Serialization.JsonIgnore]
    public int HiddenProperty { get; set; }
    public int VisibleProperty { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

  • 对于使用 Newtonsoft 尝试此操作的任何人,您可能需要安装 `Swashbuckle.AspNetCore.Newtonsoft` nuget。 (6认同)

Jay*_*hah 19

如果标记字段/属性的internalprotected或者private,它会自动通过swashbuckle招摇文档中被忽略.

  • 这将阻止从请求主体json填充属性 (10认同)
  • IMO这是最好的解决方案 (2认同)
  • 确实如此,但是这对于内部状态内容或原始请求中可能不需要的其他属性非常有用。并不是说这是一个完美的架构,但它是一个选择。 (2认同)

Ste*_*ath 12

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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这对我不起作用,因为我的模式是Pascal大小写,但是上下文似乎使用了驼峰式大小写。 (3认同)
  • 这似乎不起作用,但是我正在使用AspNetCore 2,想知道这是否有所作为吗? (2认同)

mut*_*tex 11

好吧,有点戳,我找到了一种方法来使用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在调用时httpConfiguration.EnableSwagger我将SwaggerDocsConfig如下设置使用此SchemaFilter:

c.SchemaFilter<ApplyCustomSchemaFilters>();
Run Code Online (Sandbox Code Playgroud)

希望这有助于某人.我仍然对是否有可能以某种方式使用IModelFilter感到好奇.


小智 11

对于像我这样使用.Net Core 并使用内置的人app.UseSwaggerUi3WithApiExplorer()

使用Newtonsoft.Json[JsonIgnore]标记;

public class Project
{
    [Required]
    public string ProjectName { get; set; }

    [JsonIgnore]
    public string SomeValueYouWantToIgnore { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

它将从您的文档中排除。

  • 我正在使用 .net core 3.1,并且 System.Text.Json.Serialization 中的 [JsonIgnore] 有效,但 Newtonsoft.Json 中无效! (2认同)
  • 对于使用 Newtonsoft 尝试此操作的任何人,您可能需要安装 `Swashbuckle.AspNetCore.Newtonsoft` nuget。 (2认同)

Han*_*abi 10

您可以使用该Swashbuckle.AspNetCore.Annotations包,它允许您标记某些属性仅显示在输入参数中,某些属性仅显示在输出中。

例如,如果您想隐藏AlertId帖子的输入参数中的 ,则只需通过以下操作即可[SwaggerSchema]

public class Alert
{
    [SwaggerSchema(ReadOnly = true)]
    public string AlertId { get; set; }
    public string Type { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

在文档中查看更多相关信息


Mik*_*ton 9

下面的代码很大程度上基于@Richard的答案,但我将其作为新答案包括在内,因为它具有三个全新的有用功能,我已经添加了它们:

  • 在最新版本的Swashbuckle(v5)上的.NET Core上运行
  • 允许将SwaggerIgnore属性应用于字段,而不仅仅是属性
  • 处理属性和字段名称可能已使用JsonProperty属性覆盖的事实
  • 编辑:现在可以正确处理最初的TitleCased字段或属性的驼色(@mattruma的回答提示)

因此,修改后的代码为:

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class SwaggerIgnoreAttribute : Attribute
{
}
Run Code Online (Sandbox Code Playgroud)
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);
    }
}
Run Code Online (Sandbox Code Playgroud)
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
                            .GetFields(bindingFlags).Cast<MemberInfo>()
                            .Concat(schemaFilterContext.SystemType
                            .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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

并在Startup.cs

services.AddSwaggerGen(c =>
{
    ...
    c.SchemaFilter<SwaggerIgnoreFilter>();
    ...
});
Run Code Online (Sandbox Code Playgroud)

  • lib v5.3.3 上不存在 schemaFilterContext.SystemType (6认同)
  • “lib v5.3.3 上不存在 schemaFilterContext.SystemType” - 请改用 schemaFilterContext.Type。 (2认同)

小智 7

我在这里有一个 DotNetCore 3 和 Swashbuckle 5 的工作示例。我花了几个小时才把它安装到位,所以我想回到这个对我有帮助但没有解决我的问题的线程。

创建一个虚拟的自定义属性:

[AttributeUsage(AttributeTargets.Property)]
public class SwaggerExcludeAttribute : Attribute { }
Run Code Online (Sandbox Code Playgroud)

创建一个 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,在Startup.cs文件中将其添加到 swagger 配置中

services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
    c.SchemaFilter<SwaggerExcludeFilter>();
});
Run Code Online (Sandbox Code Playgroud)

您现在可以在要从 API 模式 Shema 中排除的属性上使用自定义属性,如下所示

public class MyApiModel
{
    [SwaggerExclude]
    public Guid Token { get; set; }

    public int Id { get; set; }

    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)


mat*_*uma 5

基于Stef Heyenrath的回答。

标记要从Swagger文档中排除的属性的属性。

[AttributeUsage(AttributeTargets.Property)]
public class SwaggerExcludeAttribute : Attribute
{
}
Run Code Online (Sandbox Code Playgroud)

从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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

schema.Properties.KeyscamelCase,虽然性质本身PascalCase。调整了将小写转换为小写并进行比较以查看应排除的方法。

  • 我通过让 SchemaFilter 的构造函数采用“Swashbuckle.AspNetCore.SwaggerGen.ISerializerDataContractResolver”的实例,将其存储为成员变量,然后使用它通过关联 MemberInfos 来查找类型的序列化属性名称,从而避免了属性命名问题。这样,您使用什么序列化程序或您的成员是否被重命名都无关紧要。 (2认同)

小智 5

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();`
Run Code Online (Sandbox Code Playgroud)


fri*_*gle 5

这是一个较老的问题,但 Swashbuckle 中已经提供了一种省力的中间解决方案。

从文档中隐藏遗留属性并不能阻止这些属性的使用——它只是延迟了发现。毕竟,它们仍然是模型的一部分。事实上,没有记录就意味着消费者无法知道他们不应该使用它们!

您应该简单地考虑对它们进行标记,而不是让它们没有记录[Obsolete]

然后,Swashbuckle 会在 swagger.json 中将它们标记为已弃用。在 UI 中,这会将它们隐藏在“示例值”部分中,而在“架构”部分中,它们将显示为灰色,并在名称上带有删除线。

如果您仍然希望它们在文档中完全隐藏,则可以在SwaggerGeneratorOptions.IgnoreObsoleteProperties = true.

在最初提出这个问题时,这不是一个可能的解决方案。已弃用标志是 OpenAPI v3 的一项功能,直到 2017 年才发布。