在.Net Core的源码中,很多地方都有中间件的地方,Kestrel Server和Asp.net Core 等都用了中间件的设计,比如在Kestrel Server中,Http协议的1.0, 1.1, 2.0分别注册了不同的中间件从而导致不同方式的解析报文,这些要求了我们如何设计一个优雅的中间件框架,在MSDN 上这样描述了asp.net core的 中间件,每个中间件都应该

  • Chooses whether to pass the request to the next component in the pipeline.(选择是否将请求传递到管道中的下一个组件)
  • Can perform work before and after the next component in the pipeline.(可在管道中的下一个组件前后执行工作)

这无疑给了中间件的设计难度,在经典模型里,asp.net还是停留在管道模型里,定义了十几个event,分别执行在不同的时间节点,然后在不同的module里会注册自己的行为到事件上,在当时的观念来看,这是一个非常好的代码设计,面向切面编程,不同的module分工明细降低耦合性,但是随之而来带来的是臃肿全家桶设计,在当前的微服务年代,我们需要动态的添加这些设计,比如认证授权session module。

而现在的asp.net core 的中间件设计非常的好,可以拿到下一个中间件的控制权,并且在下一个中间件之前或者结束做其他的工作。如果不熟悉中间件的同学可以看看 msdn 的描述,这里我们来根据源码自己实现一个优雅的中间件。

首先我们要达成的效果是这样的

public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
// Do work that doesn't write to the Response.
await next.Invoke();
// Do logging or other work that doesn't write to the Response.
}); app.Run(async context =>
{
await context.Response.WriteAsync("Hello from 2nd delegate.");
});
}
}

中间件的执行顺序是这样的

从上面的用法可以看到,我们需要定义一个IApplicationBuilder,然后用use去注册中间件到applicationbuild 对象,所以我们定义一个IApplicationBuilder

 public interface IApplicationBuilder {

        IApplicationBuilder Use(Func<HttpContext, Func<Task>, Task> middleware);//注册中间件

        IApplicationBuilder Build();//生成委托链

        IApplicationBuilder Run();//调用委托链

    }

Use的接口设计,是为了我们上面实现的效果,传入一个方法指针(委托,后略),这个指针需要两个参数,一个HttpContext,一个是下一个管道的方法指针,返回一个task对象, 现在为了让我们的代码跑起来,再定义一个HttpContext对象如下。

 public class HttpContext {

    }

现在让我们去实现一个这个接口

   public delegate Task RequestDelegate(HttpContext httpContext);

  class DefaultApplicationBuilder : IApplicationBuilder { public static List<Func<RequestDelegate, RequestDelegate>> _components = new ();
public IApplicationBuilder Use(Func<HttpContext,Func<Task>,Task> middleware) { Func<RequestDelegate, RequestDelegate> component = next => {
return context => {
Func<Task> task = () => next(context);
return middleware(context,task);
};
}; _components.Add(component); return this;
}
}

现在我们分析Use的实现,首先我们定义了一个方法指针RequestDelegate,这个没啥说的,而这个的设计妙处在DefaultApplicationBuilder中维护了一个 _components对象,是一个集合对象,定义了“二级”方法指针对象,这里的二级指的是Func<Func<T>>对象,得到一个“一级”方法指针处理后返回另一个“一级”方法指针。现在我们看一下这个Use方法的实现,一个中间件middleware就相当于一个方法指针,这时候它定义了一个component,获取一个方法指针,然后返回一个方法指针,注意在返回的方法指针里,它将之前传入的方法指针重新包装了一下得到task对象,这个相当于二级的指针,然后传给中间件。这个地方有点绕。大家需要多看一下理解其中的含义。

然后我们再实现一下build 和run 方法如下。

 public IApplicationBuilder Build() {

            RequestDelegate app = context => Task.CompletedTask;

            _components.Reverse();

            foreach (var component in _components) {

                app = component(app);
} requestDelegate = app; return this;
} public IApplicationBuilder Run() { var context = new HttpContext(); requestDelegate(context); return this;
}

简单说一下build方法,这里的设计之妙就在于将“二级”指针转发成“一级”指针并生成一个委托链,其中的next参数装的就是一系列的委托链。返回的就是第一个注册的中间件。现在我们使用一下这个中间件吧。

 static void Main(string[] args) {

            IApplicationBuilder applicationBuilder = new DefaultApplicationBuilder();

            applicationBuilder.Use(async (context, next) => {
Console.WriteLine(1);
await next.Invoke();
Console.WriteLine(2); }); applicationBuilder.Use(async (context, next) => {
Console.WriteLine(3);
await next.Invoke();
Console.WriteLine(4);
}); applicationBuilder.Use(async (context, next) => {
Console.WriteLine(5);
await next.Invoke();
Console.WriteLine(6);
}); applicationBuilder
.Build()
.Run(); Console.WriteLine("Hello World!");
}

返回结果就是如下,就是msdn文档所说的调用逻辑。

1
3
5
6
4
2
Hello World!

这一块理解起来比较难,设计了这中间件这一块的人很厉害,已经将代码上传到github 上了,大家有兴趣可以对比代码来研究分析。如果有任何问题欢迎大家留言。谢谢大家的阅读

.Net Core如何优雅的实现中间件的更多相关文章

  1. Asp.Net Core 第06局:中间件

    总目录 前言 本文介绍Asp.Net Core 中间件. 环境 1.Visual Studio 2017 2.Asp.Net Core 2.2 开局 第一手:中间件概述     1.中间件:添加到应用 ...

  2. .Net Core Web Api实践之中间件的使用(一)

    前言:从2019年年中入坑.net core已半年有余,总体上来说虽然感觉坑多,但是用起来还是比较香的.本来我是不怎么喜欢写这类实践分享或填坑记录的博客的,因为初步实践坑多,文章肯定也会有各种错误,跟 ...

  3. ASP.NET Core 中的那些认证中间件及一些重要知识点

    前言 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系列(一,二,三)奠定一下基础. 有关于 Authentication 的知识太广,所以本篇介绍几个在 A ...

  4. [转]ASP.NET Core 中的那些认证中间件及一些重要知识点

    本文转自:http://www.qingruanit.net/c_all/article_6645.html 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系 ...

  5. asp.net core 教程(六)-中间件

    Asp.Net Core-中间件 在这一章,我们将了解如何设置中间件.中间件技术在 ASP.NET Core中控制我们的应用程序如何响应 HTTP 请求.它还可以控制应用程序的异常错误,这是一个在如何 ...

  6. Asp .Net core 2 学习笔记(2) —— 中间件

    这个系列的初衷是便于自己总结与回顾,把笔记本上面的东西转移到这里,态度不由得谨慎许多,下面是我参考的资源: ASP.NET Core 中文文档目录 官方文档 记在这里的东西我会不断的完善丰满,对于文章 ...

  7. 将参数传递给ASP.NET Core 2.0中的中间件

    问题 在ASP.NET Core的安装过程中,如何将参数传递给中间件? 解 在一个空的项目中添加一个POCO类来保存中间件的参数, publicclass GreetingOptions { publ ...

  8. 在ASP.NET Core中编写合格的中间件

    这篇文章探讨了让不同的请求去使用不同的中间件,那么我们应该如何配置ASP.NET Core中间件?其实中间件只是在ASP.NET Core中处理Web请求的管道.所有ASP.NET Core应用程序至 ...

  9. Asp.Net Core Endpoint 终结点路由之中间件应用

    一.概述 这篇文章主要分享Endpoint 终结点路由的中间件的应用场景及实践案例,不讲述其工作原理,如果需要了解工作原理的同学, 可以点击查看以下两篇解读文章: Asp.Net Core EndPo ...

随机推荐

  1. 12-2 MySQL数据库备份(分表)

    #!/bin/bash source /etc/profile DATE="$(date +%F_%H-%M-%S)" DB_IP="172.16.1.122" ...

  2. keycloak~OIDC&OAuth2&自定义皮肤

    1 OpenID & OAuth2 & SAML 1.1 相关资料 https://github.com/keycloak/keycloak https://www.keycloak. ...

  3. Redis 底层数据结构之字典

    文章参考 <Redis 设计与实现>黄建宏 字典 在字典中,每个键都是独一无二的,程序可以在字典中根据键查找与之相关联的值,或者通过键来更新和删除值. 字典在 Redis 中的应用相当广泛 ...

  4. coretext简单使用

    相对于UIKit,使用coretext绘制文本效率高,具有更高的自由度,可随时插入图片,增加文本点击事件等. 1.增加文本的点击事件 思路:定义UILabel子类,设置可点击的富文本range及其他属 ...

  5. 远程cmd操作

    <<PSTools.zip>><<Install_PowerCmd.exe>><<cmder_mini.zip>><< ...

  6. Pandas高级教程之:window操作

    目录 简介 滚动窗口 Center window Weighted window 加权窗口 扩展窗口 指数加权窗口 简介 在数据统计中,经常需要进行一些范围操作,这些范围我们可以称之为一个window ...

  7. DHCP原理于配置

    DHCP原理于配置                      一.DHCP服务                       1)使用DHCP的好处                       2)DH ...

  8. 关于hive的基础

    Hive基础 1.引入原因 对存在HDFS上的文件或HBase中的表进行查询时,是要手工写一堆MapReduce代码 对于统计任务,只能由懂MapReduce的程序员才能搞定 事实上,许多底层细节实际 ...

  9. 简单梳理 ES6 函数

    箭头函数 箭头函数提供了一种更加简洁的函数书写方式.基本语法是 参数 => 函数体 基本用法: var f = v => v; //等价于 var f = function(a){ ret ...

  10. lucene 入门简介

    Lucene 是一个基于 Java 的全文信息检索工具包,它不是一个完整的搜索应用程序,而是为你的应用程序提供索引和搜索功能.Lucene 目前是 Apache Jakarta 家族中的一个开源项目. ...