asp.net core3.0 webapi request.body和[frombody]冲突 [英] asp.net core3.0 webapi request.body and [frombody] conflict

查看:159
本文介绍了asp.net core3.0 webapi request.body和[frombody]冲突的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要在frombody之后通过 request.body 获取主体,但是经过2天的测试我没有找到解决方案.我添加了 Request.EnableBuffering().

I need to get the body through request.body after frombody, but I haven't found a solution after testing for 2 days. I've added 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;
}

推荐答案

我相信您遇到的问题是 cccc 变空了.这可能是因为到您进入控制器时,请求主体流已经被读取.这很有意义-必须为您填充 value 参数.因此,在此阶段尝试倒带流为时已晚.

I believe the issue you are having is your cccc comes back empty. This is likely because by the time you entered your controller, the request body stream has already been read through. It makes sense - something has to populate the value parameter for you. So it is too late to try and rewind the stream at this stage.

ASP.NET博客上有一篇有关如何实现此目标的文章:您需要一个自定义的中间件,并且需要将其插入MVC中间件上方的管道中.

ASP.NET Blog has an article on how you would approach this: you need a custom middleware and you need to insert it into the pipeline above MVC middleware.

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

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

then your custom middleware might look like so:

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://stackoverflow.com/questions/46601757/c-sharp-dotnet-core-2-pass-data-from-middleware-filter-to-controller-method 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 获取正文:

and finally in your controller, you will fetch the body from context like so:

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

此方法附带一些警告,将在本文中进行讨论.注意庞大的请求主体,并相应地调整缓冲区大小.

this method comes with a few caveats, that are discussed in the article. watch out for huge request bodies and tune your buffer size accordingly.

这篇关于asp.net core3.0 webapi request.body和[frombody]冲突的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆