asp.net core3.0 webapi request.body and [frombody] conflict [closed]

Deadly 提交于 2020-02-25 13:17:31

问题


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

回答1:


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 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.

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

then your custom middleware might look like so:

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

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.



来源:https://stackoverflow.com/questions/59598589/asp-net-core3-0-webapi-request-body-and-frombody-conflict

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!