swagger 当路由参数类型只在路由中声明而不在操作方法中作为输入参数时,SwashBuckle会忽略它们

lmyy7pcs  于 2023-05-06  发布在  其他
关注(0)|答案(1)|浏览(142)

我有一个带有一些预定义路由模板的基本控制器:

[Authorize]
[ApiController]
[Produces(MediaTypeNames.Application.Json)]
public abstract class TenantControllerBase : ControllerBase
{
    public const string DefaultRoute = "api/s/{serviceId:int}/[controller]";

    private readonly ITenantContext _tenantContext; // Extracts the value of serviceId in a middelware

    protected int ServiceId => _tenantContext.ServiceId;

    protected TenantControllerBase(ITenantContext tenantContext)
    {
        _tenantContext = tenantContext ?? throw new ArgumentNullException(nameof(tenantContext));
    }
}

这个想法是能够使用中间件检索serviceId,并使其可用于从TenantControllerBase继承的所有控制器,而无需每次在操作中显式地将其作为输入参数:

[Route(DefaultRoute)]
public class SomeTenantController : TenantControllerBase
{
    public SomeTenantController(ITenantContext tenantContext) : base(tenantContext) { }

    [HttpGet("{type}")]
    public async Task<IActionResult> Get(string type, CancellationToken cancellationToken)
    {
        var serviceId = this.ServiceId;
        
        // ...

        return Ok();
    }
}

这样做的问题是Swagger规范将serviceId的类型设置为字符串,而不是路由模板中指定的整数:

"/api/s/{serviceId}/SomeTenant/{type}": {
  "get": {
    "tags": [
      "SomeTenant"
    ],
    "parameters": [
      {
        "name": "type",
        "in": "path",
        "required": true,
        "style": "simple",
        "schema": {
          "type": "string"
        }
      },
      {
        "name": "serviceId",
        "in": "path",
        "required": true,
        "style": "simple",
        "schema": {
          "type": "string"
        }
      }
    ],
    "responses": {
      "200": {
        "description": "Success"
      }
    }
  }
},

就我所尝试的而言,让Swagger理解serviceId是一个整数的唯一方法是显式地将其添加到action方法签名中:

[HttpGet("{type}")]
    public async Task<IActionResult> Get(
        string type,
        int serviceId, 
        CancellationToken cancellationToken)
    {
        // serviceId is the same as the base field this.ServiceId;
        
        // ...

        return Ok();
    }

有没有办法强制swagger根据路由模板api/s/{serviceId:int}/[controller]中指定的值类型来设置值类型,而不必显式地将其添加到action方法签名中?

b91juud3

b91juud31#

您可以使用一个简单的操作过滤器来修补它,以更新所有端点的服务ID参数类型:

public class ServiceIdPathFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        var serviceIdParameter = operation.Parameters
            .FirstOrDefault(x => x.Name == "serviceId" && x.In == ParameterLocation.Path);
        if (serviceIdParameter != null)
        {
            serviceIdParameter.Schema.Type = "integer";
        }
    }
}

启动注册:

services.AddSwaggerGen(opts => opts.OperationFilter<ServiceIdPathFilter>());

不再对字符串值有效:

相关问题