How to configure Swashbuckle to ignore property on model

93,144

Solution 1

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

Solution 2

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.

Solution 3

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

Solution 4

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

Solution 5

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);
            }
        }
    }
}
Share:
93,144
mutex
Author by

mutex

.NET developer

Updated on February 04, 2022

Comments

  • mutex
    mutex about 2 years

    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.

  • infl3x
    infl3x over 6 years
    This is the nicest solution IMO
  • Stef Heyenrath
    Stef Heyenrath about 6 years
    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?
  • mattruma
    mattruma about 6 years
    This doesn't seem to work, but I am using AspNetCore 2, wonder if that makes a difference?
  • Boudewijn van Veen
    Boudewijn van Veen about 6 years
    Swashbuckle.AspNetCore.SwaggerGen.ISchemaFilter does not have a type parameter. How to solve it there?
  • adnan kamili
    adnan kamili almost 6 years
    This would prevent the property from getting populated from the request body json
  • ksigmund
    ksigmund almost 6 years
    This didn't work for me because my schema is Pascal casing, but the context appears to be using camel case.
  • Chris Peterson
    Chris Peterson over 5 years
    I posted an edit that makes it work on the latest dotnetcore.
  • Attila Bicskó
    Attila Bicskó over 5 years
    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));
  • MikeBeaton
    MikeBeaton about 5 years
    @Richard This is an extremely useful answer. I have posted an updated version of it below 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
    MikeBeaton about 5 years
    Have updated below 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
    MikeBeaton about 5 years
    @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
    MikeBeaton about 5 years
    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
    MikeBeaton about 5 years
    I've done a version here 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.
  • Silvair L. Soares
    Silvair L. Soares almost 5 years
    I'm using Nswag instead of Swashbuckle. Would anyone know if there is any match for the "ISchemaFilter" interface in Nswag?
  • oli_taz
    oli_taz almost 5 years
    Does this still allow the ignored property to be serialized and deserialized though as OP asked for?
  • Martea
    Martea over 4 years
    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, gist.github.com/martea/7f5210222076cedc371988ee1d123c11
  • Shankar
    Shankar about 4 years
    i'm using .net core 3.1, and [JsonIgnore] from System.Text.Json.Serialization works, but from Newtonsoft.Json doesn't!
  • Gayan
    Gayan about 4 years
    @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?
  • jjxtra
    jjxtra about 4 years
    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.
  • Vedran Mandić
    Vedran Mandić about 4 years
    schemaFilterContext.SystemType does not exist on lib v5.3.3
  • oflahero
    oflahero almost 4 years
    "schemaFilterContext.SystemType does not exist on lib v5.3.3" - use schemaFilterContext.Type instead.
  • tkit
    tkit over 3 years
    For anyone trying this with Newtonsoft, you might need to install the Swashbuckle.AspNetCore.Newtonsoft nuget.
  • tkit
    tkit over 3 years
    For anyone trying this with Newtonsoft, you might need to install the Swashbuckle.AspNetCore.Newtonsoft nuget.
  • Steve Pick
    Steve Pick about 3 years
    I avoided the property naming issues by having the constructor of my SchemaFilter take an instance of Swashbuckle.AspNetCore.SwaggerGen.ISerializerDataContractRes‌​olver, 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.
  • Steef
    Steef over 2 years
    This is working quit nice for primary keys where you want to hide them when creating items, but only list them when retrieving.
  • jjxtra
    jjxtra over 2 years
    Not found even after installing the nuget... .NET 6