筆記內容來源於微軟 MVP 楊旭老師 solenovex 的視頻
Startup 類:注冊服務和使用中間件
Startup類默認生成了兩個方法,在這個類中主要負責注冊服務和使用中間件。
讓我們先來看一下Startup類的源碼
Startup類的源碼
在下面的源碼中有ConfigureServices和Configure兩個方法。
public void ConfigureServices(IServiceCollection services){} public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.Run(async (context) => { await context.Response.WriteAsync("Hello World!"); }); }
1.ConfigureServices方法
ConfigureServices方法是用來注冊服務的,Configure方法是用來使用中間件的。
注冊服務就是依賴注入,向Ioc容器中注入類型的對象,注入后就可以直接使用該類型注入實例,而無需再次實例化,減少了代碼的耦合。
具體內容可以自行百度依賴注入/控制反轉。
2.Configure方法
Configure方法配置了Http請求處理的管道,每個Http請求到達之后,會按照Configure方法中的組件來決定如何處理這些請求。
其中的app.Run方法以及匿名函數,就是不管什么請求到達這里,都會返回 context.Response.WriteAsync("Hello World!") 響應。
注冊服務演示
我們先創建一個IWelcomeService接口以及實現該接口的WelcomeService類
public interface IWelcomeService { string GetMessage(); } public class WelcomeService : IWelcomeService { public string GetMessage() { return "Hello from IWelcomeService"; } }
然后在Startup類Configure方法中使用該接口類型對象,調用接口的GetMessage方法輸出
事實上,運行后我們會發現直接使用是不行的,因為該類型剛還有在ConfigureServices方法中注冊。
下面我們就在ConfigureServices方法中注冊接口和實現類。
public void ConfigureServices(IServiceCollection services) { services.AddSingleton<IWelcomeService, WelcomeService>(); }
運行后的結果
Hello from IWelcomeService
注冊服務的幾種形式
注冊服務時,我們使用的是AddSingleton方法,這是以單例的形式依賴注入對象,單例就是指該類型只有一個實例,具體含義和用法可以自行百度。
還有其他幾種形式,如AddTransient方法,每次請求都會生成一個實例,AddScoped方法,每次Http請求都會生成一個實例。
管道和中間件
Configure方法配置了Http請求處理的管道。
假設有個Http請求到達了我們的Web應用,有一個POST請求,那么我們的Web應用就需要處理這個請求。中間件就是負責處理請求的,他將決定如何處理這些請求。
中間件其實就是個對象,每個中間件的角色和功能都不一樣,並且局限在特定的領域內。每個中間件都很小,Web應用會用到很多中間件。
一個簡單的中間件管道示例
假設一個POST請求Product,首先通過Logger中間件,Logger可以查看到很多的信息,記錄下請求的信息,也可以拒絕請求。
然后轉送到下個中間件,比如授權中間件。授權中間件會先找一個特定的cookie的值或者token,如果找到了就轉發到下一個中間件。
下一個中間件可以是路由中間件。首先查看請求的URL,然后找到可以響應該請求的方法,就可以返回一個JSON/HTML,然后原路返回。
Startup類被調用的邏輯
搞清了Startup類中的方法的作用和能做什么后,我們來看一看Startup類是如何被調用的。
上一篇博文提到了Program類的CreateWebHostBuilder方法中調用了 UseStartup<Startup>() ,就是這個方法制定了Startup類為啟動類,實例化Starup類得到實例,並調用類中的兩個方法。
首先會調用ConfigureServices方法,注冊服務。除了預先注冊好的服務,自己寫的類和一些沒注冊內置類都需要在該方法中注冊。
然后調用Configure方法,該方法只會調用一次。在該方法中,我們使用實現了IApplicationBuilder接口的類型的對象,來配置中間件。
中間件的Use方法
默認的Run方法並不建議使用,項目中常常使用Use方法。除此之外還有內置的很多USeXxx方法。如UseWelcomePage方法就會調用歡迎頁。這些方法的參數往往可以傳遞一個對象來對其進行配置。
還有直接使用Use方法更底層,其參數是一個Func<ReuquestDelegate,ReuquestDelegate>,Func的參數是ReuquestDelegate,
其返回類型也是ReuquestDelegate。ReuquestDelegate類型就是一段可執行的代碼,例如下方代碼,返回了一個異步Task,Task返回了httpContext對象。
app.Use(next => { return async httpContext => { if (httpContext.Request.Path.StartsWithSegments("/first")) { await httpContext.Response.WriteAsync("First!"); } else { await next(httpContext); } }; });
異常頁面的中間件
下方代碼首先判斷當前環境是不是開發環境,如果是,當出現錯誤時就會使用開發者異常頁面中間件。
因為開發者需要詳細的錯誤信息,但是這些信息不能直接暴露,否則會被黑客輕易利用,因此只能在開發者環境下才需要調用開發者異常頁面中間件。
if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); }
判斷環境和自定義環境
前面講到可以判斷運行環境,事實上環境是可以自定義的,