.net 中间件的使用 Use,Run,Map,MapWhen,UseWhen
.net 提供了几种添加自定义中间件的方法Use,Run,Map,MapWhen,UseWhen
Use
app.Use(async (context, next) =>
{
Console.WriteLine("use1");
await next.Invoke();
Console.WriteLine("use2");
});
Use方法最明显的特征是
传入的委托中含有一个委托参数,我们一般用next来接收这个委托参数,通过调用next.Invode()方法来调用下一个中间件,这样Use之后的中间件才能够被执行
Run
app.Run(context =>
{
Console.WriteLine("run");
return Task.FromResult("done");
});
Run方法区别于Use方法的最明显差异是
Run相当于一个终结点,Run之后的中间件不会被执行,因为它不像Use一样可以调用next.Invoke();
Map
app.Map("/map", app =>
{
app.Run(context =>
{
Console.WriteLine("run");
return Task.FromResult("run done");
});
});
Map中间件最明显的特征是只有访问特定的路径才会执行
MapWhen
app.MapWhen(context => true, app =>
{
app.Use(async (context, next) =>
{
Console.WriteLine("use1");
await next.Invoke();
Console.WriteLine("use2");
});
});
MapWhen,当条件成立时,中间件才会被执行,并且MapWhen创建了一个新的管道,当满足条件时,新的管道会代替主管道,这意味着主管道的中间件不会被执行
UseWhen
app.UseWhen(context => true, app =>
{
app.Use(async (context, next) =>
{
Console.WriteLine("use1");
await next.Invoke();
Console.WriteLine("use2");
});
});
UseWhen和MapWhen类似,也是当条件成立时,中间件才会被执行,区别是UseWhen不会代替主管道
为了更好地说明UseWhen和MapWhen的差异,我们来做一个测试
在Startup的Configure方法最顶部分别用MapWhen、RunWhen自定义两个中间件
app.MapWhen(context => true, app =>
{
app.Use(async (context, next) =>
{
Console.WriteLine("use1");
await next.Invoke();
Console.WriteLine("use2");
});
});
//app.UseWhen(context => true, app =>
//{
// app.Use(async (context, next) =>
// {
// Console.WriteLine("use1");
// await next.Invoke();
// Console.WriteLine("use2");
// });
//});
不要采用IIS运行,采用控制台运行,以便能在控制台看见输出信息
注释UseWhen,运行
出现404,这是因为主管道被新的管道替代了,导致主管道的其它中间件没有被执行
再观察控制台,出现输出信息,说明我们定义的中间件正常执行了
再把UseWhen注释取消,把MapWhen注释掉,运行
正常出现Swagger页面,说明主管道没有被替换
控制台出现两次输出
咦?我们疑惑的发现UseWhen的中间件被执行了两次,而MapWhen的中间件只执行了一次
这是为什么呢?我也不是很清楚。
不过经过我的测试,我猜想UseWhen之所以调用了两次是因为在启动程序创建服务器时会判断一次UseWhen中的条件,结果为true则调用一次中间件,访问页面时又调用了一次,因此出现两次输出
而MapWhen在启动程序创建服务器时不会进行调用,只在访问时调用
使用扩展方法创建中间件
我们之前都是使用Use,Run,Map,MapWhen,UseWhen方法来自定义中间件,但是看一看创建项目时自动生成的代码,发现他们引入中间件都是以app.UseXXX的形式来引入的,感觉很高级的样子。
我们能不能也使用类似的方式来引入我们自己的中间件呢?这就需要用到扩展方法
具体步骤为:
新建一个静态类,之后编写一些静态方法,使用 this IApplicationBuilder app 来扩展app的方法,然后在方法内部定义中间件
public static class MyMiddleware
{
public static void UseMyMiddleware(this IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
Console.WriteLine("1");
await next.Invoke();
Console.WriteLine("2");
});
}
}
之后只要在Startup中引入我们自定义类的相关命名空间就可以使用我们的扩展方法了
例如:
app.UseMyMiddleware();