visual studio nswag net how generate c# api swagger subclassing swashbuckle

c# - studio - ¿Cómo incluyo las subclases en la documentación de Swagger API usando Swashbuckle?



swashbuckle swagger (1)

Tengo un proyecto Asp.Net web API 5.2 en c # y genero documentación con Swashbuckle.

Tengo un modelo que contiene herencia, algo así como tener una propiedad de Animal de una clase abstracta de Animal y clases de Perro y Gato que se derivan de ella.

Swashbuckle solo muestra el esquema para la clase Animal, así que traté de jugar con ISchemaFilter (que es lo que sugieren también) pero no pude hacerlo funcionar y tampoco puedo encontrar un ejemplo adecuado.

¿Alguien puede ayudar?


Parece que Swashbuckle no implementa correctamente el polimorfismo y entiendo el punto de vista del autor sobre las subclases como parámetros (si una acción expecta una clase Animal y se comporta de manera diferente si la llamas con un objeto de perro o un objeto cat, entonces deberías tener 2 acciones diferentes ...) pero como tipos de devolución, creo que es correcto devolver Animal y los objetos podrían ser de tipo Dog o Cat.

Entonces, para describir mi API y producir un esquema JSON adecuado en línea con las guías correctas (tenga en cuenta la forma en que describo el disciminador, si tiene su propio discriminador puede necesitar cambiar esa parte en particular), uso filtros de documentos y esquemas de la siguiente manera:

SwaggerDocsConfig configuration; ..... configuration.DocumentFilter<PolymorphismDocumentFilter<YourBaseClass>>(); configuration.SchemaFilter<PolymorphismSchemaFilter<YourBaseClass>>(); ..... public class PolymorphismSchemaFilter<T> : ISchemaFilter { private readonly Lazy<HashSet<Type>> derivedTypes = new Lazy<HashSet<Type>>(Init); private static HashSet<Type> Init() { var abstractType = typeof(T); var dTypes = abstractType.Assembly .GetTypes() .Where(x => abstractType != x && abstractType.IsAssignableFrom(x)); var result = new HashSet<Type>(); foreach (var item in dTypes) result.Add(item); return result; } public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type) { if (!derivedTypes.Value.Contains(type)) return; var clonedSchema = new Schema { properties = schema.properties, type = schema.type, required = schema.required }; //schemaRegistry.Definitions[typeof(T).Name]; does not work correctly in SwashBuckle var parentSchema = new Schema { @ref = "#/definitions/" + typeof(T).Name }; schema.allOf = new List<Schema> { parentSchema, clonedSchema }; //reset properties for they are included in allOf, should be null but code does not handle it schema.properties = new Dictionary<string, Schema>(); } } public class PolymorphismDocumentFilter<T> : IDocumentFilter { public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, System.Web.Http.Description.IApiExplorer apiExplorer) { RegisterSubClasses(schemaRegistry, typeof(T)); } private static void RegisterSubClasses(SchemaRegistry schemaRegistry, Type abstractType) { const string discriminatorName = "discriminator"; var parentSchema = schemaRegistry.Definitions[SchemaIdProvider.GetSchemaId(abstractType)]; //set up a discriminator property (it must be required) parentSchema.discriminator = discriminatorName; parentSchema.required = new List<string> { discriminatorName }; if (!parentSchema.properties.ContainsKey(discriminatorName)) parentSchema.properties.Add(discriminatorName, new Schema { type = "string" }); //register all subclasses var derivedTypes = abstractType.Assembly .GetTypes() .Where(x => abstractType != x && abstractType.IsAssignableFrom(x)); foreach (var item in derivedTypes) schemaRegistry.GetOrRegister(item); } }

Lo que el código anterior implementa se especifica aquí , en la sección "Modelos con soporte de polimorfismo. Básicamente produce algo como lo siguiente:

{ "definitions": { "Pet": { "type": "object", "discriminator": "petType", "properties": { "name": { "type": "string" }, "petType": { "type": "string" } }, "required": [ "name", "petType" ] }, "Cat": { "description": "A representation of a cat", "allOf": [ { "$ref": "#/definitions/Pet" }, { "type": "object", "properties": { "huntingSkill": { "type": "string", "description": "The measured skill for hunting", "default": "lazy", "enum": [ "clueless", "lazy", "adventurous", "aggressive" ] } }, "required": [ "huntingSkill" ] } ] }, "Dog": { "description": "A representation of a dog", "allOf": [ { "$ref": "#/definitions/Pet" }, { "type": "object", "properties": { "packSize": { "type": "integer", "format": "int32", "description": "the size of the pack the dog is from", "default": 0, "minimum": 0 } }, "required": [ "packSize" ] } ] } } }