当前位置:网站首页>ASP.NET 6 中间件系列 - 自定义中间件类
ASP.NET 6 中间件系列 - 自定义中间件类
2022-04-23 03:02:00 【dotNET跨平台】
这篇文章是 ASP.NET 6 中间件系列文章的第2部分,点击这里可以阅读第1部分。
在上一篇文章中,我们讨论了什么是中间件,它的作用是什么,以及在 ASP.NET 6 应用管道中添加中间件的简单方法。
在这篇文章中,我们将在这些基础上来扩展构建一些自定义中间件类。
示例项目
在 GitHub 上可以获得这篇文章涉及到的代码:
https://github.com/zilor-net/ASPNET6Middleware/tree/Part2
标准中间件结构
与我们在第1部分中所做的不同,大多数时候我们希望中间件是独立的类,而不是在 Program.cs 文件中创建。
让我们回顾一下第1部分的内容,一个响应“Hello Dear Readers!”内容的中间件?
app.Run(async context =>
{
await context.Response.WriteAsync("Hello Dear Readers!");
});
接下来,让我们创建一个自定义中间件类来实现同样的效果。
中间件类的基础知识
下面是一个空类,我们将用于这个中间件:
namespace ASPNET6Middleware.Middleware
{
public class SimpleResponseMiddleware
{
}
}
中间件类由三部分组成:
首先,任何中间件类都必须拥有RequestDelegate
类型的私有成员实例,该实例由类的构造函数填充。
RequestDelegate
代表管道中的下一个中间件:
namespace ASPNET6Middleware.Middleware
{
private readonly RequestDelegate _next;
public SimpleResponseMiddleware(RequestDelegate next)
{
_next = next;
}
}
其次,这个类必须有一个async方法InvokeAsync()
,它接受一个HttpContext
类型的实例作为它的第一个参数:
public class SimpleResponseMiddleware
{
private readonly RequestDelegate _next;
public SimpleResponseMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
//...Implementation
}
}
第三,中间件必须有自己的实现。对于这个中间件,我们要做的就是返回一个自定义的响应:
public class SimpleResponseMiddleware
{
private readonly RequestDelegate _next;
public SimpleResponseMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
await context.Response.WriteAsync("Hello Dear Readers!");
}
}
注意:在InvokeAsync()
方法中,大多数中间件都会调用await next(context);
,任何不这样做的中间件都会是一个终端中间件,它代表着管道的终结,它之后的中间件都不会执行。
向管道中添加中间件
此时,我们可以使用UseMiddleware<>()
方法,将这个中间件类添加到 Program.cs 文件中的 app 中:
app.UseMiddleware<LayoutMiddleware>();
对于简单的中间件类,这就足够了。
然而,我们更加常用的方式是使用扩展方法,而不是直接使用UseMiddleware<>()
,因为这可以为我们提供一层更加具体的封装:
namespace ASPNET6Middleware.Extensions
{
public static class MiddlewareExtensions
{
public static IApplicationBuilder UseSimpleResponseMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<SimpleResponseMiddleware>();
}
}
}
然后我们可以像这样使用这个扩展方法:
app.UseSimpleResponseMiddleware();
这两种方法都是正确的,但是我个人更喜欢扩展方法的清晰性和可读性。
构建日志中间件
在第1部分时就介绍过,中间件最常见的场景之一是日志记录,特别是记录请求路径或响应头、响应体等内容。
LoggingService 类
我们将构建一个日志中间件类,它只做两件事:
记录请求路径。
记录唯一响应头。
首先,我们必须创建接口ILoggingService
和类LoggingService
。
namespace ASPNET6Middleware.Logging
{
public class LoggingService : ILoggingService
{
public void Log(LogLevel logLevel, string message)
{
// 日志具体实现省略
}
}
public interface ILoggingService
{
public void Log(LogLevel level, string message);
}
}
然后我们需要在 Program.cs 中将LoggingService
添加到应用程序的Services
集合中:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddTransient<ILoggingService, LoggingService>();
中间件类也像普通类一样可以注入服务。
LoggingMiddleware 类
现在我们需要一个LoggingMiddleware
类来做日志。
首先,让我们为LoggingMiddleware
类创建好中间件结构,它在构造函数中接受一个ILoggingService
的实例作为参数:
namespace ASPNET6Middleware.Middleware
{
public class LoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILoggingService _logger;
public LoggingMiddleware(RequestDelegate next, ILoggingService logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
//...
}
}
}
我们的任务是记录请求的路径和响应的唯一头,这意味着在await next(context)
的前后都有代码:
namespace ASPNET6Middleware.Middleware
{
public class LoggingMiddleware
{
//..
public async Task InvokeAsync(HttpContext context)
{
// 记录传入的请求路径
_logger.Log(LogLevel.Information, context.Request.Path);
// 调用管道中的下一个中间件
await _next(context);
// 获得唯一响应头
var uniqueResponseHeaders
= context.Response.Headers
.Select(x => x.Key)
.Distinct();
// 记录响应头名称
_logger.Log(LogLevel.Information, string.Join(", ", uniqueResponseHeaders));
}
}
}
将 LoggingMiddleware 添加到管道中
因为我更喜欢使用扩展方法来添加中间件到管道中,让我们创建一个新的扩展方法:
namespace ASPNET6Middleware.Extensions
{
public static class MiddlewareExtensions
{
//...
public static IApplicationBuilder UseLoggingMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<LoggingMiddleware>();
}
}
}
最后,我们需要在 Program.cs 中调用我们的新扩展方法,将LoggingMiddleware
类添加到管道中:
app.UseLoggingMiddleware();
当我们运行应用程序时,我们可以看到代码(通过断点)可以正确地记录请求路径和响应头。
在本系列的下一篇文章中,我们将讲述中间件的执行顺序,展示一个记录执行时间的新中间件,并讨论在创建中间件管道时可能发生的一些常见问题。
版权声明
本文为[dotNET跨平台]所创,转载请带上原文链接,感谢
https://blog.csdn.net/sd7o95o/article/details/124287008
边栏推荐
- Windows MySQL 8 zip installation
- FileNotFoundError: [Errno 2] No such file or directory
- 【Hcip】OSPF常用的6种LSA详解
- Blazor University (12)组件 — 组件生命周期
- REINFORCE
- Redis Cluster集群,主节点故障,主从切换后ip变化,客户端需要处理不
- tf. keras. layers. Embedding function
- Basic SQL (VIII) data update operation practice
- .Net Core 限流控制-AspNetCoreRateLimit
- Linux redis - redis ha sentinel cluster construction details & redis master-slave deployment
猜你喜欢
tf. keras. layers. Timedistributed function
Linux redis - redis database caching service
微软是如何解决 PC 端程序多开问题的——内部实现
Linux redis - redis ha sentinel cluster construction details & redis master-slave deployment
Configuring Apache Web services for servers such as Tianyi cloud
Slave should be able to synchronize with the master in tests/integration/replication-psync. tcl
Log cutting - build a remote log collection server
Development notes of raspberry pie (12): start Advantech industrial control raspberry pie uno-220 Kit (I): introduction and operation of the system
Windows MySQL 8 zip installation
Shell script learning notes - regular expressions
随机推荐
Guangcheng cloud service can fill in a daily report regularly every day
Codeforces Round #784 (Div. 4) (A - H)题解
Navicat failed to connect to Oracle Database: cannot load OCI DLL, 87: instant client package is
Linux Redis ——Redis HA Sentinel 集群搭建详解 & Redis主从部署
Onenet connection process
tf. keras. layers. Timedistributed function
Windows MySQL 8 zip installation
Service avalanche effect
Thoughts on the 2022 national network security competition of the national secondary vocational group (only one idea for myself) - network security competition questions (10)
Q-Learning & Sarsa
Opencv reads webcam video and saves it locally
AspNetCore配置多环境log4net配置文件
Basic SQL (VIII) data update operation practice
Thoughts on the 2022 national network security competition of the national secondary vocational group (only one idea for myself) - network security competition questions (7)
c#可变参数params的介绍
ASP.NET 6 中间件系列 - 条件中间件
最通俗易懂的依赖注入与控制反转
Er and eer models
Codeforces round 784 (Div. 4) (a - H)
How to write the expected salary on your resume to double your salary during the interview?