- 持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第12天,点击查看活动详情
前言
中间件是一种装配到应用管道以处理请求和响应的软件
- 选择是否将请求传递到管道中的下一个组件。
- 可在管道中的下一个组件前后执行工作。
也可以理解中间件就是在应用程序管道中的一个组件,用来拦截请求过程进行一些其他处理和响应,与过滤器相同点在于他们都是一种面向切面编程的思想。
使用中间件
中间件管道是由
WebApplication创建,请求管道包含一系列请求委托,依次调用。
使用 Run Map 和 Use 扩展方法来配置请求委托
⚠️应尽早在管道中调用异常处理委托,这样它们就能捕获在管道的后期阶段发生的异常。
通俗来说这就是俄罗斯套娃,我们可以用代码来验证这一逻辑。
// 这里就不做太多赘述,之前解读源码的时候有讲过
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// 将中间件委托添加到应用程序的请求管道。
// 中间件一
app.Use(async (context, next) =>
{
Console.WriteLine("中间件一 ----- Start");
await next.Invoke();
Console.WriteLine("中间件一 ----- End");
});
// 中间件二
app.Use(async (context, next) =>
{
Console.WriteLine("中间件二 ----- Start");
await next.Invoke();
Console.WriteLine("中间件二 ----- End");
});
// 中间件三
app.Use(async (context, next) =>
{
Console.WriteLine("中间件三 ----- Start");
await next.Invoke();
Console.WriteLine("中间件三 ----- End");
});
app.Run();// 管道短路
- 在实际应用中并不推荐直接在 Program 类中直接定义使用中间件,可以通过定义扩展方法实现。
// 定义扩展方法
public static class DemoAppBuilderExtensions
{
// 定义中间件
public static void UseMiddlewareOne(this IApplicationBuilder app)
{
// 中间件一
app.Use(async (context, next) =>
{
Console.WriteLine("中间件一 ----- Start");
await next.Invoke();
Console.WriteLine("中间件一 ----- End");
});
}
....
....
....
}
// 使用
var app = builder.Build();
app.UseMiddlewareOne();
app.UseMiddlewareTwo();
app.UseMiddlewareThree();
中间件的执行顺序
微软的官方文档对 ASP.NET Core MVC 和 Razor Pages 应用的完整请求处理管道画了一个图,也可以完全控制如何重新排列现有中间件,或根据场景需要注入新的自定义中间件。
对中间件管道进行分支
MapExtensions 扩展方法用于给定请求路径的匹配来分支请求管道。在我们一些简单项目中通常就一个主管道即可满足,而分支管道即在某些特殊场景下使用 Map/MapWhen 建立一个分支管道,当条件符合我们的设定时,由这个分支管道来处理。
- Map 根据给定请求路径的匹配项对请求管道进行分支。 如果请求路径以给定路径开头,则执行分支。
// 添加管道分支,当路径/map 执行MapTest
app.Map("/map", MapTest);// 也支持同时匹配多个段 如/map/test
app.Run(async context =>
{
await context.Response.WriteAsync("Hello from non-Map delegate. <p>");
});
app.Run();
static void MapTest(IApplicationBuilder app)
{
app.Run(async context =>
{
await context.Response.WriteAsync("Hello Map 1");
});
}
- MapWhen 基于给定谓词的结果创建请求管道分支
// 谓词用于检测查询请求Method 是否为GET
app.MapWhen(context => context.Request.Method.Contains("GET"), MapTest);
- UseWhen 也基于给定谓词的结果创建请求管道分支。 与 MapWhen 不同的是,如果这个分支不发生短路或包含终端中间件,则会重新加入主管道,而 MapWhen 则会替换主管道。
// 基于给定谓词的结果创建请求管道分支,该分支会加入到主管道
app.UseWhen(context => true,appBuilder => MapTest(appBuilder));
总结
每个中间件组件由一个请求委托组成,这是 .NET 中的一种特定对象,它可以将执行控制传递给下一个对象。中间件是组成管道的代码模块或类,处理传入的请求和传出的响应,在ASP.NET Core中也是非常重要的基础之一,学好基础以后写自定义中间件也是顺手捏来。