ASP.NET Core 2.0 - 动态定义文档模型

时间:2018-01-15 23:04:14

标签: c# json asp.net-web-api swagger swashbuckle

我们有一套REST服务。服务在POST请求中接受json中的模型,并在POST响应中返回json中的模型。但是,这些模型在我们的ASP.NET Core 2.0项目中不是物理编译类型。相反,它们是映射到我们内部类型的映射对象。即提供的json只是我们核心实体顶层的一层,为了将数据暴露给第三方而被削减。

然而,实体需要与Swagger一起记录。 Swashbuckle做得很好。它通过命名空间Microsoft.AspNetCore.Mvc.ApiExplorer实现。我现在正在尝试使用此命名空间为json中提供的实体定义元数据。但是,我没有太多运气。我想定义一个不基于项目中物理类型的类型。我很乐意定义名称和属性等,但我无法完成我所做的任何事情。例如,抽象类ModelMetadata需要ModelMetadataIdentity类型的参数,但此类型在构造函数中不带任何参数,并且所有重要属性都是Get only。因此,例如,我实际上无法在ModelMetadataIdentity上设置Name属性。我猜这是代码中的一个小问题,我甚至可以构建一个ModelMetadataIdentity。我猜这个课程本来是抽象的。

例如,有一个名为ForType的静态方法可以编译,并且不会抛出任何异常,如下所示:

        var customModelMetadataProvider = new CustomModelMetadataProvider(ModelMetadataIdentity.ForType(typeof(TaskInfo)));
        context.ApiDescription.SupportedResponseTypes.Add(new Microsoft.AspNetCore.Mvc.ApiExplorer.ApiResponseType { ModelMetadata = customModelMetadataProvider });

但是,这没有任何作用。在Swagger文档中没有为TaskInfo显示任何文档。但是,更重要的是,这对我来说并不好,因为TaskInfo是预编译类型,我试图定义概念类型,而不是物理类型。

要了解我在说什么,您可以在此处查看示例: https://github.com/Microsoft/aspnet-api-versioning/tree/master/samples/webapi/SwaggerODataWebApiSample。例如,Order和Person被定义为项目中的类型,但我想动态地为这些类型构建元数据。

如何使用Microsoft.AspNetCore.Mvc.ApiExplorer命名空间定义概念(动态)类型?如何强制Swashbuckle识别我使用此命名空间定义的元数据?

PS:我知道有些人会想“你为什么不在代码中编写模型并编译它们?”。好吧,显然可以做到这一点,但这为配置不必要的REST服务增加了额外的一步。从内部实体到外部实体的映射是通过配置完成的 - 而不是代码!配置人员不必编译任何内容来公开这些实体。

1 个答案:

答案 0 :(得分:0)

这可以通过这样的Swashbuckle完成:

public class SwaggerOperationFilter : IOperationFilter
{
    #region Fields
    private const string testpropertyname = "TestProperty";
    private const string TestSchemaRef = "ADef";
    private static Schema TestSchema = new Schema { Required = new List<string> { testpropertyname }, Example = new { TestProperty = "Test" }, Description = "This is a Description", Title = "TestSchema", Properties = new Dictionary<string, Schema>() };
    #endregion

    #region Static Constructor
    static SwaggerOperationFilter()
    {
        TestSchema.Properties.Add(testpropertyname, new Schema { Type = "string" });
    }
    #endregion

    #region Implementation
    public void Apply(Operation operation, OperationFilterContext context)
    {
        if (!context.SchemaRegistry.Definitions.ContainsKey(TestSchemaRef))
        {
            context.SchemaRegistry.Definitions.Add(TestSchemaRef, TestSchema);
        }

        operation.Responses["200"] = new Response
        {
            Description = "This is a Response Description",
            Schema = TestSchema
        };
    }
    #endregion
}