中间件的注册除了可以借助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注册的中间件先执行。对于两个采用相同方式注册的中间件,先被注册的中间会先执行。

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

  1. 学习ASP.NET Core,怎能不了解请求处理管道[1]: 中间件究竟是个什么东西?

    ASP.NET Core管道虽然在结构组成上显得非常简单,但是在具体实现上却涉及到太多的对象,所以我们在 "通过重建Hosting系统理解HTTP请求在ASP.NET Core管道中的处理流 ...

  2. 学习ASP.NET Core, 怎能不了解请求处理管道[6]: 管道是如何随着WebHost的开启被构建出来的?

    注册的服务器和中间件共同构成了ASP.NET Core用于处理请求的管道, 这样一个管道是在我们启动作为应用宿主的WebHost时构建出来的.要深刻了解这个管道是如何被构建出来的,我们就必须对WebH ...

  3. 学习ASP.NET Core, 怎能不了解请求处理管道[4]: 应用的入口——Startup

    一个ASP.NET Core应用被启动之后就具有了针对请求的处理能力,而这个能力是由管道赋予的,所以应用的启动同时意味着管道的成功构建.由于管道是由注册的服务器和若干中间件构成的,所以应用启动过程中一 ...

  4. 学习ASP.NET Core, 怎能不了解请求处理管道[3]: 自定义一个服务器感受一下管道是如何监听、接收和响应请求的

    我们在<服务器在管道中的"龙头"地位>中对ASP.NET Core默认提供的具有跨平台能力的KestrelServer进行了介绍,为了让读者朋友们对管道中的服务器具有更 ...

  5. 学习ASP.NET Core,怎能不了解请求处理管道[2]: 服务器在管道中的“龙头”地位

    ASP.NET Core管道由注册的服务器和一系列中间件构成.我们在上一篇中深入剖析了中间件,现在我们来了解一下服务器.服务器是ASP .NET Core管道的第一个节点,它负责完整请求的监听和接收, ...

  6. ASP.NET Core 6框架揭秘实例演示[24]:中间件的多种定义方式

    ASP.NET Core的请求处理管道由一个服务器和一组中间件组成,位于 "龙头" 的服务器负责请求的监听.接收.分发和最终的响应,针对请求的处理由后续的中间件来完成.中间件最终体 ...

  7. 学习ASP.NET Core,你必须了解无处不在的“依赖注入”

    ASP.NET Core的核心是通过一个Server和若干注册的Middleware构成的管道,不论是管道自身的构建,还是Server和Middleware自身的实现,以及构建在这个管道的应用,都需要 ...

  8. 学习ASP.NET Core Razor 编程系列二——添加一个实体

    在Razor页面应用程序中添加一个实体 在本篇文章中,学习添加用于管理数据库中的书籍的实体类.通过实体框架(EF Core)使用这些类来处理数据库.EF Core是一个对象关系映射(ORM)框架,它简 ...

  9. 学习ASP.NET Core Razor 编程系列四——Asp.Net Core Razor列表模板页面

    学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...

随机推荐

  1. ExtJS 4.2 Grid组件的单元格合并

    ExtJS 4.2 Grid组件本身并没有提供单元格合并功能,需要自己实现这个功能. 目录 1. 原理 2. 多列合并 3. 代码与在线演示 1. 原理 1.1 HTML代码分析 首先创建一个Grid ...

  2. System.FormatException: GUID 应包含带 4 个短划线的 32 位数(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)。

    在NHibernate数据库查询中出现了这个错误,由于是数据库是mysql的,当定义的字段为char(36)的时候就会出现这个错误. [解决方法] 将char(36) 改成varchar(40)就行了 ...

  3. Coroutine in Java - Quasar Fiber实现--转载

    转自 https://segmentfault.com/a/1190000006079389?from=groupmessage&isappinstalled=0 简介 说到协程(Corout ...

  4. js学习之类型识别

    用来判别类型的方法有好多,整理了一下4种方法,平时用的时候,在不同情景下,还是要结合着使用的. 方法一 typeof:可以识别标准类型,除了Null:不能识别具体的对象类型,除了Function &l ...

  5. css常用hack

    原文地址:css常用hack 突然想起今天早上在CNZZ看到的统计数据,使用IE6.7的用户比例还真多,看到之后我的心都碎了.微软都放弃了为毛还有这么多人不死心? 所以说,IE下的兼容还是得做的. – ...

  6. [算法]——快速排序(Quick Sort)

    顾名思义,快速排序(quick sort)速度十分快,时间复杂度为O(nlogn).虽然从此角度讲,也有很多排序算法如归并排序.堆排序甚至希尔排序等,都能达到如此快速,但是快速排序使用更加广泛,以至于 ...

  7. [转载]网站地址栏小图标favicon.ico的制作方法

    有人也许会好奇,有的网址前面有个漂亮的小图标而且有的网站图标还会动,这是怎么做到的呢? 如下图所示: 那个小图标有个名字叫favicon.ico,网站图标虽小但可以起到很好的点缀作用,尤其是当浏览者将 ...

  8. ABAP单元测试最佳实践

    本文包含了我在开发项目中经历过的实用的ABAP单元测试指导方针.我把它们安排成为问答的风格,欢迎任何人添加更多的Q&A's,以完成这个列表. 在我的项目中,只使用传统的ABAP report. ...

  9. React Native环境配置之Windows版本搭建

    接近年底了,回想这一年都做了啥,学习了啥,然后突然发现,这一年买了不少书,看是看了,就没有完整看完的.悲催. 然后,最近项目也不是很紧了,所以抽空学习了H5.自学啃书还是很无趣的,虽然Head Fir ...

  10. MSSQL 事务,视图,索引,存储过程,触发器

    事务 事务是一种机制.是一种操作序列,它包含了一组数据库操作命令,这组命令要么全部执行,要么全部不执行. 在数据库系统上执行并发操作时事务是作为最小的控制单元来使用的.这特别适用于多用户同时操作的数据 ...