如何在ProducesResponseType Swagger上返回泛型?
问题描述:
在下面的代码,你会看到在ProducesResponseType一件T型(通用),但我不能让它工作,因为它不是一个特定类型:如何在ProducesResponseType Swagger上返回泛型?
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);
}
}
有什么建议?
答
经过仔细观察,似乎可以(并且更容易)使用操作过滤器。
沿着这个线应该工作(未经测试,只是确保它没有编译错误)。
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 }
});
}
}
}
}
}
它能做什么?每个操作(Get,Post,Put等)都会调用IOperationFilter
。在它里面,你检查它是否是ControllerActionDescriptor
,如果是,请检查控制器类型。
如果您愿意,您可以缩小为一种特定类型。我刚刚采取了从另一个类继承的每个控制器,它的基类型与通用参数通用。然后检查它是否为“Get”操作(post,put,delete通常不返回模型,只是状态码/错误响应),然后检查该类型是否已经在Swagger/OpenAPI中模式定义。如果模型在那里,请阅读它的模式并在响应中引用它。
如果模型未在模式注册表中注册,则会变得更加复杂。您需要使用反射并构建模式文件,将其添加到存储库(在调用context.SchemaRegistry.GetOrRegister(typeParam)
期间已发生),然后按照上面的方法引用它。
当模型没有用作任何其他控制器中的响应或动作参数时,会发生这种情况。
您可以获得关于OpenAPI 2.0规范的更多信息。
您无法通过属性。但是你可以编写你自己的'ISchemaFilter'或者'IDocumentFilter'来修改打开的api文件,在它被序列化为json之前 – Tseng
@Tseng你有没有这方面的示例? – Jude