2015-12-21 67 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

相关问题