【问题标题】:Add swagger parameters for unbound parameters in ASP.NET Core为 ASP.NET Core 中的未绑定参数添加 swagger 参数
【发布时间】:2021-05-21 04:26:16
【问题描述】:

我有一个 ASP.NET Core 2.2 WebApi,想上传带有一些额外元数据的大文件。该请求是一个多部分/表单数据。因为要上传的文件可能会变得非常大,所以我不想将其读入内存进行处理,而是将其直接流式传输到所需的目的地。 我按照documentation 禁用了表单值模型绑定,还调整了端点的最大请求大小。

我已经用邮递员测试了端点,它按预期工作:

但是,Swagger 显然没有认识到请求应该有参数。如何在不定义方法签名中的参数的情况下将这些参数添加到 swagger 文档中?

我的端点类似于以下示例:

[HttpPost]
[DisableFormValueModelBinding]
[DisableRequestSizeLimit]
public async Task<IActionResult> Upload() // "department" and "file" needed in the multipart/form-data
{
  // var path = await uploader.UploadAsync(Request);
  // return Ok(path);
}

通常,我会像下面的例子那样绑定参数:

public async Task<IActionResult> Upload([FromForm] string department, [FromForm] IFormFile file)

这在 Swagger 中按预期工作,但如上所述,我不想绑定参数。

【问题讨论】:

    标签: c# asp.net-core asp.net-web-api swagger multipartform-data


    【解决方案1】:

    对于 Swashbuckle.AspNetCore 版本 5 及更高版本,一些事情发生了变化。

    要像 Alexander 在他的回答中所做的那样提供参数,代码如下所示:

    operation.Parameters.Add(new OpenApiParameter()
    {
        Name = "department",
        Schema = new OpenApiSchema { Type = "string", Format = "string" },
        Required = true,
    });
    
    operation.Parameters.Add(new OpenApiParameter()
    {
        Name = "file",
        Schema = new OpenApiSchema { Type = "string", Format = "binary" },
        Required = true,
    });
    

    但是由于某种原因(我没有进一步调查),我无法使用这种方法在 Swagger UI 中执行调用。

    最后,以下示例为我提供了我正在寻找的结果:

    public class AddUnboundParametersOperationFilter : IOperationFilter
    {
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            var descriptor = context.ApiDescription.ActionDescriptor as ControllerActionDescriptor;
        
            if (descriptor != null && descriptor.ControllerTypeInfo == typeof(RemoteUpdateController) && descriptor.ActionName == nameof(RemoteUpdateController.Upload))
            {
                var openApiMediaType = new OpenApiMediaType
                {
                    Schema = new OpenApiSchema
                    {
                        Type = "object",
                        Required = new HashSet<string> { "department", "file" }, // make the parameter(s) required if needed
                        Properties = new Dictionary<string, OpenApiSchema>
                        {
                            { "department" , new OpenApiSchema() { Type = "string", Format = "string" } },
                            { "file" , new OpenApiSchema() { Type = "string", Format = "binary" } },
                        }
                    }
                };
    
                operation.RequestBody = new OpenApiRequestBody
                {
                    Content = new Dictionary<string, OpenApiMediaType>
                    {
                        { "multipart/form-data", openApiMediaType }
                    }
                };
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      您可以为此使用IOperationFilter。添加以下类,调整控制器和动作名称

      public class AddUnboundParametersOperationFilter : IOperationFilter
      {
          public void Apply(Operation operation, OperationFilterContext context)
          {
              if (operation.Parameters == null)
                  operation.Parameters = new List<IParameter>();
      
              var descriptor = context.ApiDescription.ActionDescriptor as ControllerActionDescriptor;
      
              if (descriptor != null && descriptor.ControllerTypeInfo == typeof(TestController) && descriptor.ActionName == nameof(TestController.Upload))
              {
                  operation.Parameters.Add(new NonBodyParameter()
                  {
                      Name = "department",
                      Type = "string",
                      Required = true,
                      In = "formData",
                  });
      
                  operation.Parameters.Add(new NonBodyParameter()
                  {
                      Type = "file",
                      In = "formData",
                      Name = "file",
                      Required = true
                  });
              }
          }
      }
      

      Startup.cs

      services.AddSwaggerGen(c =>
      {
          c.OperationFilter<AddUnboundParametersOperationFilter>();
          //...
      });
      

      【讨论】:

      • 这绝对让我走上了正轨,但是,您的解决方案不适用于 Swashbuckle 版本 5 及更高版本。无论如何,我认为这将适用于早期版本。如果有人在寻找第 5 版及更高版本的示例,请查看我对这个问题的回答。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-04
      • 2011-01-17
      • 1970-01-01
      • 2021-04-11
      • 2021-12-22
      • 2020-12-30
      相关资源
      最近更新 更多