有什么方法可以获取.NET Core FilterAttribute中的请求正文? [英] Is there any way to get request body in .NET Core FilterAttribute?

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

问题描述

我的请求示例

  http:// localhost:8065 / api / note 
POST
content-type:application / json
请求正文:{ id: 1234, title: test, status:草稿}

,响应应该为

  { msg:确定,代码:1} 

操作

 公共异步任务< IActionResult> Post([FromBody] NoteModel模型)






为了自动记录每个请求,我创建了一个属性来完成这项工作。该属性看起来像:(来自

解决方案

因此,此在中间件中记录/读取请求正文的最佳方法线程,以下应该可以工作:

  //使用Microsoft.AspNetCore.Http.Internal; 

公共类SampleActionFilterAttribute:TypeFilterAttribute
{
...

public void OnActionExecuting(ActionExecutedContext context)
{
/ /在执行MVC动作之前读取主体
string bodyData = ReadBodyAsString(context.HttpContext.Request);
}

私有字符串ReadBodyAsString(HttpRequest request)
{
var initialBody = request.Body; //解决方法

尝试
{
request.EnableRewind();

使用(StreamReader reader = new StreamReader(request.Body))
{
string text = reader.ReadToEnd();
返回文字;
}
}
最后
{
//解决方法,因此MVC操作将能够读取主体以及
请求。
}

返回字符串。
}
}

两次读取请求正文这样发布






更新:如果在中间件中使用上述方法,则在 ReadBodyAsString 中的上述方法适用,而不是在动作过滤器中使用。区别在于,在调用动作过滤器时(即使对于 OnActionExecuting ),主体流也已被读取,并且 [FromBody]模型已被填充。



好的优点是,因此可以使用 context.ActionArguments []在操作过滤器中直接获取模型。 < model_name>] 。在您的情况下:

  public void OnActionExecuted(ActionExecutedContext context)
{
var model = context.ActionArguments [ model]作为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天全站免登陆