有没有办法在 .NET Core FilterAttribute 中获取请求正文? [英] Is there any way to get request body in .NET Core FilterAttribute?

查看:32
本文介绍了有没有办法在 .NET Core FilterAttribute 中获取请求正文?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的请求示例

http://localhost:8065/api/note邮政内容类型:应用程序/json请求正文:{id":1234",title":test",status":draft"}

响应应该是

{ "msg" : "ok", "code" : 1}

动作

public async TaskPost([FromBody]NoteModel 模型)

<小时>

为了自动记录每个请求,我创建了一个属性来完成这项工作.该属性如下所示:(来自

解决方案

据此"最佳方式在中间件"线程中记录/读取请求正文,以下应该起作用:

//使用 Microsoft.AspNetCore.Http.Internal;公共类 SampleActionFilterAttribute : TypeFilterAttribute{...public void OnActionExecuting(ActionExecutedContext context){//在 MVC 动作执行之前读取主体string bodyData = ReadBodyAsString(context.HttpContext.Request);}私有字符串 ReadBodyAsString(HttpRequest 请求){var initialBody = request.Body;//解决方法尝试{request.EnableRewind();使用 (StreamReader reader = new StreamReader(request.Body)){字符串文本 = reader.ReadToEnd();返回文本;}}最后{//解决方法,以便 MVC 操作也能够读取正文request.Body = initialBody;}返回字符串.空;}}

两次读取请求正文中描述的类似方法

<小时>

更新:ReadBodyAsString 中的上述方法如果在中间件中使用,而不是在动作过滤器中使用将起作用.不同之处在于,当动作过滤器调用时(即使对于 OnActionExecuting),主体流已经被读取并且 [FromBody] 模型 已经被填充.​​

好消息是,可以通过使用 context.ActionArguments[""] 直接在动作过滤器中获取模型.在你的情况下:

public void OnActionExecuted(ActionExecutedContext context){var model = context.ActionArguments["model"] as NoteModel;}

Sample of my request

http://localhost:8065/api/note
POST
content-type:application/json
request body: { "id" : "1234", "title" : "test", "status" : "draft"}

and the response should be

{ "msg" : "ok", "code" : 1}

The action

public async Task<IActionResult> Post([FromBody]NoteModel model)


In order to have every request logged automatically, I create an attribute to do this job. The attribute looks like: (from Microsoft Docs)

public class SampleActionFilterAttribute : TypeFilterAttribute
{
    public SampleActionFilterAttribute():base(typeof(SampleActionFilterImpl))
    {
    }

    private class SampleActionFilterImpl : IActionFilter
    {
        private readonly ILogger _logger;
        public SampleActionFilterImpl(ILoggerFactory loggerFactory)
        {
            _logger = loggerFactory.CreateLogger<SampleActionFilterAttribute>();
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {

        }

        public void OnActionExecuted(ActionExecutedContext context)
        {
            _logger.LogDebug("[path]" + context.HttpContext.Request.Path);
            _logger.LogDebug("[method]" + context.HttpContext.Request.Method);
            _logger.LogDebug("[body]"); //log request body, expectation: { "id" : "1234", "title" : "test", "status" : "draft"}
            _logger.LogDebug("[statuscode]" + context.HttpContext.Response.StatusCode);
            _logger.LogDebug("[response]"); //log response
        }
    }
}

I try to use streamReader to get request body only get empty string.

StreamReader reader = new StreamReader(context.HttpContext.Request.Body);
string text = reader.ReadToEnd();

Is that because the body was read by [fromBody] from controller so the stream can not be read twice? If so, how am I supposed to get request body and response in OnActionExecuted method?


Update:

I've just copied Set's code into my project, not working. Here is the debug gif

解决方案

Accordingly to this "Best way to log/read request body in a middleware" thread, the following should work:

// using Microsoft.AspNetCore.Http.Internal;

public class SampleActionFilterAttribute : TypeFilterAttribute
{
    ... 

    public void OnActionExecuting(ActionExecutedContext context)
    {
        // read body before MVC action execution
        string bodyData = ReadBodyAsString(context.HttpContext.Request);
    }

    private string ReadBodyAsString(HttpRequest request)
    {
        var initialBody = request.Body; // Workaround

        try
        {
            request.EnableRewind();

            using (StreamReader reader = new StreamReader(request.Body))
            {
                string text = reader.ReadToEnd();
                return text;
            }
        }
        finally
        {
            // Workaround so MVC action will be able to read body as well
            request.Body = initialBody; 
        }

        return string.Empty;
    }
 }

Also similar approach described in Read request body twice SO post


Update: above approach in ReadBodyAsString with will work if used in middleware, not in action filter. The difference is that when action filter is calling (even for OnActionExecuting), the body stream already has been read and [FromBody] model has been populated.

The good nesw is that so it is possible to get model directly in action filter by using context.ActionArguments["<model_name>"]. In your case:

public void OnActionExecuted(ActionExecutedContext context)
{
   var model = context.ActionArguments["model"] as NoteModel;
}

这篇关于有没有办法在 .NET Core FilterAttribute 中获取请求正文?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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