【问题标题】:Reading request body in middleware for .Net 5在.Net 5的中间件中读取请求正文
【发布时间】:2021-08-18 11:24:19
【问题描述】:

我正在尝试读取从客户端发送到我的后端的请求正文。内容以 JSON 格式发送,并让用户从表单中输入。如何在为控制器路由设置的中间件中读取请求正文。

这是我的模型

namespace ChatboxApi.Models
{
    public class User
    {
        public string Login { get; set; } = default;
        public string Password { get; set; } = default;
        public string Email { get; set; } = default;
        public string FullName { get; set; } = default;
        public int Phone { get; set; } = default;
        public string Website { get; set; } = default;

    }
}

这是我的控制器

namespace ChatboxApi.Controllers
{
    [ApiController]
    [Route("api/signup")]
    public class SignupController : ControllerBase
    {
        [HttpPost]
        public ActionResult SignUp([FromBody] User user)
        {
            return Ok(user);
        }

    }
}

这是我的中间件类

namespace ChatboxApi.Middleware
{
    public class CreateSession
    {
        private readonly RequestDelegate _next;

        public CreateSession(RequestDelegate next)
        {
            this._next = next;
        }

        public async Task Invoke(HttpContext httpContext)
        {
           //I want to get the request body here and if possible
           //map it to my user model and use the user model here.
            
            
        }

}

【问题讨论】:

  • 你不应该将中间件用于这样的事情,imo。理想情况下,您的请求路由应该取决于请求路径 - 或最多取决于 HTTP 请求标头。您不应根据请求正文的内容进行路由。这只是自找麻烦 - 尤其是因为 ASP.NET 甚至会在收到请求正文之前路由请求 - 这解释了您遇到的问题。
  • 所以你的意思是在控制器中完成工作比在中间件中更好?
  • 是的。 “工作”不应在中间件中完成 - 中间件应用于设置请求处理环境或为实际处理程序提供服务(例如设置失败请求日志记录、解压缩 gzip-compressed请求正文等)。
  • 嗨@championq45,有什么更新吗?我的回答是否帮助您解决了您的问题?如果可以,请您接受作为答案吗?如果没有,请您跟进让我知道吗?参考:How to accept as answer。谢谢。
  • @Rena 谢谢你的提醒。您的答案确实有效,并且已被标记为问题的答案。

标签: c# asp.net .net asp.net-mvc asp.net-core-middleware


【解决方案1】:

通常Request.Body不支持倒带,所以只能读取一次。临时解决方法是在调用 EnableBuffering 后立即拉出正文,然后将流倒回到 0 并且不处理它:

public class CreateSession
{
    private readonly RequestDelegate _next;

    public CreateSession(RequestDelegate next)
    {
        this._next = next;
    }

    public async Task Invoke(HttpContext httpContext)
    {
        var request = httpContext.Request;

        request.EnableBuffering();
        var buffer = new byte[Convert.ToInt32(request.ContentLength)];
        await request.Body.ReadAsync(buffer, 0, buffer.Length);
        //get body string here...
        var requestContent = Encoding.UTF8.GetString(buffer);

        request.Body.Position = 0;  //rewinding the stream to 0
        await _next(httpContext);

    }
}

注册服务:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    //...
    app.UseHttpsRedirection();

    app.UseMiddleware<CreateSession>();

    app.UseRouting();

    app.UseAuthorization();

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

}

【讨论】:

  • 如果请求正文超过 2GB - 或者没有请求正文,此方法将不起作用。
【解决方案2】:

我创建了中间件来记录每个请求并保存在数据库中。希望这段代码对你有所帮助。

using Newtonsoft.Json;

namespace ChatboxApi.Middleware
{
    public class CreateSession
    {
        private readonly RequestDelegate _next;    

        public CreateSession(RequestDelegate next)
        {
            this._next = next;
        }
           
        public async Task Invoke(HttpContext httpContext)
        {
           // I want to get the request body here and if possible
           // map it to my user model and use the user model here.

            var req = httpContext.Request;
            var xbody = await ReadBodyAsync(req);
            var bodyRaw = JsonConvert.SerializeObject(xbody);

            var param = JsonConvert.SerializeObject(req.Query);
            var header = JsonConvert.SerializeObject(req.Headers);
            var originalUrl = JsonConvert.SerializeObject(req.Path);
        }
}

【讨论】:

    猜你喜欢
    • 2021-03-13
    • 2019-06-23
    • 2023-02-23
    • 2018-04-07
    • 1970-01-01
    • 2019-01-17
    • 1970-01-01
    • 1970-01-01
    • 2021-08-21
    相关资源
    最近更新 更多