如何在asp.net核心webapi控制器中读取请求正文? [英] How to read request body in a asp.net core webapi controller?

查看:382
本文介绍了如何在asp.net核心webapi控制器中读取请求正文?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用OnActionExecuting方法读取请求正文,但是我总是获得该正文的null.

I'm trying to read the request body in OnActionExecuting method, but I always get null for the body.

var request = context.HttpContext.Request;
var stream = new StreamReader(request.Body);
var body = stream.ReadToEnd();

我试图将流位置显式设置为0,但这也没有用.由于这是ASP.NET CORE,因此我认为情况几乎没有什么不同.我可以在这里看到所有有关旧版webapi版本的示例.
还有其他方法吗?

I have tried to explicitly set the stream position to 0 but that also didn't work. Since this is ASP.NET CORE, Things are little different I think. I can see all the samples here referring to old webapi versions.
Is there any other way of doing this?

推荐答案

在ASP.Net Core中,多次阅读正文请求似乎很复杂,但是,如果您第一次尝试以正确的方式进行操作,则应该适合下一次尝试.

In ASP.Net Core it seems complicated to read several times the body request, however if your first attempt does it the right way, you should be fine for the next attempts.

例如,我通过替换体流阅读了几种周转方法,但是我认为以下是最干净的方法:

I read several turnaround for example by substituting the body stream, but I think the following is the cleanest:

最重要的是

  1. 让请求知道您将阅读其正文两次或多次,
  2. 不关闭体液流,并且
  3. 将其倒带到其初始位置,这样内部过程就不会丢失.

正如Murad指出的那样,您还可以利用.Net Core 2.1扩展:

As pointed out by Murad, you may also take advantage of the .Net Core 2.1 extension: EnableBuffering It stores large requests onto the disk instead of keeping it in memory, avoiding large-streams issues stored in memory (files, images, ...). You can change the temporary folder by setting ASPNETCORE_TEMP environment variable, and files are deleted once the request is over.

在AuthorizationFilter 中,您可以执行以下操作:

In an AuthorizationFilter, you can do the following:

// Helper to enable request stream rewinds
using Microsoft.AspNetCore.Http.Internal;
[...]
public class EnableBodyRewind : Attribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationFilterContext context)
    {
        var bodyStr = "";
        var req = context.HttpContext.Request;

        // Allows using several time the stream in ASP.Net Core
        req.EnableRewind(); 

        // Arguments: Stream, Encoding, detect encoding, buffer size 
        // AND, the most important: keep stream opened
        using (StreamReader reader 
                  = new StreamReader(req.Body, Encoding.UTF8, true, 1024, true))
        {
            bodyStr = reader.ReadToEnd();
        }

        // Rewind, so the core is not lost when it looks the body for the request
        req.Body.Position = 0;

        // Do whatever work with bodyStr here

    }
}



public class SomeController : Controller
{
    [HttpPost("MyRoute")]
    [EnableBodyRewind]
    public IActionResult SomeAction([FromBody]MyPostModel model )
    {
        // play the body string again
    }
}

然后,您可以在请求处理程序中再次使用主体.

Then you can use the body again in the request handler.

在您的情况下,如果得到的结果为空,则可能意味着该正文已在较早的阶段被读取.在这种情况下,您可能需要使用中间件(见下文).

In your case if you get a null result, it probably means that the body has already been read at an earlier stage. In that case you may need to use a middleware (see below).

但是,如果要处理大数据流,则要小心,该行为意味着所有内容都已加载到内存中,如果文件上传,则不应触发此操作.

However be careful if you handle large streams, that behavior implies that everything is loaded into memory, this should not be triggered in case of a file upload.

我的看起来像这样(同样,如果您下载/上传大文件,则应禁用此功能以避免出现内存问题):

Mine looks like this (again, if you download/upload large files, this should be disabled to avoid memory issues):

public sealed class BodyRewindMiddleware
{
    private readonly RequestDelegate _next;

    public BodyRewindMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        try { context.Request.EnableRewind(); } catch { }
        await _next(context);
        // context.Request.Body.Dipose() might be added to release memory, not tested
    }
}
public static class BodyRewindExtensions
{
    public static IApplicationBuilder EnableRequestBodyRewind(this IApplicationBuilder app)
    {
        if (app == null)
        {
            throw new ArgumentNullException(nameof(app));
        }

        return app.UseMiddleware<BodyRewindMiddleware>();
    }

}

这篇关于如何在asp.net核心webapi控制器中读取请求正文?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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