中间件注册可以除了可以使用Startup之外,还可以选择StartupFilter

中间件的注册除了可以借助Startup对象(DelegateStartup或者ConventionBasedStartup)来完成之外,也可以利用另一个叫做StartupFilter的对象来实现。所谓的StartupFilter是对所有实现了IStartupFilter接口的类型及其对象的统称。IStartupFilter接口定义了如下一个唯一的方法Configure,该方法的参数next返回的Action<IApplicationBuilder>对象体现了后续StartupFilter和Startup对中间件的注册,而自身对中间件的注册则实现在返回的Action<IApplicationBuilder>对象中。[本文已经同步到《ASP.NET Core框架揭秘》之中]

   1: public interface IStartupFilter
   2: {
   3:     Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next);
   4: }

我们可以采用服务注册的方式注册多个StartupFilter。具体来说,StartupFilter具有如下两种不同的注册方式,一种是通过调用WebHostBuilder的ConfigureServices方法以服务的形式注册所需的StartupFilter,另一种则是将针对StartupFilter的服务注册实现在启动类的ConfigureServices方法上。

   1: //注册方式1
   2: new WebHostBuilder()
   3:     .ConfigureServices(svcs => svcs
   4:         .AddSingleton<IStartupFilter, Filter1>()
   5:         .AddSingleton<IStartupFilter, Filter2>())                    
   6:     …
   7:  
   8: //注册方式2
   9: public class Startup
  10: {
  11:     public void ConfigureServices(IServiceCollection svcs)
  12:     {
  13:         svcs.AddSingleton<IStartupFilter,Filter1>()
  14:             .AddSingleton<IStartupFilter, Filter2>();
  15:     }    
  16: }

既然中间件可以同时通过Startup和StartupFilter进行注册,那么通过这两个种方式注册的中间件有何不同吗?其实它们唯一的区别在于StartupFilter注册的中间件会先执行。话句话说,对于由注册中间件构成的管道来说,通过Startup注册的中间件位于通过StartupFilter注册的中间件之后。我们不妨通过一个简单的实例来证实这一点。我们在一个ASP.NET Core控制台应用中定义如下四个中间件类型(Foo、Bar、Baz和Gux),它们针对请求的处理逻辑很简单,就是将自身的类型名称写入请求的响应中。

   1: public abstract class MiddlewareBase
   2: {
   3:     private RequestDelegate _next;
   4:  
   5:     public MiddlewareBase(RequestDelegate next)
   6:     {
   7:         _next = next;
   8:     }
   9:     public async Task Invoke(HttpContext context)
  10:     {
  11:         await context.Response.WriteAsync($"{this.GetType().Name}=>");
  12:         await _next(context);
  13:     }
  14: }
  15:  
  16: public class Foo : MiddlewareBase
  17: {
  18:     public Foo(RequestDelegate next) : base(next){}
  19: }
  20: public class Bar : MiddlewareBase
  21: {
  22:     public Bar(RequestDelegate next) : base(next) {}
  23: }
  24: public class Baz : MiddlewareBase
  25: {
  26:     public Baz(RequestDelegate next) : base(next) {}
  27: }
  28: public class Gux : MiddlewareBase
  29: {
  30:     public Gux(RequestDelegate next) : base(next) {}
  31: }

接下来我们定义了如下一个泛型的 StartupFilter<TMiddleware>类,这是一个专门用于注册指定类型中间件的StartupFilter,泛型参数代表注册的中间件类型。在实现的Configure方法中,我们将中间件的注册实现在返回的Action<IApplicationBuilder>对象中。

   1: public class StartupFilter<TMiddleware> : IStartupFilter
   2: {
   3:     public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
   4:     {
   5:         return app=> {
   6:             app.UseMiddleware<TMiddleware>();
   7:             next(app);
   8:         };
   9:     }
  10: }

我们最终编写如下一段简单的程序来启动承载的应用程序。如下面的额代码片段所示,在利用WebHostBuilder创建并启动WebHost之前,我们调用其ConfigureServices方法注册了两个StartupFilter<TMiddleware>对象,它们对应的中间件类型分别为Foo和Bar。在随后调用的Configure方法中,我们又完成了针对中间Baz和Gux的注册。这段程序实际上注册了五个中间件(调用ApplicationBuilder的Run方法可以视为中间件注册)。

   1: public class Program
   2: {
   3:     public static void Main()
   4:     {
   5:         new WebHostBuilder()
   6:             .UseKestrel()
   7:             .ConfigureServices(svcs => svcs
   8:                 .AddSingleton<IStartupFilter>(new StartupFilter<Foo>())
   9:                 .AddSingleton<IStartupFilter>(new StartupFilter<Bar>()))
  10:             .Configure(app => app
  11:                 .UseMiddleware<Baz>()
  12:                 .UseMiddleware<Gux>()
  13:                 .Run(async context=> await context.Response.WriteAsync("End")))
  14:             .Build()
  15:             .Run();
  16:     }
  17: }

我们现在需要确定注册的这五个在进行请求处理过程中的执行顺序。为此我们直接启动这个程序,然后开启浏览器访问默认的监听地址(http://localhost:5000),浏览器会按照如下图所示形式显示出请求在这个五个中间件中的“路由”。浏览器显示的结果清晰地表明通过StartupFilter注册的中间件比通过Startup注册的中间件先执行。对于两个采用相同方式注册的中间件,先被注册的中间会先执行。

作者:蒋金楠 

中间件注册可以除了可以使用Startup之外,还可以选择StartupFilter的更多相关文章

  1. 学习ASP.NET Core, 怎能不了解请求处理管道[5]: 中间件注册可以除了可以使用Startup之外,还可以选择StartupFilter

    中间件的注册除了可以借助Startup对象(DelegateStartup或者ConventionBasedStartup)来完成之外,也可以利用另一个叫做StartupFilter的对象来实现.所谓 ...

  2. 终于将rsync-3.1.2配置成功,之外还挖掘了一些新的用法

    1.为什么要用rsync: 有两台主机,开始准备做HA,考虑到工作量的问题,最终决定将重要文件进行同步即可. 找了一些同步的工具,rsync得到一致好评,速度快,消耗小等等. 2.接着找资料,最后选用 ...

  3. 除了 Microsoft Office我们还可以选择哪些软件?

    不同的人有不同爱好,不同的人有着不同的人生追求,软件公司也是如此.尽管 Microsoft Office 比之前要便宜得多了,但其按时间累计的完整的安装版本的价格仍然很高,基于对普通用户亦或手头比较紧 ...

  4. ASP.NET Core框架揭秘(持续更新中…)

    之前写了一系列关于.NET Core/ASP.NET Core的文章,但是大都是针对RC版本.到了正式的RTM,很多地方都发生了改变,所以我会将之前发布的文章针对正式版本的.NET Core 1.0进 ...

  5. ASP.NET Core框架揭秘(持续更新中…)

    之前写了一系列关于.NET Core/ASP.NET Core的文章,但是大都是针对RC版本.到了正式的RTM,很多地方都发生了改变,所以我会将之前发布的文章针对正式版本的.NET Core 1.0进 ...

  6. ASP.NET Core 学习笔记 第二篇 依赖注入

    前言 ASP.NET Core 应用在启动过程中会依赖各种组件提供服务,而这些组件会以接口的形式标准化,这些组件这就是我们所说的服务,ASP.NET Core框架建立在一个底层的依赖注入框架之上,它使 ...

  7. lambda匿名函数透析

    lambda匿名函数透析 目录 1       匿名函数的作用... 1 2       匿名函数的格式... 1 3       匿名函数实例代码... 3   1         匿名函数的作用 ...

  8. spring-第二章-AOP

    一,回顾 1.控制反转(IOC) 以前创建对象,由我们自己决定,现在我们把管理对象的声明周期权力交给spring; 2.依赖注入(DI) A对象需要B对象的支持,spring就把B注入给A,那么A就拥 ...

  9. APP打开(三)—激活率提升20%的思考

    激活是APP拉新后的一个重要环节.通常,我们希望用户打开我们的APP之后,能够顺利的被激活,从而留下来成为我们的忠实用户. 激活一词,就跟北斗星指标一样,对每个产品来说都是不一样的.有些APP一旦打开 ...

随机推荐

  1. swoole+nginx反向代理

    nginx配置: server { listen 80; server_name www.swoole.com; root /data/wwwroot/www.swoole.com; location ...

  2. Ajax处理后台返回的Json数据

    // 处理后台传来的Json字符串装换成Json对象 var dataJson = JSON.parse(data); // 此时可以从Json对象中取值 if(dataJson.result == ...

  3. mysql之count

    两种引擎对count的处理 CREATE TABLE `test` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` char(15) D ...

  4. HihoCoder1643 : 最少换乘([Offer收割]编程练习赛37)(bfs)

    描述 小Ho居住的城市有N条公交车线路,其中第i条线路上有Ki个车站. 某些线路之间会有公共的车站,小Ho可以在这些车站从一条线路换乘到另一条线路. 现在给定N条公交车线路以及两个车站S和E,你能帮助 ...

  5. ubuntu关闭cups服务

    本人使用的ubuntu10.10每次开机时使用nmap扫描127.0.0.1的时候总是能发现一个631端口开启,在/etc/services找到 631端口是网络打印机服务,但对于我一个普通用户来说这 ...

  6. poj 1269 Intersecting Lines——叉积求直线交点坐标

    题目:http://poj.org/problem?id=1269 相关知识: 叉积求面积:https://www.cnblogs.com/xiexinxinlove/p/3708147.html什么 ...

  7. SQL SERVER 判断是否存在数据库、表、列、视图

    SQL SERVER 判断是否存在数据库.表.列.视图 --1. 判断数据库是否存在 IF EXISTS (SELECT * FROM SYS.DATABASES WHERE NAME = '数据库名 ...

  8. Jenkins安装配置简单使用

    安装启动是十分简单的,直接去https://jenkins.io/download/下载对应的rpm包就好了,需要注意的是我们的机器上要提前有java环境,相对应要选择你java环境可以支持的jenk ...

  9. matlab在处理图像时为什么把数据转换为double型?

    1 有些函数支持double型,而不支持uint8的数据类型,所以要转换 2 精度问题了,因为uint8进行数据处理的时候,容易造成数据溢出或精度不够. 为了节省存储空间,matlab为图像提供了特殊 ...

  10. ContOS 小细节

    rm [filename] 这个filenam 中间如果有()那么就必须用/转义,如 demo_(2).txt 必须写为 demo_\(2\).txt 上传 rz下载 sz + 文件名退出 exit解 ...