• .NETCore 之 中间件 01


    .Net core 的Pipeline 是由各种各样的中间件组成的(个人理解),通过一张图我们大体认识一样中间件的请求流程。

     从图中我们可以看出 请求 middleware1->middleware2->middleware,响应:middleware3->middleware2->middleware1,他的请求流程很像  俄罗斯套娃模型

    中间件基本使用:

    我们在 使用 ApplicationBuilder Use 就可以轻松的注册中间件

      app.Use(next =>
                {
                    Console.WriteLine("this is middleware 1");
                    return new RequestDelegate(async context =>
                    {
                        await context.Response.WriteAsync("this is hello world1 start");
                        await next.Invoke(context);
                        await context.Response.WriteAsync("this is hello world1 end");
                    });
                });
    
                app.Use(next =>
                {
                    Console.WriteLine("this is middleware 2");
                    return new RequestDelegate(async context =>
                    {
                        await context.Response.WriteAsync("this is hello world2 start");
                        await next.Invoke(context);
                        await context.Response.WriteAsync("this is hello world2 end");
                    });
                });
    
                app.Use(next =>
                {
                    Console.WriteLine("this is middleware 3");
                    return new RequestDelegate(async context =>
                    {
                        await context.Response.WriteAsync("this is hello world3 start"); 
                        await context.Response.WriteAsync("this is hello world3 end");
                    });
                });

    上段代码相应结果:

    cmd 下:

     浏览器下:

    我们发现在 控制台显示的是 Middleware3->middleware2->middleware1

    但是在浏览器中显示的是 middleware1->middleware2->middleware3     middleware3->middleware2->middleware1

    这时候我们求助源码:

    // Copyright (c) .NET Foundation. All rights reserved.
    // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Http.Features;
    using Microsoft.Extensions.Internal;
    
    namespace Microsoft.AspNetCore.Builder
    {
        public class ApplicationBuilder : IApplicationBuilder
        {
            private const string ServerFeaturesKey = "server.Features";
            private const string ApplicationServicesKey = "application.Services";
    
            private readonly IList<Func<RequestDelegate, RequestDelegate>> _components = new List<Func<RequestDelegate, RequestDelegate>>();
    
            public ApplicationBuilder(IServiceProvider serviceProvider)
            {
                Properties = new Dictionary<string, object>(StringComparer.Ordinal);
                ApplicationServices = serviceProvider;
            }
    
            public ApplicationBuilder(IServiceProvider serviceProvider, object server)
                : this(serviceProvider)
            {
                SetProperty(ServerFeaturesKey, server);
            }
    
            private ApplicationBuilder(ApplicationBuilder builder)
            {
                Properties = new CopyOnWriteDictionary<string, object>(builder.Properties, StringComparer.Ordinal);
            }
    
            public IServiceProvider ApplicationServices
            {
                get
                {
                    return GetProperty<IServiceProvider>(ApplicationServicesKey);
                }
                set
                {
                    SetProperty<IServiceProvider>(ApplicationServicesKey, value);
                }
            }
    
            public IFeatureCollection ServerFeatures
            {
                get
                {
                    return GetProperty<IFeatureCollection>(ServerFeaturesKey);
                }
            }
    
            public IDictionary<string, object> Properties { get; }
    
            private T GetProperty<T>(string key)
            {
                object value;
                return Properties.TryGetValue(key, out value) ? (T)value : default(T);
            }
    
            private void SetProperty<T>(string key, T value)
            {
                Properties[key] = value;
            }
    
            public IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
            {
                _components.Add(middleware);
                return this;
            }
    
            public IApplicationBuilder New()
            {
                return new ApplicationBuilder(this);
            }
    
            public RequestDelegate Build()
            {
                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 = StatusCodes.Status404NotFound;
                    return Task.CompletedTask;
                };
    
                foreach (var component in _components.Reverse())
                {
                    app = component(app);
                }
    
                return app;
            }
        }
    }
    

    app.Use  主要把 中间件记录下来,系统会自动掉调用 Build 方法执行,调用Build 之后。按照上面的代码 在控制台会显示   Middleware3->middleware2->middleware1,其次最终返回的中间件是middleware1 ,这时候 系统会 Kestrel 服务器会从上到下执行中间件

    方便理解原来,模仿了 ApplicationBuilder 注册流程。

      public class ApplicationBuilder
        {
            private readonly Stack<Func<RequestDelegate, RequestDelegate>> _components = new Stack<Func<RequestDelegate, RequestDelegate>>();
    
            public ApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
            {
                _components.Push(middleware);
                return this;
            }
    
            public RequestDelegate Build()
            {
                RequestDelegate app = async s =>
                {
                    Console.WriteLine("http 404");
                    await Task.CompletedTask;
                };
    
                while (this._components.Any())
                {
                    app = this._components.Pop()(app);
                }
                return app;
            }
        }
    
    public delegate Task RequestDelegate(string context); 

    调用:

       ApplicationBuilder app = new ApplicationBuilder();
    
                app.Use(next => {
                    Console.WriteLine("this is middleware 1");
                    return new RequestDelegate(async context => {
                        Console.WriteLine("this is hello world 1 start");
                        await next.Invoke(context);
                        Console.WriteLine("this is hello world 1 end");
                    });
                });
    
                app.Use(next => {
                    Console.WriteLine("this is middleware 2");
                    return new RequestDelegate(async context => {
                        Console.WriteLine("this is hello world 2 start");
                        await next.Invoke(context);
                        Console.WriteLine("this is hello world 2 end");
                    });
                });
    
                app.Use(next => {
                    Console.WriteLine("this is middleware 3");
                    return new RequestDelegate(async context => {
                        Console.WriteLine("this is hello world 3 start"); 
                        Console.WriteLine("this is hello world 3 end");
    
                        await Task.CompletedTask;
                    });
                });
    
    
                app.Build();
    

    至于后面的操作是 Kestrel 服务器干的事情了。

      

     

  • 相关阅读:
    LINUX安装NGINX
    CentOS 设置mysql的远程访问
    centos6 mysql 安装与配置
    php读取用友u8采购入库单列表及详细
    php读取用友u8客户档案
    深度linux没有ll等命令的解决办法
    CentOS7下FTP的安装与配置
    虚拟机CentOS6.5搭建samba服务器实现文件共享
    linux 查找php.ini在那个文件夹
    CBE引擎概览
  • 原文地址:https://www.cnblogs.com/delaywu/p/13121855.html
Copyright © 2020-2023  润新知