Как настроить Swashbuckle для игнорирования свойства на модели

Я использую Swashbuckle для генерации документации Swagger\UI для проекта webapi2. Наши модели используются совместно с некоторыми устаревшими интерфейсами, поэтому есть несколько свойств, которые я хочу игнорировать в моделях. Я не могу использовать атрибут 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.

Ответ 1

Если вам нужно это сделать, но без использования 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>();

Ответ 2

Если вы помечаете поле/свойство как internal protected или private, оно будет автоматически проигнорировано с помощью swashbuckle в документации swagger.

Ответ 3

Решение 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);
            }
        }
    }
}

Ответ 4

Ну, с небольшим ворсом я нашел способ сделать это, используя 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.

Ответ 5

Приведенный ниже код в значительной степени основан на ответе @Richard, но я включил его в качестве нового ответа, поскольку в нем есть три совершенно новых полезных функции, которые я добавил:

  • Работает на .NET Core в последней версии Swashbuckle (v5)
  • Позволяет SwaggerIgnore атрибут SwaggerIgnore к полям, а не только к свойствам
  • Обрабатывает тот факт, что имена свойств и полей могли быть переопределены с JsonProperty атрибута JsonProperty
  • РЕДАКТИРОВАТЬ: теперь корректно обрабатывает camelCasing исходных полей или свойств 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

Основано на ответе Stef Heyenrath.

Атрибут для отметки свойств, исключаемых из документации 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.Keys - это camelCase, а сами свойства - PascalCase. Настроил метод преобразования обоих в нижний регистр и сравнения, чтобы увидеть, что должно быть исключено.

Ответ 7

(На основе ответа мьютекса.)

Я добавил еще одну строку, чтобы не иметь проблем с 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;       
} 

Ответ 8

Вот что я использовал с 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

Для таких людей, как я, которые используют .Net Core и используют встроенное приложение. app.UseSwaggerUi3WithApiExplorer()

Используйте тег [JsonIgnore] используя Newtonsoft.Json;

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

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

Это будет исключено из вашей документации.

Ответ 10

Как добавить свойства в схему в классе SwaggerDocument. Как я могу сделать это, я хочу добавить новую модель "Ошибка": тип: объект Свойства: Код ошибки: Описание ошибки:

Ответ 11

Я использую Nswag вместо Swashbuckle. Кто-нибудь знает, есть ли какое-либо соответствие для интерфейса "ISchemaFilter" в Nswag?

Ответ 12

У меня есть рабочий пример с 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, например

public class MyApiModel
{
    [SwaggerExclude]
    public Guid Token { get; set; }

    public int Id { get; set; }

    public string Name { get; set; }
}