C# Swagger HttpPost 原始 urlencoded 正文

问题描述 投票:0回答:1

我正在使用控制器和 Swagger 在 C#.Net 中构建 API,但我需要在 POST 中接受任意一组键值,并且无法找到如何让 swagger 显示输入框(如果可能的话,用于 HttpPost 方法将正文拆分为 IFormCollection)。

POST 内容如下所示:

key1=val1&key2=val2&key3=val3a&key3=val3b&.....

等等任意数量的键值。

处理程序如下所示,可以正常工作,但 SwaggerUI 不提供任何输入框来传递正文:

[HttpPost]
[Consumes(MediaTypeNames.Application.FormUrlEncoded)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> SetKeys()
{
    var keyvals = await Request.Body.ToDictionary();  // Uses Stream extension
    if (keyvals.Count == 0)
        return BadRequest("No data received");

    // update database

    return NoContent(); //204
}

我尝试过不同的签名都无济于事

public async Task<IActionResult> SetKeys([FromForm] string content)
public async Task<IActionResult> SetKeys([FromBody] string content)
public async Task<IActionResult> SetKeys([FromForm] IFormCollection content)
public async Task<IActionResult> SetKeys([FromBody] IFormCollection content)
public async Task<IActionResult> SetKeys([FromBody] List<KeyValuePair<string, string>> content)

将 Consumes 设置为 text/plain 有效(Swagger 显示一个输入框,并且在发送之前不会对其进行操作),然后读取 [FromBody],但我仍然必须将正文提取为键值对,并且我失去了对预期的验证检查内容类型:

[HttpPost]
[Consumes(MediaTypeNames.Text.Plain)]
[ProducesResponseType(typeof(string), StatusCodes.Status200OK, MediaTypeNames.Application.FormUrlEncoded)]
public async Task<IActionResult> SetKeys([FromBody] string content)
{
    var keyvals = await content.ToDictionary();  // Uses String extension
    if (keyvals.Count == 0)
        return BadRequest("No data received");

    // update database

    return NoContent(); //204
}

我什至尝试了一个InputFormatter,它至少允许我以大摇大摆的方式选择Content-Type,但它将每个字符的内容分割成一个键:

using System.Net.Mime;
using Microsoft.AspNetCore.Mvc.Formatters;

namespace RequestRouter.Utilities;

public class RawBodyInputFormatter : InputFormatter
{
    public RawBodyInputFormatter()
    {
        this.SupportedMediaTypes.Add(MediaTypeNames.Application.FormUrlEncoded);
        //this.SupportedMediaTypes.Add(MediaTypeNames.Text.Plain);
    }

    public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
    {
        var request = context.HttpContext.Request;
        using var reader = new StreamReader(request.Body);
        var content = await reader.ReadToEndAsync();
        return await InputFormatterResult.SuccessAsync(content);
    }

    protected override bool CanReadType(Type type)
    {
        return type == typeof(string);
    }
}

选择 application/x-www-form-urlencoded 时 Swagger 如何格式化卷曲:

curl -X 'POST' \
  'http://localhost:8001/config' \
  -H 'accept: */*' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d '0=k&1=e&2=y&3=1&4=%3D&5=v&6=a&7=l&8=1'
c# asp.net-core swagger
1个回答
0
投票

我们可以通过使用自定义

IOperationFilter
来实现此功能。这是测试结果,你可以先查看一下。

enter image description here

FormDataOperationFilter.cs

using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace WebApplication1
{
    public class FormDataOperationFilter : IOperationFilter
    {
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            var formMediaType = new OpenApiMediaType();
            formMediaType.Schema = context.SchemaGenerator.GenerateSchema(typeof(Dictionary<string, string>), context.SchemaRepository);
            formMediaType.Schema.Properties.Clear();

            operation.RequestBody = new OpenApiRequestBody
            {
                Content = { ["application/x-www-form-urlencoded"] = formMediaType }
            };
        }
    }
}

程序.cs

using Microsoft.OpenApi.Models;
using WebApplication1;

var builder = WebApplication.CreateBuilder(args);

...
builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
    c.OperationFilter<FormDataOperationFilter>();
});

var app = builder.Build();

...

app.Run();
© www.soinside.com 2019 - 2024. All rights reserved.