.NET Core Web API-如何从ActionResult获取响应信息 创建用于拦截请求和响应的中间件将中间件连接到HTTP管道创建自定义属性以处理端点级别的日志记录

问题描述

我有一个WebAPI Core端点方法,其中使用内部库(RequestLogManager)保存来自传入请求的请求和响应数据。

因为我想记录响应代码和正文,所以我将ActionResult存储在方法结尾处返回的变量中(而不是从方法中的多个位置返回)。示例:

    // This is a contrived method to illustrate the issue.
    
    [Route("test/actionresult/{testParam:int}")]
    [HttpGet]
    public async Task<ActionResult> GetTestActionResult(int testParam)
    {
        ActionResult actionResult = Ok(); // Default

        // Log Incoming Request
        int requestlogid = await RequestLogManager.LogIncomingRequestAsync("API - GetTestActionResult",Request);

        switch (testParam)
        {
            case 204:
                actionResult = NoContent();
                break;

            case 404:
                actionResult = NotFound();
                break;

            case 500:
                actionResult = StatusCode(StatusCodes.Status500InternalServerError,"An Error Occurred!");
                break;

            default:
                break;
        }

        // Log Outgoing Response
        RequestLogManager.LogResponseForRequestNowait(requestlogid,??? ResponseBody ???,??? ResponseCode ???);

        return actionResult;
    }

方法结束时,如何从ActionResult获取响应代码和正文的值以记录日志?

  • 我尝试使用Response.Body和Response.StatusCode,但是它们始终为“”和200(我想是因为我使用的是ActionResult而不是实际创建HttpResponse)。
  • 我尝试将ActionResult强制转换为ObjectResult-ObjectResult确实在属性StatusCode和Value中具有那些-但这会导致错误消息:Unable to cast object of type 'Microsoft.AspNetCore.Mvc.NoContentResult' to type 'Microsoft.AspNetCore.Mvc.ObjectResult'

解决方法

中间件是处理请求和响应日志记录的方法。您可以自定义中间件,并且可以将它们挂接到HTTP管道中,并且可以在中间件实现中执行日志记录。这种方法可帮助您在全球范围内做到这一点。

创建用于拦截请求和响应的中间件

// Request Logging middleware
public class RequestLoggingMiddleware
{
    private RequestDelegate _next;
    public RequestLoggingMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        // Logic to log your request. Can be accessed via "context.Request"
        await _next.Invoke(context);
    }
}
// Response Logging Middleware
public class ResponseLoggingMiddleware
{
    private RequestDelegate _next;
    public ResponseLoggingMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        // observe the Invoke() method being called first
        await _next.Invoke(context)
        // This is where your logging logic goes. For eg.,you can capture 404 as below
        if(context.Response.StatusCode == 404)
        {
            // log the 404 and do whatever you want to do on a 404 here.
        }
    }
}

将中间件连接到HTTP管道

这非常简单,并通过以下代码语句完成。

// Within the Configure() method of Startup.cs
app.UseMiddleware<ResponseLoggingMiddleware>();
app.UseMiddleware<RequestLoggingMiddleware>();

在这里,连接中间件的顺序很重要。有关中间件订购和一般here

中间件的更多信息

更新:

创建自定义属性以处理端点级别的日志记录

public class LoggingAttribute : Attribute,IActionFilter
{
    public void OnActionExecuted(ActionExecutedContext context)
    {
        // This method is called just right after the completion of the 
        // execution of the action method. Status Code can be obtained as shown below
        // response logging based on status code goes here.
        var result = context.Result;
        var response = context.HttpContext.Response.StatusCode;
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
        // This method is called before the action method is invoked.
        // Access the request using context.HttpContext.Request
        // and include the logging logic where
        var request = context.HttpContext.Request;            
    }
}

现在可以将该属性添加到控制器内部的操作方法中,如下所示。

[HttpGet]
[LoggingAttribute]
public ActionResult<IEnumerable<string>> Get()
{
    // ...other code
}