ASP.NET Core 3.0 WebAPI请求体(Request.Body)和[FromBody]冲突问题

4

frombody 中获取请求体需要使用 request.body,但是经过两天的测试我还没有找到解决办法。我已经添加了 Request.EnableBuffering()

// PUT: api/Test/5
[HttpPut("{id}")]
public async Task<string> PutAsync(int id, [FromBody]ProductInfo value)
{
    var ccccc = "";
    Request.EnableBuffering();
    using (var reader = new StreamReader(Request.Body, encoding: System.Text.Encoding.UTF8))
    {
        var body = await reader.ReadToEndAsync();
        ccccc = body;
        Request.Body.Position = 0;
    }
    return ccccc;
}

1
你遇到了什么错误? - Isma
请提供ProductInfo的定义,并解释您想要实现什么。 - Zinov
1个回答

4
我想您遇到的问题是您的cccc返回为空。这很可能是因为在进入控制器时,请求正文流已经被读取完了。这是有道理的 - 必须有一些东西来填充value参数。所以现在尝试倒带流已经太迟了。 ASP.NET Blog有一篇文章介绍了如何解决这个问题:您需要一个自定义中间件,并将其插入到MVC中间件之上的管道中。

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<CustomMiddleware>(); // register your custom middleware with DI container
    services.AddControllers();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseMiddleware<CustomMiddleware>(); // inject your middleware before MVC injects theirs

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

然后您的自定义中间件可能如下所示:

CustomMiddleware.cs

public class CustomMiddleware : IMiddleware
{
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        context.Request.EnableBuffering(); // now you can do it

        // Leave the body open so the next middleware can read it.
        using (var reader = new StreamReader(context.Request.Body, encoding: Encoding.UTF8, detectEncodingFromByteOrderMarks: false, leaveOpen: true))
        {
            var body = await reader.ReadToEndAsync();
            context.Items.Add("body", body); // there are ways to pass data from middleware to controllers downstream. this is one. see https://dev59.com/CFYN5IYBdhLWcg3w9Mfr for more

            // Reset the request body stream position so the next middleware can read it
            context.Request.Body.Position = 0;
        }

        // Call the next delegate/middleware in the pipeline
        await next(context);
    }
}

最后,在您的控制器中,您将像这样从context获取主体:

// PUT: api/Test/5
[HttpPut("{id}")]
public async Task<string> PutAsync(int id, [FromBody]ProductInfo value)
{            
    var ccccc = (string)HttpContext.Items["body"];
    return ccccc;
}

这种方法有一些注意事项,在文章中进行了讨论。要注意大请求体并相应地调整缓冲区大小。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接