web-dev-qa-db-fra.com

Comment configurer Swashbuckle pour ignorer la propriété sur le modèle

J'utilise Swashbuckle pour générer la documentation\UI de swagger pour un projet webapi2. Nos modèles étant partagés avec certaines interfaces héritées, il y a quelques propriétés que je veux ignorer sur les modèles. Je ne peux pas utiliser l'attribut JsonIgnore car les interfaces héritées doivent également être sérialisées au format JSON. Par conséquent, je ne souhaite pas ignorer les propriétés globalement, uniquement dans la configuration Swashbuckle.

J'ai trouvé une méthode de faire ceci documentée ici:

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

Mais cela semble être obsolète avec la version actuelle de Swashbuckle. 

La méthode recommandée pour l'ancienne version de Swashbuckle utilise une implémentation IModelFilter comme suit:

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

Mais je ne sais pas comment configurer Swashbuckle pour utiliser le filtre IModelFilter dans la version actuelle? J'utilise Swashbuckle 5.5.3. 

18
mutex

Si vous devez le faire mais sans utiliser JsonIgnore (vous devez peut-être quand même sérialiser/désérialiser la propriété), créez simplement un attribut personnalisé.

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

Ensuite, un filtre de schéma semblable à 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
}

N'oubliez pas d'enregistrer le filtre

c.SchemaFilter<SwaggerExcludeFilter>();
19
Richard

Si vous marquez un champ/une propriété comme internal ou protected ou private, il sera automatiquement ignoré par swashbuckle dans la documentation swagger.

13
Jay Shah

Eh bien, en cherchant un peu, j'ai trouvé un moyen de faire cela en utilisant 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);
    }
}

puis, lors de l'appel de httpConfiguration.EnableSwagger, j'ai défini la SwaggerDocsConfig pour utiliser ce SchemaFilter comme suit:

c.SchemaFilter<ApplyCustomSchemaFilters>();

J'espère que ça aide quelqu'un. Je serais toujours curieux de savoir s'il est possible d'utiliser IModelFilter d'une manière ou d'une autre.

8
mutex

La solution AspNetCore se présente comme suit:

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);
            }
        }
    }
}
6
Stef Heyenrath

Le code ci-dessous est très basé sur la réponse de @ Richard, mais je l'inclue en tant que nouvelle réponse car il comporte trois nouvelles fonctionnalités utiles que j'ai ajoutées:

  • Fonctionne sur .NET Core sur la dernière version de Swashbuckle (v5)
  • Permet à l'attribut SwaggerIgnore d'être appliqué aux champs et pas seulement aux propriétés
  • Traite le fait que les noms de propriété et de champ peuvent avoir été remplacés à l'aide de l'attribut JsonProperty
  • EDIT: gère maintenant correctement la mise en cache des champs ou des propriétés d'origine TitleCased (à l'invite de la réponse de @ mattruma)

Le code révisé est donc:

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

et en Startup.cs:

services.AddSwaggerGen(c =>
{
    ...
    c.SchemaFilter<SwaggerIgnoreFilter>();
    ...
});
4
Mike Beaton

Voici ce que j'ai utilisé avec 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);
    }
}
3
johng

( Basé sur la réponse de mutex .)

J'ai ajouté une autre ligne pour ne pas avoir de problèmes avec 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);        
}

Si vous voulez supprimer tous les schémas

public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type)
{
  schema.properties = null;       
} 

Pour les personnes comme moi qui utilisent .Net Core et utilisent le build in app.UseSwaggerUi3WithApiExplorer()

Utilisez la balise [JsonIgnore] en utilisant Newtonsoft.Json ;

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

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

Il sera exclu de votre documentation.

2
Jorben Saaltink

Basé sur la réponse de Stef Heyenrath.

Attribut pour marquer les propriétés à exclure de la documentation Swagger.

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

Filtre permettant d’exclure les propriétés de la documentation 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);
            }
        }
    }
}

Le schema.Properties.Keys est camelCase, tandis que les propriétés elles-mêmes sont PascalCase. Tweaked la méthode pour convertir les deux en minuscules et comparer pour voir ce qui devrait être exclu.

0
mattruma