问题描述
我有一个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
}