【问题标题】:How to return generic types on ProducesResponseType Swagger?如何在 ProducesResponseType Swagger 上返回泛型类型?
【发布时间】:2017-10-19 05:18:20
【问题描述】:

在下面的代码中,您会在 ProducesResponseType 上看到一个 T 类型(通用),但我无法使其工作,因为它不是特定类型:

 public class ApiController<T> : ApiBaseController where T : class, IDocument
  {    
    protected IDataService<T> data = null;

    [HttpGet("{id}")]
    **[ProducesResponseType(typeof(T), 201)]**
    [ProducesResponseType(typeof(void), 500)]         
    public async Task<IActionResult> Get(string id)
    {
        var result = await data.Get(id);

        return Ok(result);
    }
 }

有什么建议吗?

【问题讨论】:

  • 你不能通过属性。但是您可以编写自己的 ISchemaFilterIDocumentFilter 来修改打开的 api 文档,然后再将其序列化为 json
  • @Tseng 你有这个样品吗?

标签: generics asp.net-core swagger swagger-ui swashbuckle


【解决方案1】:

仔细观察后,似乎可以(并且更容易)使用操作过滤器。

类似的东西应该可以工作(未经测试,只是确保它没有给出编译错误)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Controllers;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace MyCompany.Common.Web.Swagger.OperationFilters
{
    public class GenericOperationFilter : IOperationFilter
    {
        public void Apply(Operation operation, OperationFilterContext context)
        {
            if (context.ApiDescription.ActionDescriptor is ControllerActionDescriptor controllerDescriptor)
            {
                var baseType = controllerDescriptor.ControllerTypeInfo.BaseType?.GetTypeInfo();
                // Get type and see if its a generic controller with a single type parameter
                if (baseType == null || (!baseType.IsGenericType && baseType.GenericTypeParameters.Length == 1))
                    return;

                if (context.ApiDescription.HttpMethod == "GET" && !operation.Responses.ContainsKey("200"))
                {
                    var typeParam = baseType.GenericTypeParameters[0];

                    // Get the schema of the generic type. In case it's not there, you will have to create a schema for that model
                    // yourself, because Swagger may not have added it, because the type was not declared on any of the models
                    string typeParamFriendlyId = typeParam.FriendlyId();

                    if (!context.SchemaRegistry.Definitions.TryGetValue(typeParamFriendlyId, out Schema typeParamSchema))
                    {
                        // Schema doesn't exist, you need to create it yourself, i.e. add properties for each property of your model.
                        // See OpenAPI/Swagger Specifications
                        typeParamSchema = context.SchemaRegistry.GetOrRegister(typeParam);

                        // add properties here, without it you won't have a model description for this type
                    }

                    // for any get operation for which no 200 response exist yet in the document
                    operation.Responses.Add("200", new Response
                    {
                        Description = "Success",
                        Schema = new Schema { Ref = typeParamFriendlyId }
                    });
                }
            }
        }
    }
}

它有什么作用? IOperationFilter 为每个操作(Get、Post、Put 等)调用。在里面,你检查它是否是ControllerActionDescriptor,如果是,检查控制器类型。

如果您愿意,您可以将其缩小到一种特定类型。我刚刚采用了从另一个类继承的每个控制器,它的基类型是具有 一个单个泛型参数的泛型。

最后,它检查它是否是一个“获取”操作(post、put、delete 通常不返回模型,只返回状态代码/错误响应),然后检查该类型是否已经在 Swagger/OpenAPI 架构中定义。如果模型在那里,请阅读它的架构并在响应中引用它。

如果模型没有在模式注册表中注册,它会变得更加复杂。您需要使用反射并构建模式文件,将其添加到存储库(在context.SchemaRegistry.GetOrRegister(typeParam) 调用期间已经发生),然后像上面那样引用它。

当模型不用作任何其他控制器中的响应或操作参数时,可能会发生这种情况。

您将获得有关 OpenAPI 2.0 规范的更多信息。

【讨论】:

    猜你喜欢
    • 2022-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-18
    • 2016-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多