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

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

问题描述

我正在尝试在 OnActionExecuting 方法中读取请求正文,但我总是为正文获取 null.

I'm trying to read the request body in the 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,所以我认为事情有点不同.我可以看到这里的所有示例都是指旧的 Web API 版本.

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 a little different I think. I can see all the samples here referring to old web API 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 扩展:EnableBuffering 它将大请求存储到磁盘而不是将其保存在内存中,避免存储在内存中的大流问题(文件、图像、……).您可以通过设置ASPNETCORE_TEMP 环境变量来更改临时文件夹,一旦请求结束,文件将被删除.

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 core webapi 控制器中读取请求正文?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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