• 阅读源码探索实现NetCore中间件


    1.先看代码,在Core2.2 Startup 中,Configure 方法写入中间件,app.Use

    
    
     1 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
     2 {
     3     #region Middleware
     4     app.Use(next =>
     5     {
     6         Console.WriteLine("this is Middleware1");
     7         return new RequestDelegate(async context =>
     8         {
     9             context.Response.ContentType = "text/html; charset=utf-8";
    10             await context.Response.WriteAsync("<span><h3>This is Middleware1 start</h3></span>");
    11             await next.Invoke(context);
    12             await context.Response.WriteAsync("<span><h3>This is Middleware1 end</h3></span>");
    13         });
    14     });
    15     app.Use(next =>
    16     {
    17         return new RequestDelegate(async context =>
    18         {
    19             await context.Response.WriteAsync("<span><h3>This is Middleware2 start</h3></span>");
    20             await next.Invoke(context);
    21             await context.Response.WriteAsync("<span><h3>This is Middleware2 end</h3></span>");
    22         });
    23     });
    24     app.Use(next =>
    25     {
    26         Console.WriteLine("this is Middleware3");
    27         return new RequestDelegate(async context =>
    28         {
    29             await context.Response.WriteAsync("<span><h3>This is Middleware3 start</h3></span>");
    30             await next.Invoke(context);
    31             await context.Response.WriteAsync("<span><h3>This is Middleware3 end</h3></span>");
    32         });
    33     });
    34     app.Run(async context => await context.Response.WriteAsync("跑完了.")); //这一句得加上,才能看出
    35     #endregion
    36 
    37 
    38 
    39     if (env.IsDevelopment())
    40         app.UseDeveloperExceptionPage();
    41     else
    42     {
    43         app.UseExceptionHandler("/Home/Error");
    44         // The default HSTS value is 30 days. You may want to change this for production scenarios, see 
    45         app.UseHsts();
    46     }
    47 
    48     app.UseHttpsRedirection();
    49     app.UseStaticFiles();
    50     app.UseCookiePolicy();
    51 
    52     app.UseMvc(routes =>
    53     {
    54         routes.MapRoute(
    55             name: "default",
    56             template: "{controller=Home}/{action=Index}/{id?}");
    57     });
    58 }
    
    

    2.调试运行输出

    3.通过查看源码,得知app.Use方法其实去添加了一个Func委托到 IList<Func<RequestDelegate, RequestDelegate>>

    public IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
    {
        //_components 就是这个 private readonly IList<Func<RequestDelegate, RequestDelegate>> _components 
        //= new List<Func<RequestDelegate, RequestDelegate>>();
       _components.Add(middleware);// _components 
       return this;
    }
    处理中间件的逻辑看这段代码
     1 public RequestDelegate Build()
     2 {
     3     RequestDelegate app = context =>
     4     {
     5         // If we reach the end of the pipeline, but we have an endpoint, then something unexpected has happened.
     6         // This could happen if user code sets an endpoint, but they forgot to add the UseEndpoint middleware.
     7         var endpoint = context.GetEndpoint();
     8         var endpointRequestDelegate = endpoint?.RequestDelegate;
     9         if (endpointRequestDelegate != null)
    10         {
    11             var message =
    12                 $"The request reached the end of the pipeline without executing the endpoint: '{endpoint.DisplayName}'. " +
    13                 $"Please register the EndpointMiddleware using '{nameof(IApplicationBuilder)}.UseEndpoints(...)' if using " +
    14                 $"routing.";
    15             throw new InvalidOperationException(message);
    16         }
    17 
    18         context.Response.StatusCode = 404;
    19         return Task.CompletedTask;
    20     };
    21 
    22     foreach (var component in _components.Reverse())
    23     {
    24         app = component(app);
    25     }
    26 
    27     return app;
    28 }
    透过这段源码可以发现,处理整个中间件逻辑是,所有的中间件 被存入到 集合 _components ,核心就是把这个集合,转换成单个委托 RequestDelege 。方便调用者调用,执行委托里面的 方法。
    借助于这个想法和思路,自己来写个demo
    新建一个Core测试程序:
     
    namespace Test
    {
        /// <summary>
        /// 给入字符串,返回 Task
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public delegate Task Conduit(string str);
    
    
        public class MiddlewareDemo
        {
            [Test]
            public void Implement()
            {
                CustomMiddleware middle = new CustomMiddleware();
    
                #region C
    
                middle.Add(next =>
                {
                    return zfc =>
                   {
                       Console.WriteLine("第一阶段开始");
                       System.Diagnostics.Debug.WriteLine("第一阶段开始");
                       return next(zfc);
                   };
                });
    
                middle.Add(next =>
                {
                    return zfc =>
                   {
                       Console.WriteLine("第二阶段开始");
                       System.Diagnostics.Debug.WriteLine("第二阶段开始");
                       return next(zfc);
                   };
                });
    
                middle.Add(next =>
                {
                    return zfc =>
                   {
                       Console.WriteLine("第三阶段开始");
                       System.Diagnostics.Debug.WriteLine("第三阶段开始");
                       return next(zfc);
                   };
                });
    
                #endregion
    
    
                #region D
                //middle.Add(next =>
                //{
                //    return async zfc =>
                //    {
                //        Console.WriteLine("第一阶段开始");
                //        System.Diagnostics.Debug.WriteLine("第一阶段开始");
                //        await next(zfc);
                //        Console.WriteLine("第一阶段结束");
                //        System.Diagnostics.Debug.WriteLine("第一阶段结束");
                //    };
                //});
    
                //middle.Add(next =>
                //{
                //    return async zfc =>
                //    {
                //        Console.WriteLine("第二阶段开始");
                //        System.Diagnostics.Debug.WriteLine("第二阶段开始");
                //        await next(zfc);
                //        System.Diagnostics.Debug.WriteLine("第二阶段结束");
                //        Console.WriteLine("第二阶段结束");
                //    };
                //});
    
                //middle.Add(next =>
                //{
                //    return async zfc =>
                //    {
                //        Console.WriteLine("第三阶段开始");
                //        System.Diagnostics.Debug.WriteLine("第三阶段开始");
                //        await next(zfc);
                //        System.Diagnostics.Debug.WriteLine("第三阶段结束");
                //        Console.WriteLine("第三阶段结束");
                //    };
                //});
                #endregion
                var ak = middle.GetDelegate();
                ak.Invoke("正序执行中间件"); 
            System.Diagnostics.Debug.WriteLine("**********分界线**********");
                var ff = middle.Reverse();
                ff.Invoke("开始执行中间件!");
    
                System.Diagnostics.Debug.WriteLine("跑完了ddd");
                Console.WriteLine("跑完了ddd");
    
            }
        }
    
    
        /// <summary>
        /// 模拟中间件
        /// </summary>
        public class CustomMiddleware
        {
            public IList<Func<Conduit, Conduit>> _middlelist = new List<Func<Conduit, Conduit>>();
            // Add也就是NetCore中StartUp中的 app.Use ,同理     
            public void Add(Func<Conduit, Conduit> func)
            {
                _middlelist.Add(func);
            }
    
            //为了方便理解做比较,这个没有集合倒序
            //把集合整合成一个 Conduit委托
            public Conduit GetDelegate()
            {
                Conduit conduit = str =>
                 {
                     str = "初始化!";
                     return Task.CompletedTask;
                 };
                foreach (Func<Conduit, Conduit> item in _middlelist)//正序
                  //核心在这里,看似在赋新值,其实是在一层又一层包裹这一个执行方法实例,
                  //给人感觉就像在叠加一样,如果这个地方没有倒序,那么执行方法顺序就是反的
                   conduit = item(conduit); 
                return conduit;
            }
    
    
            /// <summary>
            /// 把集合进行倒叙,然后整合成一个 Conduit委托
            /// </summary>
            /// <returns></returns>
            public Conduit Reverse()
            {
                Conduit app = str =>
                 {
                     str = "初始化!";
                     return Task.CompletedTask;
                 };
                foreach (var component in _middlelist.Reverse())//倒序
                {
                    app = component(app);
                }
                return app;
    
            }
    
    
    
    
            /*
               public RequestDelegate Build()
               {
    
                IList<Func<RequestDelegate, RequestDelegate>> _components = new List<Func<RequestDelegate, RequestDelegate>>();
    
                   RequestDelegate app = context =>
                   {
                       // If we reach the end of the pipeline, but we have an endpoint, then something unexpected has happened.
                       // This could happen if user code sets an endpoint, but they forgot to add the UseEndpoint middleware.
                       var endpoint = context.GetEndpoint();
                       var endpointRequestDelegate = endpoint?.RequestDelegate;
                       if (endpointRequestDelegate != null)
                       {
                           var message =
                               $"The request reached the end of the pipeline without executing the endpoint: '{endpoint.DisplayName}'. " +
                               $"Please register the EndpointMiddleware using '{nameof(IApplicationBuilder)}.UseEndpoints(...)' if using " +
                               $"routing.";
                           throw new InvalidOperationException(message);
                       }
    
                       context.Response.StatusCode = 404;
                       return Task.CompletedTask;
                   };
    
                   foreach (var component in _components.Reverse())
                   {
                       app = component(app);
                   }
                   return app;
               }
               */
        }
    }

     运行效果:

     至此,模仿Core中间件的执行已经完成,感兴趣的小伙伴,可以新建一个测试程序,测试一下,你会发现很多不同的东西哦
     
    
    
  • 相关阅读:
    vim对光标所在的数字进行增减
    fedora找开ftpd服务器并以root登陆
    wxwidget自定义消息处理步骤
    c++的检测的确比C++更严格
    php常用字符串操作函数
    如何判断一个数组是一维数组或者是二维数组?用什么函数?
    php 面试 题汇总
    php 数组 常用函数
    php 会话控制
    用tp实现中文验证码
  • 原文地址:https://www.cnblogs.com/Qintai/p/11827973.html
Copyright © 2020-2023  润新知