Search code examples
asp.netasp.net-mvcasp.net-core.net-core

Read Asp.Net Core Response body in ActionFilterAttribute


I'm using ASP.NET Core as a REST API Service. I need access to request and response in ActionFilter. Actually, I found the request in OnActionExcecuted but I can't read the response result.

I'm trying to return value as follow:

[HttpGet]
[ProducesResponseType(typeof(ResponseType), (int)HttpStatusCode.OK)]
[Route("[action]")]
public async Task<IActionResult> Get(CancellationToken cancellationToken)
{
    var model = await _responseServices.Get(cancellationToken);
    return Ok(model);
}

And in ActionFilter OnExcecuted method as follow:

_request = context.HttpContext.Request.ReadAsString().Result;
_response = context.HttpContext.Response.ReadAsString().Result; //?

I'm trying to get the response in ReadAsString as an Extension method as follow:

public static async Task<string> ReadAsString(this HttpResponse response)
{
     var initialBody = response.Body;
     var buffer = new byte[Convert.ToInt32(response.ContentLength)];
     await response.Body.ReadAsync(buffer, 0, buffer.Length);
     var body = Encoding.UTF8.GetString(buffer);
     response.Body = initialBody;
     return body;
 }

But, there is no result!

How I can get the response in OnActionExcecuted?


Solution

  • If you're logging for JSON result/ view result , you don't need to read the whole response stream. Simply serialize the context.Result:

    public class MyFilterAttribute : ActionFilterAttribute
    {
        private ILogger<MyFilterAttribute> logger;
    
        public MyFilterAttribute(ILogger<MyFilterAttribute> logger){
            this.logger = logger;
        }
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            var result = context.Result;
            if (result is JsonResult json)
            {
                var x = json.Value;
                var status = json.StatusCode;
                this.logger.LogInformation(JsonConvert.SerializeObject(x));
            }
            if(result is ViewResult view){
                // I think it's better to log ViewData instead of the finally rendered template string
                var status = view.StatusCode;
                var x = view.ViewData;
                var name = view.ViewName;
                this.logger.LogInformation(JsonConvert.SerializeObject(x));
            }
            else{
                this.logger.LogInformation("...");
            }
        }