ASP.NET Core 2.2 基礎知識(二) 中間件


中間件是一種裝配到應用管道以處理請求和相應的軟件.每個軟件都可以:

1.選擇是否將請求傳遞到管道中的下一個組件;

2.可在調用管道中的下一個組件前后執行工作.

管道由 IApplicationBuilder 創建:

每個委托都可以在下一個委托前后執行操作,.此外,委托還可以決定不將請求傳遞給下一個委托,這就是對請求管道進行短路.通常需要短路,是因為這樣可以避免不必要的工作.比如:

1.靜態文件中間件可以返回靜態文件請求並使管道的其余部分短路;

2.現在管道中調用異常處理委托,以便他們可以捕獲在管道的后期階段所發生的異常.

委托的添加方式一共有3種:

1.Run

該方法的XML注釋是這樣寫的:

Adds a terminal middleware delegate to the application's request pipeline.向應用程序請求管道添加一個終端中間件.

通俗來講,意思就是該方法添加的委托,會使"請求管道短路",不管該委托是否提前響應都會短路.比如下面代碼中標紅的部分,不管有沒有這一句代碼,下面的所有代碼都不會執行.

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.Run(async context =>
            {
                await context.Response.WriteAsync("Hello World!");
            });

            //下面的都不會執行了,因為上面的委托已經終止了管道,或者說:"已經讓管道短路了"
          ...  
        }

 

2.Use

該方法的XML注釋是這樣寫的:

Adds a middleware delegate defined in-line to the application's request pipeline.和上面的 Run 方法相比,少了"terminal".意義就已經很明顯了.

                //用 Use 將多個請求委托鏈接在一起. next 參數表示管道中的下一個委托,可通過不調用 next 參數使管道短路.
                //通常可在下一個委托前后執行操作,如以下示例
                app.Use(async (context, next) =>
                {
                    var name = context.Request.Query["name"];
                    if (!string.IsNullOrWhiteSpace(name))
                    {
                        await context.Response.WriteAsync($"hello world , {name}");
                    }
                    await next.Invoke();
                });

請求一:

請求二:

 

3.Map

根據給定請求路徑的匹配項來創建請求分支.如果請求路徑以給定的路徑開頭,則執行分支,如紅色部分代碼

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            //Map
            app.Map(new PathString("/map1"), MapTest1);
            app.Map("/map2", MapTest2);
            app.MapWhen(context => !string.IsNullOrWhiteSpace(context.Request.Query["name"]), MapTest3);

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }
            app.UseHttpsRedirection();
            app.UseMvc();
        }


        public void MapTest1(IApplicationBuilder app)
        {
            app.Run(async context => { await context.Response.WriteAsync("this is maptest1"); });
        }

        public void MapTest2(IApplicationBuilder app)
        {
            app.Run(async context => { await context.Response.WriteAsync("this is maptest2"); });
        }

        public void MapTest3(IApplicationBuilder app)
        {
            app.Run(async context => { await context.Response.WriteAsync("this is maptest3"); });
        }

 

另外,Map 支持嵌套 :  app.Map("/map2", builder => { builder.Map("/map22", MapTest22); });

封裝中間件

在實際運用過程中,我們通常將中間件封裝在類中,然后通過擴展方法公開出來.方式有兩種:

一.啟動時構造

1.自定義中間件

    public class MyMiddleware
    {
        private readonly RequestDelegate _next;

        public MyMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        //方法名必須是 Invoke 或者 InvokeAsync
        public async Task InvokeAsync(HttpContext context)
        {
            var name = context.Request.Query["name"];
            if (!string.IsNullOrWhiteSpace(name))
            {
                await context.Response.WriteAsync($"hello world,{name}");
            }
            else
            {
                await _next(context);
            }
        }
    }

2.通過擴展方法公開

    public static class MyMiddlewareExtensions
    {
        public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder app)
        {
            return app.UseMiddleware<MyMiddleware>();
        }
    }

3.調用自定義的中間件.

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }

            //調用自制中間件
 app.UseMyMiddleware();

            app.UseHttpsRedirection();
            app.UseMvc();
        }

 

這種方式編寫的中間件,是在web應用啟動時構造的,而不是按請求構造的,因此相當於單例.

所以,如果想正確使用中間件依賴項的生存期,則需要將這些依賴項添加到 Invoke 或者 InvokeAsync 方法的入參里面,如:

    public class Person
    {
        public string Name { get; set; }
    }
    public class Startup
    {
        ...other codes
    
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            //services.AddSingleton(new Person() { Name = "admin" });
            //services.AddTransient<Person>();
            services.AddScoped<Person>();
        }
        ...other codes
    }

 

        //方法名必須是 Invoke 或者 InvokeAsync
        public async Task InvokeAsync(HttpContext context, Person person)
        {
            var name = context.Request.Query["name"];
            if (!string.IsNullOrWhiteSpace(name))
            {
                await context.Response.WriteAsync($"hello world,{name},the person`s hashcode is {person.GetHashCode()}");
            }
            else
            {
                await context.Response.WriteAsync($"hello world,{person.Name},the person`s hashcode is {person.GetHashCode()}");
            }
        }

 

 二.按請求激活

該方式需要自定義中間件實現 IMiddleware 接口.

    public class MyMiddleware : IMiddleware
    {
        private readonly Person _person;

        public MyMiddleware(Person person)
        {
            _person = person;
        }


        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            var name = context.Request.Query["name"];
            if (!string.IsNullOrWhiteSpace(name))
            {
                await context.Response.WriteAsync($" {name} , hello ! the model`s hashcode is {this.GetHashCode()}");
            }
            else
            {
                await context.Response.WriteAsync($" {_person.Name} hello ! the model`s hashcode is {this.GetHashCode()}");
            }
        }
    }

 

擴展方法的代碼沒變:

    public static class MyMiddlewareExtensions
    {
        public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder app)
        {
            return app.UseMiddleware<MyMiddleware>();
        }
    }

 

調用自制的中間件:

    public class Startup
    {

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
            //將中間件對象按我們需要的生存期注入到容器中.
            //services.AddTransient<MyMiddleware>();
            //services.AddScoped<MyMiddleware>();
            services.AddSingleton<MyMiddleware>();

       services.AddSingleton(new Person { Name = "admin" });
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { //注冊我們的中間件 app.UseMyMiddleware(); app.UseHttpsRedirection(); app.UseMvc(); } }

 

 

 

 

...未完待續


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM