vlambda博客
学习文章列表

.NET Core 管道模型中间件及管道模拟实现

管道,Pipeline

ASP.NET Core 路由,认证,绘画,缓存,都是由管道来处理的中间件。

MVC WEB API,都是建立在某个特殊的中间件之上。

编写中间件来扩展请求管道,可以在AP.NET Core基础之上,创建自己的Web框架。

中间件Middleware,两个职责:

1 选择是否将请求传递给管道种的下一个中间件

2 在管道种的下一个中间件的前后执行工作。

每一个中间件都有权做出决定是否将请求传递给下一个中间件,也可以直接做出响应,促使管道短路。

短路就是指不再将请求继续往下传递,而是结束请求并开始响应。短路是非常有必要的,避免很多不必要的工作。

.NET Core 管道模型中间件及管道模拟实现

http请求被层层处理和控制,层次清晰,处理起来非常方便

ASP.NET MVC里的过滤器Filter和中间件都是AOP思想的产物。定位和关注点不一样。

过滤器关注的是如何实现功能(非业务),它是一种功能。

中间件是ASP.NET Core管道模型中的重要组成部分,担负了整个请求到响应的处理流程。

过滤器实现的功能,只是中间件顺带表现出来的。

如何布置管道?在管道里布置中间件。

中间件是有顺序的,添加中间件的顺序就是请求调用这些中间件的顺序。

请求和响应,方向是相反的,顺序自然也是相反的。

顺序很重要。有的中间件无所谓,有的中间件必须有顺序。

内置中间件直接use就可以用了。

自定义中间件。约定:具有类型为RequestDeletegate的参数的公共构造函数。

下面是模拟实现管道的代码,参考了.NET CORE 3.0里管道的实现方式。

.NET Core 管道模型中间件及管道模拟实现

Program.cs类代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

using System;

using System.Threading.Tasks;

 

namespace PipelineDemo

{

    public delegate Task RequestDelegate(HttpContext context);

    class Program

    {

        static void Main(string[] args)

        {

            var app = new ApplicationBuilder();

            app.Use(async (context,next)=>{

                Console.WriteLine("中间件1号 Begin");

                await next();

                Console.WriteLine("中间件1号 End");

            });

            app.Use(async (context, next) => {

                Console.WriteLine("中间件2号 Begin");

                await next();

                Console.WriteLine("中间件2号 End");

            });

            app.Use(Middleware3);

            var firstMiddleware = app.Build();

            firstMiddleware(new HttpContext());

        }

        public static async Task Middleware3(HttpContext httpcontext, Func<Task> next)

        {

            Console.WriteLine("中间件3号 Begin");

            await next();

            Console.WriteLine("中间件3号 End");

        }

    }

}


ApplicationBuilder.cs类代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

34

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

namespace PipelineDemo

{

    public class ApplicationBuilder

    {

        private static readonly IList<Func<RequestDelegate, RequestDelegate>> _components = new List<Func<RequestDelegate, RequestDelegate>>();

 

        public ApplicationBuilder Use(Func<HttpContext, Func<Task>, Task> middleware)

        {

            return Use(next =>

            {

                return context =>

                {

                    Task SimpleNext() => next(context);

                    return middleware(context, SimpleNext);

                };

            });

        }

        public ApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware) {

            _components.Add(middleware);

            return this;

        }

        public RequestDelegate Build() {

            // 默认中间件

            RequestDelegate app = context =>

            {

                Console.WriteLine("默认中间件");

                return Task.CompletedTask;

            };

            // 对_components反转,逐一执行添加中间件的委托,最后返回第一个中间件的委托

            // 把_components里独立的中间件委托串联起来,然后返回反转后的最后一个中间件(其实就是第一个)

            // 管道真正建立起来,每一个中间件都相连

            foreach (var component in _components.Reverse()) {

                app = component(app);

            }

            return app;

        }

    }

}

HttpContext.cs类代码,仅为模拟,所以没有属性

1

2

3

4

5

6

7

8

9

10

using System;

using System.Collections.Generic;

using System.Text;

 

namespace PipelineDemo

{

    public class HttpContext

    {

    }

}

运行效果

出处:https://www.leavescn.com/Articles/Content/1158