什么是中间件:

应用程序管道中用来处理请求和响应的组件。

中间件是一个请求委托(public delegate Task RequestDelegate(HttpContext context))的实例,所以中间件的本质是一个方法,参数是HttpContext,返回参数是一个task,每个中间件根据不同的方法,可以决定是否将请求传递给管道中的下个组件,也可以在执行管道中下个请求的前后都处理业务逻辑。

注册中间件的方法

中间件由管道来注册,ApplicationBuilder来通过注册中间件来构建一个请求管道。构建中间件的方法有:

Run

       用run方法注册的中间件,执行之后,不会再执行下一个中间件,所以这个中间件也叫终端中间件

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            //第一个中间件
            app.Run(async (context) =>
            {
                context.Response.ContentType = "text/plain;charset=utf-8";//防止中文乱码
                await context.Response.WriteAsync("第一个中间件输出你好~");
            });
            //第二个中间件
            app.Run(async (context) =>
            {
                await context.Response.WriteAsync("第二个中间件输出你好~");
            });
        }

它只会执行第一个,不会执行第二个中间件

Use

        use方法的参数是一个委托实例,第一个参数是HttpContext,这是待处理的请求上下文,第二个参数是next,下一个中间件,可以用next.Invoke()调用下一个中间件,并且可以在调用下一个中间件之后/之前对HttpContext进行逻辑处理。

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            //第一个中间件
            app.Use(async (context, next) =>
            {
                context.Response.ContentType = "text/plain;charset=utf-8";//防止中文乱码
                await context.Response.WriteAsync($"第一个中间件输出你好~{Environment.NewLine}");

                await context.Response.WriteAsync($"下一个中间件执行前执行===>{Environment.NewLine}");
                await next.Invoke();
                await context.Response.WriteAsync($"下一个中间件执行后执行<==={Environment.NewLine}");
            });
            //第二个中间件
            app.Use(async (context,next) =>
            {
                await context.Response.WriteAsync($"第二个中间件输出你好~{Environment.NewLine}");
            });
        }

如果没有调用next.Invoke(),会造成管道短路,后面的中间件都不会执行

Map

        当业务复杂的时候,我们可以考虑把不同的业务分支交给不同的管道来处理,Map根据请求的路径的匹配项来创建不同的管道分支。如果请求的路径以给定路径开头,则执行这个分支。

public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        public IConfiguration Configuration { get; }

        // 依赖注入
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }
        /// <summary>
        /// 配置用户分支管道,处理以url以/userinfo开头的请求 
        /// </summary>
        /// <param name="app"></param>
        private static void UserinfoConfigure(IApplicationBuilder app)
        {
            app.Use(async (context, next) =>
            {
                await context.Response.WriteAsync($"处理用户业务,{Environment.NewLine}");
                await next.Invoke();
            });
            app.Run(async (context) => { await context.Response.WriteAsync("用户业务处理完成~"); });
        }
        /// <summary>
        /// 配置产品分支管道,处理以url以/product开头的请求
        /// </summary>
        /// <param name="app"></param>
        private static void ProductConfigure(IApplicationBuilder app)
        {
            app.Use(async (context, next) =>
            {
                await context.Response.WriteAsync($"处理产品业务");
                await next.Invoke();
            });
        }
        // 配置请求处理管道
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            //防止中文乱码
            app.Use(async (context,next) =>
            {
                context.Response.ContentType = "text/plain;charset=utf-8";
                await next.Invoke();
            });

            app.Map("/userinfo", UserinfoConfigure);

            app.Map("/product", ProductConfigure);

            app.Run(async context =>
            {
                await context.Response.WriteAsync("主管道处理其他业务");
            });
        }
    }

MapWhen

        MapWhen和Map的思想比较接近,MapWhen根据自定义条件来创建请求管道分支,并将请求映射到分支。

public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        public IConfiguration Configuration { get; }

        // 依赖注入
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }
        /// <summary>
        /// 配置分支管道,处理以url中有包含/userinfo的请求
        /// </summary>
        /// <param name="app"></param>
        private static void UserinfoConfigure(IApplicationBuilder app)
        {
            app.Use(async (context, next) =>
            {
                await context.Response.WriteAsync($"处理用户业务,{Environment.NewLine}");
                await next.Invoke();
            });
            app.Run(async (context) => { await context.Response.WriteAsync("用户业务处理完成~"); });
        }
        /// <summary>
        /// 配置分支管道,处理以查询参数有name的请求
        /// </summary>
        /// <param name="app"></param>
        private static void HNameConfigure(IApplicationBuilder app)
        {
            app.Use(async (context, next) =>
            {
                await context.Response.WriteAsync($"查询参数包含name,值为:{context.Request.Query["name"]}");
                await next.Invoke();
            });
        }
        // 配置请求处理管道
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            //防止中文乱码
            app.Use(async (context,next) =>
            {
                context.Response.ContentType = "text/plain;charset=utf-8";
                await next.Invoke();
            });
          
            app.MapWhen(context => context.Request.Query.ContainsKey("name"), HNameConfigure);
            app.MapWhen(context => context.Request.Path.Value.ToString().Contains("/userinfo"), UserinfoConfigure);

            app.Run(async context =>
            {
                await context.Response.WriteAsync("主管道处理其他业务");
            });
        }
    }