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

时间:2016-12-06 22:00:37

标签: 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>());

但我不确定如何配置Swashbuckle以在当前版本中使用IModelFilter?我使用的是Swashbuckle 5.5.3。

17 个答案:

答案 0 :(得分:26)

如果你需要这样做但不使用JsonIgnore(可能你仍然需要序列化/反序列化属性),那么只需创建一个自定义属性。

[AttributeUsage(AttributeTargets.Property)]
public class SwaggerExcludeAttribute : Attribute
{
}

然后是类似于Johng's

的架构过滤器
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>();

答案 1 :(得分:17)

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

使用JsonIgnore命名空间中的System.Text.Json.Serialization

JsonIgnore中的Newtonsoft.Json无效

public class Test
{
    [System.Text.Json.Serialization.JsonIgnore]
    public int HiddenProperty { get; set; }
    public int VisibleProperty { get; set; }
}

答案 2 :(得分:15)

如果您将字段/属性标记为internalprotectedprivate,swagbuckle会在swagger文档中自动将其忽略。

答案 3 :(得分:8)

嗯,有点戳,我找到了一种方法来使用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感到好奇。

答案 4 :(得分:7)

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);
            }
        }
    }
}

答案 5 :(得分:7)

下面的代码很大程度上基于@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
                            .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);
        }
    }
}

Startup.cs中的

services.AddSwaggerGen(c =>
{
    ...
    c.SchemaFilter<SwaggerIgnoreFilter>();
    ...
});

答案 6 :(得分:5)

我在这里有一个使用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文件中,将此文件添加到招摇配置中

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; }
}

答案 7 :(得分:4)

请参考https://stackoverflow.com/a/58193046/11748401答案,以创建过滤器,您只需使用以下代码即可:

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);
                }
            }
        }
    }

}

答案 8 :(得分:3)

以下是我与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);
    }
}

答案 9 :(得分:3)

这是一个较旧的问题,但此后在 Swashbuckle 中提供了一种省力的中间解决方案。

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

与其将它们隐藏起来,不如考虑将它们标记为 [Obsolete]

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

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

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

答案 10 :(得分:3)

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

中的版本的用户

通过 Newtonsoft.Json ;

使用[JsonIgnore]标签
public class Project
{
    [Required]
    public string ProjectName { get; set; }

    [JsonIgnore]
    public string SomeValueYouWantToIgnore { get; set; }
}

它将从您的文档中排除。

答案 11 :(得分:2)

Based on mutex's answer。)

我添加了另一行,以便NullReferenceException没有问题。

public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type)
{
  var excludeProperties = new[] { "myProp1", "myProp2, myProp3"};

   foreach (var prop in excludeProperties)
     if(schema.properties != null) // This line
       if (schema.properties.ContainsKey(prop))
        schema.properties.Remove(prop);        
}

如果要删除所有架构

public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type)
{
  schema.properties = null;       
} 

答案 12 :(得分:2)

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();`

答案 13 :(得分:2)

Based on Stef Heyenrath's answer.

用于标记要从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.KeyscamelCase,而属性本身是PascalCase。调整了将该方法转换为小写字母并进行比较以查看应排除的内容的方法。

答案 14 :(得分:1)

我受到Ignoring properties from controller action model in Swagger using JsonIgnore博客的启发。

我正在使用.net core 2.1Swashbuckle.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>();
                });

......

}

答案 15 :(得分:0)

就我而言,我想保持我的应用程序层DTO干净(没有像JsonIngore这样的注释),但仍然可以在Controllers Web API中使用它们。

因此,在我的应用程序层中,我有一个这样的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需要基类CreateItemCommand。
  • .Apply只是一种非常简单的扩展方法,我可以轻松地将路由参数值设置为相应的dto属性。

答案 16 :(得分:0)

你可以使用Swashbuckle.AspNetCore.Annotations包,它允许你标记一些属性只显示在输入参数中,有些只显示在输出中。

例如,如果你想隐藏帖子的输入参数中的AlertId,你只需要通过[SwaggerSchema]来做到这一点:

public class Alert
{
    [SwaggerSchema(ReadOnly = true)]
    public string AlertId { get; set; }
    public string Type { get; set; }
}

Documentation

中查看更多信息