问题
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.
回答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>();
回答2:
If you mark field/property as internal
or protected
or private
, it will be ignored automatically by swashbuckle in swagger documentation.
回答3:
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);
}
}
}
}
回答4:
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.
回答5:
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>();
...
});
回答6:
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.
回答7:
(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;
}
回答8:
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);
}
}
回答9:
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.
回答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; }
}
回答11:
Referring to @Florentin answers, 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);
}
}
}
}
}
来源:https://stackoverflow.com/questions/41005730/how-to-configure-swashbuckle-to-ignore-property-on-model