简体   繁体   English

ASP.NET核心中未绑定参数添加swagger参数

[英]Add swagger parameters for unbound parameters in ASP.NET Core

I have an ASP.NET Core 2.2 WebApi and want to upload large files with some additional metadata.我有一个 ASP.NET Core 2.2 WebApi 并且想要上传带有一些额外元数据的大文件。 The request is a multipart/form-data.该请求是一个多部分/表单数据。 Because the files to upload can get quite large, I do not want to read it into memory for processing but rather stream it directly to it's desired destination.因为要上传的文件可能会变得很大,所以我不想将其读入 memory 进行处理,而是将 stream 直接读入所需的目的地。 I followed the documentation to disable form value model binding and I also adjusted the maximum request size for the endpoint.我按照文档禁用了表单值 model 绑定,并且我还调整了端点的最大请求大小。

I have tested the endpoint with postman and it works as expected:我已经用 postman 测试了端点,它按预期工作: 在此处输入图像描述

However, Swagger obviously does not recognize that there should be parameters for the request.但是,Swagger 显然不承认请求应该有参数。 How can I add these parameters to the swagger documentation without defining the parameters in the method's signature?如何在不定义方法签名中的参数的情况下将这些参数添加到 swagger 文档中?

My endpoint looks like the following example:我的端点类似于以下示例:

[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);
}

Usually, I would bind the parameters like the following example:通常,我会像下面的例子那样绑定参数:

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

This works as expected in Swagger but as mentioned above, I do not want to bind the parameters.这在 Swagger 中按预期工作,但如上所述,我不想绑定参数。

For Swashbuckle.AspNetCore version 5 and above some things have changed.对于 Swashbuckle.AspNetCore 版本 5 及更高版本,一些事情发生了变化。

To provide the parameters like Alexander did in his answer, the code would look something like the following:为了像 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,
});

For some reason however (which I did not investigate further), I was not able to perform an call in the Swagger UI with this approach.但是由于某种原因(我没有进一步调查),我无法使用这种方法在 Swagger UI 中执行调用。

In the end, the following example provided me the result I was looking for:最后,以下示例为我提供了我正在寻找的结果:

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 }
                }
            };
        }
    }
}

You can use IOperationFilter for this.您可以为此使用IOperationFilter Add the following class, adjust controller and action names添加以下class,调整controller和动作名称

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
            });
        }
    }
}

In Startup.csStartup.cs

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM