2015-12-21 429 views
6

我在C#中Asp.Net的Web API 5.2項目,並生成文檔與Swashbuckle。如何在使用Swashbuckle的Swagger API文檔中包含子類?

我有一個包含繼承像從動物抽象類,狗和貓類,從中獲得具有動物屬性模型。

Swashbuckle只顯示Animal類的模式,所以我嘗試使用ISchemaFilter(也是他們的建議),但我無法使其工作,也找不到合適的示例。

任何人都可以幫忙嗎?

+0

任何運氣搞清楚了這出? – Craig

+0

還沒有,但我將不得不再次關注它。請讓我知道,如果你發現任何東西 –

回答

13

看來Swashbuckle沒有正確實現多態性,我理解作者關於子類作爲參數的觀點(如果一個動作需要一個Animal類並且行爲不同,如果你用一個狗對象或貓對象調用它,那麼你應該有2個不同的動作..)但作爲返回類型,我相信返回Animal是正確的,並且對象可以是Dog或Cat類型。

因此,爲了描述我的API並根據正確的指導方針產生一個合適的JSON模式(請注意我描述disciminator的方式,如果您有自己的鑑別器,您可能需要更改該部分),我使用文檔和模式濾波器如下:

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

什麼以前的代碼實現指定here,在節段「模式與多態支持它基本上會產生類似以下內容:

{ 
    "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'必須是你自己的類?我想通了,你可以通過添加一個'使用Swashbuckle.Swagger',然後改變該行的代碼爲'無功parentSchema = schemaRegistry.Definitions [abstractType.FriendlyId]使用揚鞭的默認約定;' – wags1999

+0

是的,這是我的課。我需要它,因爲我們也有schemaId委託:configuration.SchemaId(SchemaIdProvider.GetSchemaId); –

+2

@PaoloVigori:我用的是上Swashbuckle.AspNetCore的'PolymorphismDocumentFilter'被稱爲和鑑別設置代碼,而不是在產生招搖定義。 「allOf」條目在那裏。有任何想法嗎? – Tseng

相關問題