阅读本文你的收获:
- 学习如何自定义中间件
- 学会封装一个日志记录中间件
本文主要分享的是如何自定义中间件,如果想要了解中间件的基本概念,请看ASP.NET Core基础之中间件(一)
一、场景描述
内置的中间件可以对请求和响应进行一些处理,但是无法知道请求花了多少时间,当发生异常时也无法把错误信息进行捕获并记录到日志文件文件中。当内置中间件无法满足我们的需求时,就需要自己动手DIY一个自定义中间件了。
为了满足以上的需求,我们一起来自定义一个请求日志中间件,它有以下的功能:
- 可以记录请求的处理所消耗的时间
- 当请求发生异常的时候,可以捕获并记录到日志里面
二、实现请求日志中间件
编写自定义中间件的流程
以下一步步带你来实现自定义中间件,开发环境:
- 平台版本是:.NET6
- 开发框架:ASP.NET Core WebApi
- 开发工具:Visual Studio2022
1. 定义请求日志中间件类
注意点
(1) 出于规范性考虑,自定义中间件类的名称以Middleware结尾,如RequestLogMiddleware是我定义的请求日志中间件类。
(2) 写一个中间件类,该类必须满足以下要求:
- 类的公共构造函数至少有一个 RequestDelegate 类型的参数,其它的参数根据情况自行决定要不要加
- 类中必须有一个名为Invoke或InvokeAsync的公共方法,此方法的第一个参数必须是 HttpContext 类型,该方法返回类型为Task
using Microsoft.AspNetCore.Http; //
using Microsoft.Extensions.Logging; //日志记录
using System.Diagnostics; //秒表
/// <summary>
/// 请求日志中间件(无需继承任何基类)
/// </summary>
public class RequestLogMiddleware
{
//下一个请求委托
private readonly RequestDelegate _next;
//通过构造函数完成日志工具对象的注入
private readonly ILogger<RequestLogMiddleware> _logger;
/// <summary>
/// 构造方法
/// </summary>
/// <param name="next">请求委托</param>
/// <param name="logger">日志工具对象</param>
/// <returns></returns>
public RequestLogMiddleware(RequestDelegate next, ILogger<RequestLogMiddleware> logger)
{
_next = next;
_logger = logger;
}
/// <summary>
/// 公开方法
/// </summary>
/// <param name="context">Http请求上下文</param>
/// <returns></returns>
public async Task InvokeAsync(HttpContext context)
{
string requestUrl = context.Request.Path;
try
{
//实例化一个秒表对象,用于记录执行前后的时间
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
await _next(context); //继续调用下一个请求委托
stopwatch.Stop();
_logger.LogInformation($"请求{requestUrl},消耗了{stopwatch.ElapsedMilliseconds}毫秒");
}
catch (Exception ex)
{
//异常日志记录到文件
_logger.LogError($"请求异常:{requestUrl},错误信息:{ex.Message}");
}
}
}
代码说明:
- 可以看到在代码中
await _next(context);
的前后加了秒表计时的功能,这样我们就能知道请求耗时了。 - 另外用try…catch进行异常捕获,这样当请求处理发生异常时,就可以将错误信息记录到日志中。
- 本代码中记录的日志信息较为简单是输出到 控制台界面,如果要记录到文件中,还需要结合NLog、Log4Net这样的日志组件。
2. 封装扩展方法
写一个扩展方法 将以上中间件公开给使用者:
using Microsoft.AspNetCore.Builder; //IApplicationBuilder所在的命名空间
/// <summary>
/// 以下扩展方法,将以上中间件公开给使用者
/// </summary>
public static class RequestLogMiddlewareExt
{
public static IApplicationBuilder UseRequestLogMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestLogMiddleware>();
}
}
3. 在中间件管道中,使用RequestLog中间件
三、测试自定义中间件
在Swagger中的请求某个api,可以在控制台窗口中,看到请求的耗时信息。
总结
当内置的中间件无法满足你需求的时候,我们可以按照以上的流程来自定义中间件,实现对请求或响应的特殊处理场景,如记录日志的中间件、处理异常的中间件、防止SQL注入的中间件等。需要重申的是,中间件类,必须满足以下条件:
- 类的公共构造函数至少有一个 RequestDelegate 类型的参数,其它的参数根据情况自行决定要不要加
- 类中必须有一个名为Invoke或InvokeAsync的公共方法,此方法的第一个参数必须是 HttpContext 类型,该方法返回类型为Task
本次分享就这么多,希望对你有帮助。关于如何记录更详细的日志信息,我将在后期的博文中分享,欢迎评论+关注。