.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. 关于Unity3D自定义编辑器的学习

    被人物编辑器折腾了一个月,最终还是交了点成品上去(还要很多优化都还么做).  刚接手这项工作时觉得没概念,没想法,不知道.后来就去看<<Unity5.X从入门到精通>>中有关于 ...

  2. 加深一下BlockingQueue的认识

    认识BlockingQueue BlockingQueue是一种可以阻塞线程的队列,java中对这种队列提供了方法抽象,BlockingQueue则是抽象的接口. add:添加元素到队列里,添加成功返 ...

  3. Hyper-V2:向VM增加虚拟硬盘

    使用Hyper-V创建VM,在VM成功安装OS之后,发现VM只有一个逻辑盘C,用于存储VM的操作系统.在产品环境中,需要向VM增加虚拟硬盘,便于将数据单独存储在不同的逻辑盘符中.在Hyper-V中,分 ...

  4. 《Django By Example》第一章 中文 翻译 (个人学习,渣翻)

    书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:本人目前在杭州某家互联网公司工作, ...

  5. ASP.NET MVC5+EF6+EasyUI 后台管理系统(72)-微信公众平台开发-消息处理

    系列目录 前言 Senparc.Weixin.MP SDK提供了MessageHandler消息处理类 在作者的Wiki中也详细说明了如何定义这个类,下面我们来演示,消息的回复,及效果 了解Messa ...

  6. 从netty-example分析Netty组件续

    上文我们从netty-example的Discard服务器端示例分析了netty的组件,今天我们从另一个简单的示例Echo客户端分析一下上个示例中没有出现的netty组件. 1. 服务端的连接处理,读 ...

  7. C++常见笔试面试要点以及常见问题

    1. C++常见笔试面试要点: C++语言相关: (1) 虚函数(多态)的内部实现 (2) 智能指针用过哪些?shared_ptr和unique_ptr用的时候需要注意什么?shared_ptr的实现 ...

  8. AEAI DP V3.7.0 发布,开源综合应用开发平台

    1  升级说明 AEAI DP 3.7版本是AEAI DP一个里程碑版本,基于JDK1.7开发,在本版本中新增支持Rest服务开发机制(默认支持WebService服务开发机制),且支持WS服务.RS ...

  9. C语言可以开发哪些项目?

    C语言是我们大多数人的编程入门语言,对其也再熟悉不过了,不过很多初学者在学习的过程中难免会出现迷茫,比如:不知道C语言可以开发哪些项目,可以应用在哪些实际的开发中--,这些迷茫也导致了我们在学习的过程 ...

  10. GIT笔记命令行(1)

    Git简单易用,只要输入git就可以列出他的所有参数 C:\Users\spu>git usage: git [--version] [--help] [-C <path>] [-c ...