2015-12-21 8 views
6

Ich habe ein Asp.Net Web API 5.2 Projekt in C# und erzeuge Dokumentation mit Swashbuckle.Wie schließe ich Unterklassen in die Swagger-API-Dokumentation mit Swashbuckle ein?

Ich habe Modell, das Vererbung so etwas wie eine Animal-Eigenschaft aus einem Animal abstrakten Klasse und Dog und Cat-Klassen, die daraus abgeleitet enthalten.

Swashbuckle zeigt nur das Schema für die Animal-Klasse, also habe ich versucht, mit ISchemaFilter zu spielen (das, was sie auch vorschlagen), aber ich konnte es nicht funktionieren lassen und auch kein richtiges Beispiel finden.

Jeder kann helfen?

+0

Glück gehabt diese Bezifferung aus? – Craig

+0

Noch nicht, aber ich werde mich bald wieder darum kümmern müssen. Bitte lassen Sie mich wissen, wenn Sie etwas finden –

Antwort

13

Es scheint, dass Swashbuckle Polymorphismus nicht korrekt implementiert und ich die Sicht des Autors über Unterklassen als Parameter verstehe (wenn eine Aktion eine Animal-Klasse erwartet und sich anders verhält, wenn Sie sie mit einem Hunde- oder Katzenobjekt aufrufen , dann sollten Sie 2 verschiedene Aktionen haben ..) aber als Rückgabetypen glaube ich, dass es korrekt ist, Tier zurückzugeben, und die Objekte könnten Hunde- oder Katzenarten sein.

Um meine API zu beschreiben und ein korrektes JSON-Schema in Übereinstimmung mit den korrekten Richtlinien zu erzeugen (beachten Sie, wie ich den Disciminator beschreibe, wenn Sie einen eigenen Diskriminator haben, müssen Sie diesen Teil möglicherweise ändern) Dokument und Schema Filter wie folgt:.

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

Was der vorherige Code implementiert wird here angegeben, im Abschnitt „Modellen mit Polymorphie-Support Es produziert im Grunde so etwas wie die folgenden:

{ 
    "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" 
      ] 
     } 
     ] 
    } 
    } 
} 
+2

'SchemaIdProvider' muss Ihre eigene Klasse sein? Ich habe herausgefunden, dass Sie die Standardkonvention von Swagger verwenden können, indem Sie ein 'Using Swashbuckle.Swagger' hinzufügen und dann diese Zeile in' var ändern parentSchema = schemaRegistry.Definitions [abstractType.FriendlyId]; ' – wags1999

+0

Ja, das ist meine Klasse. Ich brauche es, weil wir auch einen Delegaten für schemaId haben: configuration.SchemaId (SchemaIdProvider.GetSchemaId); –

+2

@PaoloVigori: Ich habe das auf Swashbuckle.AspNetCore verwendet, der 'PolymorphismDocumentFilter' wird aufgerufen und der Diskriminator wird im Code gesetzt, aber nicht in der erzeugten Swagger-Definition. 'allOf' Einträge sind da. Irgendwelche Ideen? – Tseng

Verwandte Themen