95

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 want to ignore on the models. I can't use JsonIgnore attribute because the legacy interfaces also need to serialize to JSON so I don't want to ignore the properties globally, just in the Swashbuckle configuration.

I found a method of doing this documented here:

https://github.com/domaindrivendev/Swashbuckle/issues/73

But this appears to be out of date with the current Swashbuckle release.

The method recommended for the old version of Swashbuckle is using an IModelFilter implementation as follows:

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

But I'm unsure how to configure Swashbuckle to use the IModelFilter in the current version? I'm using Swashbuckle 5.5.3.

ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
mutex
  • 7,536
  • 8
  • 45
  • 66
  • you can actually use JsonIgnore propety which will not show up the property in the swagger – Silly John Dec 07 '16 at 15:22
  • 1
    As mentioned in the question I don't want to use JsonIgnore as I have legacy code that also needs to use the models, and if I apply JsonIgnore that will affect swagger and the legacy code... – mutex Dec 07 '16 at 20:54

21 Answers21

79

If you need to do this but without using JsonIgnore (maybe you still need to serialize/deserialize the property) then just create a custom attribute.

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

Then a schema filter similar to 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
}

Don't forget to register the filter

c.SchemaFilter<SwaggerExcludeFilter>();
kmcnamee
  • 5,097
  • 2
  • 25
  • 36
Richard
  • 1,602
  • 1
  • 15
  • 16
  • 4
    It seems this does only work for output models ? When I apply this code on an input model (used by GET), that model is not found? – Stef Heyenrath Mar 04 '18 at 08:38
  • 2
    Swashbuckle.AspNetCore.SwaggerGen.ISchemaFilter does not have a type parameter. How to solve it there? – Boudewijn van Veen Apr 25 '18 at 14:17
  • I posted an edit that makes it work on the latest dotnetcore. – Chris Peterson Sep 07 '18 at 20:04
  • 5
    I've ran into an issue using this solution with case sensitivity. My property names in my POCOs were in PascalCase while the serialized object's name was in camelCase, so instead of ContainsKey, may be a good idea to check for var foundKey = schema.properties.Keys.FirstOrDefault(x => string.Equals(x, excludedProperty.Name, StringComparison.CurrentCultureIgnoreCase)); – Attila Bicskó Sep 26 '18 at 11:21
  • 1
    @Richard This is an extremely useful answer. I have posted an updated version of it [below](https://stackoverflow.com/a/54480742/795690) which: works on the latest (v5) version of Swashbuckle; can be applied to fields as well as properties; respects the possible renaming of data members by the `JsonProperty` attribute. Thank you! – MikeBeaton Feb 01 '19 at 13:43
  • Thanks for the guideline, had a issue with obsolete attribute not working, did get a working solution with branding up properties and methods with depricated thanks to you, https://gist.github.com/martea/7f5210222076cedc371988ee1d123c11 – Martea Nov 22 '19 at 13:27
  • 2
    @Richard i tried this solution on asp.net core 3.1 it seems custom attribute, not picking `ar excludedProperties = context.Type.GetProperties() .Where(t => t.GetCustomAttribute(typeof(SwaggerExcludeAttribute), true) != null);` line always empty, any thought? – Gayan Mar 24 '20 at 16:35
  • Doesn't work for me with SubClass, polymorphism and JsonIgnore attribute on override field of the subclass, any ideas for .NET 6 ? – NilkOne Nov 16 '22 at 15:31
67

Solution for .NET Core 3.1 and .NET Standard 2.1:

Use JsonIgnore from System.Text.Json.Serialization namespace.

( JsonIgnore from Newtonsoft.Json will NOT work )

public class Test
{
    [System.Text.Json.Serialization.JsonIgnore]
    public int HiddenProperty { get; set; }
    public int VisibleProperty { get; set; }
}
VeganHunter
  • 5,584
  • 2
  • 26
  • 26
  • 10
    For anyone trying this with Newtonsoft, you might need to install the `Swashbuckle.AspNetCore.Newtonsoft` nuget. – tkit Aug 03 '20 at 18:29
  • Not found even after installing the nuget... .NET 6 – jjxtra Dec 29 '21 at 21:19
  • Wow!, that's the 100% correct answer. I was trying to figure out this since last 2 hours. – Waqas Idrees Nov 14 '22 at 23:30
  • Doesn't work for me with SubClass, polymorphism and JsonIgnore attribute on override field of the subclass, any ideas for .NET 6 ? – NilkOne Nov 16 '22 at 15:31
  • I'm on .NET 7 and this simply does nothing. Yes I triple checked that I didn't have the Newtonsoft `using`. Making the field `internal` was the way to go. – asontu Dec 06 '22 at 08:46
58

If you mark field/property as internal or protected or private, it will be ignored automatically by swashbuckle in swagger documentation.

Update: Obviously, those properties/fields won't be populated in request/response.

Jay Shah
  • 3,553
  • 1
  • 27
  • 26
  • 2
    This is the nicest solution IMO – infl3x Oct 04 '17 at 13:27
  • 25
    This would prevent the property from getting populated from the request body json – adnan kamili May 06 '18 at 13:53
  • 3
    That is true, however this works great for internal state stuff or other properties that might not be needed in the original request. Not saying this is a perfect architecture, but it's an option. – jjxtra Apr 14 '20 at 18:29
37

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

and in Startup.cs:

services.AddSwaggerGen(c =>
{
    ...
    c.SchemaFilter<SwaggerIgnoreFilter>();
    ...
});
mutex
  • 7,536
  • 8
  • 45
  • 66
MikeBeaton
  • 3,314
  • 4
  • 36
  • 45
  • 1
    @mattruma was right about camel casing. I've extracted the internal method used by Swashbuckle and used that. I'm not sure how to read the current settings of Swashbuckle in the context of this filter, as I think the camel casing can be switched on or off somewhere. – MikeBeaton Feb 01 '19 at 16:32
  • As per several other answers above, I think the difference in required classes for this version vs. @Richard's version is to do with .NET Core vs. Framework, not Swagger v5 vs. v4. If someone needed to, it would be relatively easy to convert the other features of this version back to the .NET Framework classes. – MikeBeaton Feb 01 '19 at 16:35
  • 1
    I'm using Nswag instead of Swashbuckle. Would anyone know if there is any match for the "ISchemaFilter" interface in Nswag? – Silvair L. Soares Jul 03 '19 at 16:41
  • 6
    schemaFilterContext.SystemType does not exist on lib v5.3.3 – Vedran Mandić Apr 21 '20 at 11:23
  • 2
    "schemaFilterContext.SystemType does not exist on lib v5.3.3" - use schemaFilterContext.Type instead. – oflahero Jul 20 '20 at 16:12
  • Doesn't work for me with SubClass, polymorphism and JsonIgnore attribute on override field of the subclass, any ideas for .NET 6 ? – NilkOne Nov 16 '22 at 15:30
16

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);
            }
        }
    }
}
Stef Heyenrath
  • 9,335
  • 12
  • 66
  • 121
  • 2
    This doesn't seem to work, but I am using AspNetCore 2, wonder if that makes a difference? – mattruma Apr 17 '18 at 14:05
  • 3
    This didn't work for me because my schema is Pascal casing, but the context appears to be using camel case. – ksigmund May 07 '18 at 19:13
  • Have updated [below](https://stackoverflow.com/a/54480742/795690) to work with latest (v5) version of Swashbuckle, also to deal with fields, also to deal with field/property renames using the `JsonProperty` attribute. – MikeBeaton Feb 01 '19 at 16:15
13

For people like me who are using .Net Core and are using the build in app.UseSwaggerUi3WithApiExplorer()

Use [JsonIgnore] tag using Newtonsoft.Json;

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

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

It will be excluded from your documentation.

Akhila
  • 3,235
  • 1
  • 14
  • 30
Jorben Saaltink
  • 131
  • 1
  • 2
  • 1
    Does this still allow the ignored property to be serialized and deserialized though as OP asked for? – oli_taz Jul 10 '19 at 15:35
  • 2
    i'm using .net core 3.1, and [JsonIgnore] from System.Text.Json.Serialization works, but from Newtonsoft.Json doesn't! – Shankar Feb 08 '20 at 00:35
  • 3
    For anyone trying this with Newtonsoft, you might need to install the `Swashbuckle.AspNetCore.Newtonsoft` nuget. – tkit Aug 03 '20 at 18:28
12

Well, with a bit of poking I found a way to do this using 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);
    }
}

then when calling httpConfiguration.EnableSwagger I set the SwaggerDocsConfig to use this SchemaFilter as follows:

c.SchemaFilter<ApplyCustomSchemaFilters>();

Hope this helps someone. I'd still be curious on whether it's possible to use the IModelFilter somehow though.

mutex
  • 7,536
  • 8
  • 45
  • 66
10

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

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.

mattruma
  • 16,589
  • 32
  • 107
  • 171
  • 1
    I've done a version [here](https://stackoverflow.com/a/54480742/795690) which takes on board your good point about camel casing (thank you!), but does it using the `ToCamelCase` method copied from Swashbuckle, and also supports excluding fields as well as properties, and also the possibility of property renaming using `JsonProperty`. – MikeBeaton Feb 01 '19 at 16:49
  • 2
    I avoided the property naming issues by having the constructor of my SchemaFilter take an instance of `Swashbuckle.AspNetCore.SwaggerGen.ISerializerDataContractResolver`, store it as a member variable, and then use that to lookup the type's serialized property names by correlating on MemberInfos. This way, it doesn't matter what serializer you use or whether your members are renamed. – Steve Pick Mar 31 '21 at 17:06
8

You can use the Swashbuckle.AspNetCore.Annotations package, it allows you to mark that some properties are only displayed in the input parameters, and some are only displayed in the output.

for example, if you want to hide the AlertId in the input parameter of the post, you just need to do this by the [SwaggerSchema]:

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

See more about it in the Documentation

Hanabi
  • 577
  • 4
  • 9
  • This is working quit nice for primary keys where you want to hide them when creating items, but only list them when retrieving. – Steef Sep 22 '21 at 12:12
7

Swashbuckle now has support for 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();`
4

Here is what I used with 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);
    }
}
johng
  • 171
  • 9
4

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

}
Sunny12
  • 303
  • 3
  • 11
4

This is an older question, but an low-effort, intermediate solution has since become available in Swashbuckle.

Hiding legacy properties from documentation doesn't do much to discourage usage of these properties - it just delays discovery. After all, they're still part of the model. In fact, leaving them undocumented means consumers have no way of knowing they shouldn't use them!

Rather than have them go undocumented, you should simply consider marking them [Obsolete].

Swashbuckle will then mark them as deprecated in the swagger.json. In the UI, this will hide them in the Example Value sections, and in the Schema sections, they will show as grayed out with strikethrough on the names.

If you still want them to be completely hidden from the documentation, you can then set in SwaggerGeneratorOptions.IgnoreObsoleteProperties = true.

This was not a possible solution at the time this question was originally asked. The deprecated flag is a feature of OpenAPI v3, which was not released until 2017.

friggle
  • 3,362
  • 3
  • 35
  • 47
3

(Based on mutex's answer.)

I added another line to not have problems with 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);        
}

If you want to delete all schemas

public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type)
{
  schema.properties = null;       
} 
Nathan Tuggy
  • 2,237
  • 27
  • 30
  • 38
3

In my case I wanted to keep my Application Layer DTOs clean (without any annotation like JsonIngore) but still being able to use them in my Controllers Web APIs.

So, in my Application Layer I have a DTO like this:

public class CreateItemCommand {
     public Guid ContainerId { get; set; }
     public string Name { get; set; }
}

And my API design for creating an item is something like: POST /containers/{containerId}/items

As the ContainerId is coming from the api route, I don't want the asp.net core trying to bind it into the command DTO and I don't want swashbuckle listing it neither.

So my solution is to inherit the original DTO in the API layer like this:

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));
  • The useCase.Create from the ApplicationLayer expects the base class CreateItemCommand.
  • .Apply is just a very simple extension method that i've made to easily set the routing parameter value into the correspondent dto property.
2

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

......

}

Ciarán Bruen
  • 5,221
  • 13
  • 59
  • 69
Kyle
  • 21
  • 3
2

Very userful solution form @Jay Shah, but if you using N'Tier architecture you can not reach protected or private DAL data from BL. to solve this, you can make this prop's acces modifier as "protected internal"

public class Test
{
    
    protected internal int HiddenProperty { get; set; }
    
}

with this you can access aforementioned data from BL but not PL. or API layer.

Hgrbz
  • 185
  • 3
  • 12
1

I needed more control to remove properties which were declared elsewhere and couldn't easly use a removal attribute.

The filter created removed all items which it came accross from my excludes list:

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

In startup or program.cs for you .Net 6 fans.

services.AddSwaggerGen(c =>
                {
                    c.SwaggerDoc("v1", new Info
                    {
                        Version = "2.5",
                        Title = "My Swagger Doc G",
                    });

                    c.SchemaFilter<SwaggerExcludeFilter>();     
                    ...
       
ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122
1

I'm using dotnet core 3.1 and Swashbuckle 6.3.1, here is updated version with the similar logic for using ISchemaFilter to filter properties marked with customed attribute SwaggerExcludeAttribute

public class SwaggerExcludeFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        var type = context.Type;
        if (!schema.Properties.Any() || type == null)
        {
            return;
        }

        var excludedPropertyNames = type
                .GetProperties()
                .Where(
                    t => t.GetCustomAttribute<SwaggerExcludeAttribute>() != null
                ).Select(d => d.Name).ToList();

        if (!excludedPropertyNames.Any())
        {
            return;
        }

        var excludedSchemaPropertyKey = schema.Properties
               .Where(
                    ap => excludedPropertyNames.Any(
                        pn => pn.ToLower() == ap.Key
                    )
                ).Select(ap => ap.Key);

        foreach (var propertyToExclude in excludedSchemaPropertyKey)
        {
            schema.Properties.Remove(propertyToExclude);
        }
    }
}
Ravikumar B
  • 779
  • 1
  • 14
  • 25
0

Attribute to enable annotation of properties.

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

Filter to exclude all properties annotated with attribute.

public class SwaggerExcludeFilter : ISchemaFilter
{
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        if (schema.Properties is null)
        {
            return;
        }

        foreach (var property in context.Type.GetProperties().Where(p => p.GetCustomAttribute<SwaggerExcludeAttribute>() is {}))
        {
            var remove = schema.Properties.Keys.SingleOrDefault(p => p == property.Name);

            if (remove is {})
            {
                _ = schema.Properties.Remove(remove);
            }
        }
    }
}

Filter registration in Swagger generation service.

_ = services.AddSwaggerGen(options => options.SchemaFilter<SwaggerExcludeFilter>());

Annotation on properties that should be excluded.

public class Response
{
    public string Message { get; set; }

    [SwaggerExclude]
    public string? StackTrace { get; set; }
}