.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)---- 注册和构建原理的更多相关文章

  1. .NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法

    .NET Core中间件的注册和管道的构建(3) ---- 使用Map/MapWhen扩展方法 0x00 为什么需要Map(MapWhen)扩展 如果业务逻辑比较简单的话,一条主管道就够了,确实用不到 ...

  2. .NET Core中间件的注册和管道的构建(2)---- 用UseMiddleware扩展方法注册中间件类

    .NET Core中间件的注册和管道的构建(2)---- 用UseMiddleware扩展方法注册中间件类 0x00 为什么要引入扩展方法 有的中间件功能比较简单,有的则比较复杂,并且依赖其它组件.除 ...

  3. ASP.NET Core 1.0中的管道-中间件模式

    ASP.NET Core 1.0借鉴了Katana项目的管道设计(Pipeline).日志记录.用户认证.MVC等模块都以中间件(Middleware)的方式注册在管道中.显而易见这样的设计非常松耦合 ...

  4. Core 1.0中的管道-中间件模式

    ASP.NET Core 1.0中的管道-中间件模式 SP.NET Core 1.0借鉴了Katana项目的管道设计(Pipeline).日志记录.用户认证.MVC等模块都以中间件(Middlewar ...

  5. 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/ ...

  6. .net core 中间件管道底层剖析

    .net core 管道(Pipeline)是什么? 由上图可以看出,.net core 管道是请求抵达服务器到响应结果返回的中间的一系列的处理过程,如果我们简化一下成下图来看的话,.net core ...

  7. net core 中间件管道

    net core 中间件管道 .net core 管道(Pipeline)是什么? 由上图可以看出,.net core 管道是请求抵达服务器到响应结果返回的中间的一系列的处理过程,如果我们简化一下成下 ...

  8. ASP.NET Core 中间件详解及项目实战

    前言 在上篇文章主要介绍了DotNetCore项目状况,本篇文章是我们在开发自己的项目中实际使用的,比较贴合实际应用,算是对中间件的一个深入使用了,不是简单的Hello World,如果你觉得本篇文章 ...

  9. [转]ASP.NET Core 中间件详解及项目实战

    本文转自:http://www.cnblogs.com/savorboard/p/5586229.html 前言 在上篇文章主要介绍了DotNetCore项目状况,本篇文章是我们在开发自己的项目中实际 ...

随机推荐

  1. webp图片实践之路

    最近,我们在项目中实践了webp图片,并且抽离出了工具模块,整合到了项目的基础模板中.传闻IOS10也将要支持webp,那么使用webp带来的性能提升将更加明显.估计在不久的将来,webp会成为标配. ...

  2. 【疯狂造轮子-iOS】JSON转Model系列之一

    [疯狂造轮子-iOS]JSON转Model系列之一 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 之前一直看别人的源码,虽然对自己提升比较大,但毕竟不是自己写的,很容易遗 ...

  3. JS调用Android、Ios原生控件

    在上一篇博客中已经和大家聊了,关于JS与Android.Ios原生控件之间相互通信的详细代码实现,今天我们一起聊一下JS调用Android.Ios通信的相同点和不同点,以便帮助我们在进行混合式开发时, ...

  4. 一起来玩echarts系列(一)------箱线图的分析与绘制

    一.箱线图 Box-plot 箱线图一般被用作显示数据分散情况.具体是计算一组数据的中位数.25%分位数.75%分位数.上边界.下边界,来将数据从大到小排列,直观展示数据整体的分布情况. 大部分正常数 ...

  5. ASP.NET Aries 入门开发教程3:开发一个列表页面及操控查询区

    前言: Aries框架毕竟是开发框架,所以重点还是要写代码的,这样开发人员才不会失业,哈. 步骤1:新建html 建一个Html,主要有三步: 1:引入Aries.Loader.js 2:弄一个tab ...

  6. 多个Img标签之间的间隙处理方法

    1.多个标签写在一行 <img src="/i/eg_tulip.jpg" alt="郁金香" height="100px"/> ...

  7. 重撸JS_1

    1.声明 用 var 或 let 声明的未赋初值的变量,值会被设定为undefined(译注:即未定义值,本身也是一个值) 试图访问一个未初始化的变量会导致一个 ReferenceError 异常被抛 ...

  8. js学习之类型识别

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

  9. WPF CheckBox 样式

    <Style x:Key="FocusVisual"> <Setter Property="Control.Template"> < ...

  10. 【架构设计】分布式文件系统 FastDFS的原理和安装使用

    本文地址 分享提纲: 1.概述 2. 原理 3. 安装 4. 使用 5. 参考文档 1. 概述 1.1)[常见文件系统] Google了一下,流行的开源分布式文件系统有很多,介绍如下:   -- mo ...