.NET Core中间件的注册和管道的构建(1)---- 注册和构建原理
.NET Core中间件的注册和管道的构建(1)---- 注册和构建原理
0x00 问题的产生
管道是.NET Core中非常关键的一个概念,很多重要的组件都以中间件的形式存在,包括权限管理、会话管理、路由等。所以搞明白中间件是如何注册并最终构建成管道的很重要。园子里很多先驱早已经开始了这方面的研究学习,也写了很多文章,不过我看了后有些地方还不是特别明白。毕竟每个人都是不同的,有些内容作者觉得是常识不需要多写的地方对我来说可能就是个盲区。幸好.NET Core整个项目都是开源的,找到源码看了下解决了我心中的困惑。同时写篇博客记录一下,也算一个补充,如果大家看了能有所收获那就更好了。本来是想一片文章写完的,后来发现太长了,所以分了两篇。这是第一篇,主要说一下中间件的注册和管道的构建原理,后面一篇写一下注册中间件类的原理和写中间件类需要注意的约定和特性。
0x01 中间件的注册
管道的构建主要包含中间件注册和把注册的中间件构建成管道。先来说中间件的注册。
什么是中间件。说简单一点中间件就是一个方法,传入一个HttpContext类型参数,返回Task。参数HttpContext中包含了HTTP请求和响应等相关信息,中间件可以读取/修改其中的部分内容,并决定是否让下一个中间件继续处理这个HttpContext。这个方法包装为一个委托RequestDelegate。

为了让中间件有权决定是否让下一个中间件继续处理HttpContext,当前中间件需要下一个中间件的引用。所以在注册中间件的时候需要注册为Func<RequestDelegate,RequestDelegate>的形式,其中传入的参数指的是下一个中间件,返回的是我们注册的中间件,传入的参数在ApplicationBuilder在执行Build()方法构建管道时传入(后面会看到)。所以为了方便理解,不那么严谨的来看,中间件以Func<NextMiddleware,ThisMiddleware>的形式注册并存储在一个列表中。

可以通过ApplicationBuilder的Use方法注册中间件

0x02 管道的构建
管道的构建就是把Func<RequestDelegate,RequestDelegate>列表串在一起。用第一个Func的返回值作为第二个Func的参数,第二个Func的返回值作为第三个Func的参数,依次类推。最终返回最后一个Func返回的RequestDelegate(中间件)。管道工作时最后一个RequestDelegate可以决定是否调用倒数第二个RequestDelegate,倒数第二个RequestDelegate可以决定是否调用倒数第三个RequestDelegate,依次类推直到调用第一个RequestDelegate。这中间有两个问题:
第一个是这样构建管道,中间件的顺序和注册的时候是相反的,所以在构件时首先把列表_components.Reverse()以保证正确的中间件顺序。
第二个问题是构建第一个中间件时没有RequestDelegate可以传入,所以需要构建一个把状态码设置为404的中间件作为最开始的RequestDelegate传入。当然在构建完成后这个中间件是存在于管道最末端的。这样管道构建就算完成了。Build()代码如下:

0x03 测试
构建完成后的管道和中间件如下图:

这是微软官方的图,很多文章中也引用过。从这张图中可以看出来中间件通过调用next()启动下一个中间件。如果中间件不调用next()那么它之后的所有中间件就都不会调用了。除此之外还有一个细节需要注意,就是next()的调用并不是必须要放到最后的。也就是说可以先调用后面的中间件,等后面的中间件调用完成后在执行一些操作(图中的more logic)。
下面来分别进行测试,正常建立一个.NET Core MVC Web项目。
测试1:注释掉Configure()中的所有内容,然后依次注册中间件:

运行后结果为:

这个测试印证了之前代码中看到的中间件的注册顺序就是调用顺序。
测试2:注释掉Middleware1的next调用,其它保持不变。这样Middleware1就不会调用Middleware2,Middleware2以及之后的所有中间件都无法调用。

运行结果变为:

这个测试说明Middleware1不调用next()的话后面的Middleware2和Middleware3都没有被调用。
测试3:把Configure()方法修改如下:

我们在最开始注册一个中间件记录当前时间,然后调用后面所有中间件,最后返回时计算后面所有中间件执行所消耗的时间。为了看上去更明显后面又注册了一个中间件强制睡眠100毫秒。需要注意的是强制睡眠的中间件要注册在MVC之前,因为MVC结束后就直接返回了,不会调用后面的中间件了。
运行结果为:

这个测试说明对下一个中间件的调用不一定非要放到最后,可以先调用后面中间件,等后面所有中间件调用完成后再继续处理。
0x04 写在最后
这篇文章主要讨论了中间件的注册和管道构建的一些原理,实际上对于复杂一点的中间件来说,一般都有更复杂的逻辑并对其它组件依赖。下一篇将讨论把中间件写成一个类并注入依赖的方法和原理。
此外这篇文章主要是我个人的一些理解和直觉。。。好吧真的有些是直觉,能力有限,博客园大牛众多,有错误的地方大家嘴下留情啊。
0x05 相关文章
.NET Core中间件的注册和管道的构建(1)---- 注册和构建原理
.NET Core中间件的注册和管道的构建(2)---- 用UseMiddleware扩展方法注册中间件类
.NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法
.NET Core中间件的注册和管道的构建(1)---- 注册和构建原理的更多相关文章
- .NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法
.NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法 0x00 为什么需要Map(MapWhen)扩展 如果业务逻辑比较简单的话,一条主管道就够了,确实用不到 ...
- .NET Core中间件的注册和管道的构建(2)---- 用UseMiddleware扩展方法注册中间件类
.NET Core中间件的注册和管道的构建(2)---- 用UseMiddleware扩展方法注册中间件类 0x00 为什么要引入扩展方法 有的中间件功能比较简单,有的则比较复杂,并且依赖其它组件.除 ...
- ASP.NET Core 1.0中的管道-中间件模式
ASP.NET Core 1.0借鉴了Katana项目的管道设计(Pipeline).日志记录.用户认证.MVC等模块都以中间件(Middleware)的方式注册在管道中.显而易见这样的设计非常松耦合 ...
- Core 1.0中的管道-中间件模式
ASP.NET Core 1.0中的管道-中间件模式 SP.NET Core 1.0借鉴了Katana项目的管道设计(Pipeline).日志记录.用户认证.MVC等模块都以中间件(Middlewar ...
- ASP.NET Core MVC 2.x 全面教程_ASP.NET Core MVC 03. 服务注册和管道
ASP.NET Core MVC 2.x 全面教程_ASP.NET Core MVC 03. 服务注册和管道 语雀: https://www.yuque.com/yuejiangliu/dotnet/ ...
- .net core 中间件管道底层剖析
.net core 管道(Pipeline)是什么? 由上图可以看出,.net core 管道是请求抵达服务器到响应结果返回的中间的一系列的处理过程,如果我们简化一下成下图来看的话,.net core ...
- net core 中间件管道
net core 中间件管道 .net core 管道(Pipeline)是什么? 由上图可以看出,.net core 管道是请求抵达服务器到响应结果返回的中间的一系列的处理过程,如果我们简化一下成下 ...
- ASP.NET Core 中间件详解及项目实战
前言 在上篇文章主要介绍了DotNetCore项目状况,本篇文章是我们在开发自己的项目中实际使用的,比较贴合实际应用,算是对中间件的一个深入使用了,不是简单的Hello World,如果你觉得本篇文章 ...
- [转]ASP.NET Core 中间件详解及项目实战
本文转自:http://www.cnblogs.com/savorboard/p/5586229.html 前言 在上篇文章主要介绍了DotNetCore项目状况,本篇文章是我们在开发自己的项目中实际 ...
随机推荐
- Apache执行Python脚本
由于经常需要到服务器上执行些命令,有些命令懒得敲,就准备写点脚本直接浏览器调用就好了,比如这样: 因为线上有现成的Apache,就直接放它里面了,当然访问安全要设置,我似乎别的随笔里写了安全问题,这里 ...
- 探索ASP.NET MVC5系列之~~~2.视图篇(上)---包含XSS防御和异步分部视图的处理
其实任何资料里面的任何知识点都无所谓,都是不重要的,重要的是学习方法,自行摸索的过程(不妥之处欢迎指正) 汇总:http://www.cnblogs.com/dunitian/p/4822808.ht ...
- [转]利用URLConnection来发送POST和GET请求
URL的openConnection()方法将返回一个URLConnection对象,该对象表示应用程序和 URL 之间的通信链接.程序可以通过URLConnection实例向该URL发送请求.读取U ...
- WebApi接口 - 响应输出xml和json
格式化数据这东西,主要看需要的运用场景,今天和大家分享的是webapi格式化数据,这里面的例子主要是输出json和xml的格式数据,测试用例很接近实际常用情况:希望大家喜欢,也希望各位多多扫码支持和点 ...
- 手把手教你写一个RN小程序!
时间过得真快,眨眼已经快3年了! 1.我的第一个App 还记得我14年初写的第一个iOS小程序,当时是给别人写的一个单机的相册,也是我开发的第一个完整的app,虽然功能挺少,但是耐不住心中的激动啊,现 ...
- 著名ERP厂商的SSO单点登录解决方案介绍一
SSO英文全称Single Sign On,单点登录.SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统.它包括可以将这次主要的登录映射到其他应用中用于同一个用户 ...
- springmvc SSM shiro redis 后台框架 多数据源 代码生成器
A集成代码生成器 [正反双向(单表.主表.明细表.树形表,开发利器)+快速构建表单 下载地址 ; freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本,处理类 ...
- Android之SAX解析XML
一.SAX解析方法介绍 SAX(Simple API for XML)是一个解析速度快并且占用内存少的XML解析器,非常适合用于Android等移动设备. SAX解析器是一种基于事件的解析器,事件驱动 ...
- Express 教程 01 - 入门教程之经典的Hello World
目录: 前言 一.Express?纳尼?! 二.开始前的准备工作 三.测试安装之经典的Hello World 四.使用express(1)来生成一个应用程序 五.说明 前言: 本篇文章是建立在Node ...
- HTML5 程序设计 - 使用HTML5 Canvas API
请你跟着本篇示例代码实现每个示例,30分钟后,你会高喊:“HTML5 Canvas?!在哥面前,那都不是事儿!” 呵呵.不要被滚动条吓到,很多都是代码和图片.我没有分开写,不过上面给大家提供了目录,方 ...