How to configure Swashbuckle to ignore property on model

后端 未结 15 1710
旧巷少年郎
旧巷少年郎 2020-12-02 15:10

I\'m using Swashbuckle to generate swagger documentation\\UI for a webapi2 project. Our models are shared with some legacy interfaces so there are a couple of properties I

相关标签:
15条回答
  • 2020-12-02 15:55

    Based on Stef Heyenrath's answer.

    Attribute to mark properties to exclude from the Swagger documentation.

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

    The filter to exclude the properties from the Swagger documentation.

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

    The schema.Properties.Keys are camelCase, while the properties themselves are PascalCase. Tweaked the method to convert both to lower case and compare to see what should be excluded.

    0 讨论(0)
  • 2020-12-02 15:57

    The code below is very much based on @Richard's answer, but I am including it as a new answer because it has three completely new, useful features which I have added:

    • Runs on .NET Core on the latest version of Swashbuckle (v5)
    • Allows the SwaggerIgnore attribute to be applied to fields not just to properties
    • Handles the fact that property and field names may have been overridden using the JsonProperty attribute
    • EDIT: Now correctly handles camelCasing of originally TitleCased fields or properties (prompted by @mattruma's answer)

    So the revised code is:

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

    and in Startup.cs:

    services.AddSwaggerGen(c =>
    {
        ...
        c.SchemaFilter<SwaggerIgnoreFilter>();
        ...
    });
    
    0 讨论(0)
  • 2020-12-02 16:03

    I get inspired by the blog of Ignoring properties from controller action model in Swagger using JsonIgnore.

    I'm using .net core 2.1 and Swashbuckle.AspNetCore 5.3.1. The code below solved the problem.

    Add a new filter

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

    Use the Filter in Startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
    
    ......
    
     services.AddSwaggerGen(options =>
                    {
                        options.SwaggerDoc("v1", new OpenApiInfo { Title = "CustomApi", Version = "v1" });
                        options.OperationFilter<SwaggerJsonIgnoreFilter>();
                    });
    
    ......
    
    }
    
    
    0 讨论(0)
  • 2020-12-02 16:05

    I have here a working example with DotNetCore 3 and Swashbuckle 5. It took me a few hours to get it in place so I thought to come back to this thread which helped me but didn't solve my issue.

    Create a dummy custom attribute:

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

    Create a SchemaFilter which will be used by swagger to generate the API Model Schema

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

    Then, inside the Startup.cs file add this to the swagger configuration

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

    You can now use the custom attribute on a property that you want to exclude from the API Mode Shema like this

    public class MyApiModel
    {
        [SwaggerExclude]
        public Guid Token { get; set; }
    
        public int Id { get; set; }
    
        public string Name { get; set; }
    }
    
    0 讨论(0)
  • 2020-12-02 16:06

    Referring to https://stackoverflow.com/a/58193046/11748401 answer, for creating a filter you can simply use the following code:

    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);
                    }
                }
            }
        }
    
    }
    
    0 讨论(0)
  • 2020-12-02 16:11

    The AspNetCore solution looks like:

    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);
                }
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题