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

ASP.NET Core 2.0 - Define Model For Documentation Dynamically

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

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

例如,有一个名为 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:我知道有些人会想"Why wouldn't you just write the models in code and compile them?"。好吧,显然这可以完成,但是这增加了一个额外的步骤来配置 REST 服务,这不是必需的。从我们的内部实体到外部实体的映射是通过配置完成的——而不是代码!配置人员不必编译任何东西来公开这些实体。

这可以像这样用 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
}