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(); } }
...未完待續