上篇介紹了Program.cs中Main作了什麼,這篇咱們來討論下Startup.cs它又作了什麼呢?html
咱們新建一個Asp.Net Core Mvc項目,先來開一下Startup的代碼ios
public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.Configure<CookiePolicyOptions>(options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request. options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseCookiePolicy(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); } }
Startup包含兩個方法,咱們先來分析一下ConfigureServices。經過方法上面的註釋能夠看到,這個方法是被.Net運行時調用的,實際上Asp.Net Core提供了內置的IOC容器,此方法就是用來將咱們本身的服務Service注入到Ioc容器當中。那麼如何注入呢?固然是利用該方法的參數IServiceCollection進行注入。若是是咱們自定義的Service,可使用services.AddTransient<IStudentRepository,MockStudentRepository>()或其餘的兩種方式Singleton/Scoped來注入,具體區別看下面代碼。若是是注入.Net Core自帶的,通常是使用AddMvc,AddCors()。web
public void ConfigureServices(IServiceCollection services) { //單例注入,建立的對象在全部的地方全部的請求會話建立的都是相同 services.AddSingleton<IStudentRepository, MockStudentRepository>(); //瞬時注入,每次都建立一個新的對象 services.AddTransient<IStudentRepository, MockStudentRepository>(); //做用域注入,建立的對象在同一個請求會話時是相同的 services.AddScoped<IStudentRepository, MockStudentRepository>(); //注入MVC模塊,包含MvcCore和經常使用第三方庫的服務和方法 services.AddMvc(); //只包含核心的Mvc功能 services.AddMvcCore(); }
接下來咱們來看一下另外一個方法Configure。它是用來配置Asp.Net Core Mvc的Http請求管道的。Asp.Net Core的http請求管道與咱們以前的Asp.Net Mvc的請求管道有着很大的差異,它引入了中間件的概念,更像是一種責任鏈的模式。json
如今咱們就先來分析一下,參數IHostingEnvironment env,顧名思義是web宿主的環境變量相關的。在咱們的實際開發中,咱們經常會將咱們的環境分紅:開發環境development,繼承環境integration,測試環境testing,預發佈環境staging,生產環境production。那這個環境是怎麼配置的呢?實際上它是經過 ASPNETCORE_ENVIRONMENT 這個環境變量來配置運行時的環境的。cookie
通常咱們的配置遵循:app
一、開發機器上,能夠在launchingsetting.json文件中設置該環境變量async
二、在預發佈環境staging或生產環境production下,儘可能將該變量設置在操做系統中的環境變量裏,由於上篇咱們也講到,Asp.Net Core啓動讀取變量配置的時候是會依次覆蓋的。測試
三、除了Asp.Net Core提供的development,staging,production外,咱們能夠定義其餘的環境,經過調用 env.IsEnvironment("自定義的環境變量");來判斷是否處於此環境。ui
通常咱們能夠配置開發環境下顯示錯誤的方式以下面代碼。this
if (env.IsDevelopment()) { DeveloperExceptionPageOptions developerExceptionPageOptions = new DeveloperExceptionPageOptions(); developerExceptionPageOptions.SourceCodeLineCount = 50; //異常顯示行數 app.UseDeveloperExceptionPage(); //開發者異常頁面 }
在咱們繼續往下看代碼以前,先來了解一下Asp.Net Core的中間件這個概念。
中間件是組裝到應用程序管道中以處理請求和響應的軟件,Asp.Net Core自帶了不少的中間件,能夠看下下圖展現的中間件,能夠看到請求通過Logging -> StaticFiles -> MVC後處理完再從MVC -> StaticFiles -> Logging返回給調用方。
其中MVC爲終端中間件,終端中間件表示執行完這個中間件的時候就已經結束了,不會再往下調用其餘的管道中間件了,這也是咱們建立完項目後看到最後一個是app.UseMvc的緣由。
關於中間件咱們須要注意的:
一、中間件能夠同時被訪問和請求
二、能夠處理請求後,將請求傳遞給下一個中間件
三、能夠處理請求後,使管道短路
四、能夠處理傳出響應
五、中間件是按照添加的順序執行的
如今咱們來具體分析下Configure裏面是怎麼配置管道的。IApplicationBuilder app 參數爲咱們提供了不少擴展方法,經過這些方法能夠配置咱們的中間件。首先咱們來看Asp.Net Core提供的Use,Map,Run方法。
Use
方法可使管道短路(即,能夠不調用下一個中間件)。咱們再Configure方法中調用app.Use方法,若是咱們在該方法中不調用next()方法,那麼請求到達該方法就結束返回了,不會再往下一個中間件執行,即後面的Run不會執行。
app.Use(async (context, next) => { context.Response.ContentType = "text/plain;charset=utf-8;"; //解決中文亂碼 await context.Response.WriteAsync("這是第一個Hello World"); //await next(); //調用下一個中間件 }); app.Run(async (context) => { //獲取當前進程名 await context.Response.WriteAsync( System.Diagnostics.Process.GetCurrentProcess().ProcessName); });
若是咱們放開了next(),則會繼續往下執行
再看一下下面的代碼
app.Use(async (context, next) => { context.Response.ContentType = "text/plain;charset=utf-8;"; //解決中文亂碼 await context.Response.WriteAsync("Use1以前"); await next(); //調用下一個中間件 await context.Response.WriteAsync("Use1以後"); }); app.Use(async (context, next) => { await context.Response.WriteAsync("Use2以前"); await next(); //調用下一個中間件 await context.Response.WriteAsync("Use2以後"); });
app.Run(async (context) => { //獲取當前進程名 await context.Response.WriteAsync( System.Diagnostics.Process.GetCurrentProcess().ProcessName); });
咱們能夠看到,請求過來後,以鏈式的方式執行: Use1以前 --> next --> Use2以前 --> next --> Run --> Use2以後 --> Use1以前。
Run
方法是一個約定, 而且一些中間件組件可能暴露在管道末端運行的Run [Middleware]方法,若是將Run放在了Configure裏面,它也是終端中間件。
app.Run(async (context) => { context.Response.ContentType = "text/plain;charset=utf-8;"; //解決中文亂碼 //獲取當前進程名 await context.Response.WriteAsync("當前進程名:" + System.Diagnostics.Process.GetCurrentProcess().ProcessName); });
Map*
擴展用做分支管道的約定。映射根據給定的請求路徑的匹配來分支請求流水線,若是請求路徑以給定路徑開始,則執行分支。
private static void HandleMapTest1(IApplicationBuilder app) { app.Run(async context => { await context.Response.WriteAsync("Map Test 1"); }); } private static void HandleMapTest2(IApplicationBuilder app) { app.Run(async context => { await context.Response.WriteAsync("Map Test 2"); }); } app.Map("/map1", HandleMapTest1); app.Map("/map2", HandleMapTest2);
最後咱們再來看一下Asp.Net Core提供的一些其餘的中間件。
/*自定義默認頁(第一種方式)*/ //DefaultFilesOptions defaultFilesOptions = new DefaultFilesOptions(); //defaultFilesOptions.DefaultFileNames.Clear(); //defaultFilesOptions.DefaultFileNames.Add("custom.html"); //自定義默認頁 //app.UseDefaultFiles(defaultFilesOptions); /**************************************************************************/ /*自定義默認頁(第二種方式)*/ //FileServerOptions fileServerOptions = new FileServerOptions(); //fileServerOptions.DefaultFilesOptions.DefaultFileNames.Clear(); //fileServerOptions.DefaultFilesOptions.DefaultFileNames.Add("custom.html"); //app.UseFileServer(fileServerOptions); //集合了UseStaticFiles,UseDefaultFiles,UseDirectoryBrowser /************************************************/ //app.UseDefaultFiles(); //添加默認文件中間件,必須註冊在UseStaticFiles前 index.html index.htm default.html default.htm app.UseStaticFiles(); //添加靜態文件中間件 //app.UseDirectoryBrowser();//暴露項目文件夾,不推薦使用 app.UseMvcWithDefaultRoute();//在請求管道中添加帶默認路由的MVC
好了,這篇博文介紹了Startup文件作了哪些事情,其中最重要的就是中間件,那麼下一篇就來聊聊Asp.Net Corez中的中間件吧。