說明:此隨筆主要詳細解釋asp.netcore 3.1的Program類和Startup類,以及兩者之間的關系。
Program類 :為了詳細解讀,將此類的兩個方法改寫。
public class Program { #region 這兩個方法是創建項目的時候自動創建的,為了詳細解讀,將這兩個方法注釋掉並重新改寫。 //public static void Main(string[] args) //{ // CreateHostBuilder(args).Build().Run(); //} //public static IHostBuilder CreateHostBuilder(string[] args) => // Host.CreateDefaultBuilder(args) // .ConfigureWebHostDefaults(webBuilder => // { // webBuilder.UseStartup<Startup>(); // }); #endregion #region 改寫 Main 和 CreateHostBuilder 方法如下 /// <summary> /// 應用程序入口,asp.netcore 本質上是控制台程序 /// </summary> /// <param name="args"></param> public static void Main(string[] args) { //CreateHostBuilder(args).Build().Run(); 改寫前 //改寫后 var hostBuilder = CreateHostBuilder(args);//創建宿主host構建器 var webHost = hostBuilder.Build();//用構建器 創建宿主host webHost.Run();//運行宿主host之后,就可以監聽http或者https請求了。即 運行宿主host,開始監聽HTTP或者HTTPS請求。 } /// <summary> /// 改寫后的 CreateHostBuilder 方法 /// </summary> /// <param name="args"></param> /// <returns></returns> public static IHostBuilder CreateHostBuilder(string[] args) { //創建構建器hostbuilder var hostBuilder = Host.CreateDefaultBuilder(args); //配置 hostbuilder hostBuilder.ConfigureWebHostDefaults(webBuilder => { //注冊Startup類,startup類配置web應用的啟動邏輯,asp.netcore運行時 會實例化這個類, webBuilder.UseStartup<Startup>(); }); return hostBuilder; } #endregion }
Startup 類
由運行時 調用 ConfigureServices 和Configure 這兩個方法。調用的第一個方法是 ConfigureServices 方法,這個方法用於注冊服務,
服務被注冊后,才能傳遞對應的具體實現類。然后調用 Configure方法,這個方法用於配置管道中間件。
其中,管道的工作的工作流程如下:
當用戶發出一起請求后,應用程序都會為其創建一個請求管道,在這個請求管道中,
每一個中間件都會按順序進行處理(可能會執行,也可能不會被執行,取決於具體的業務邏輯),
等最后一個中間件處理完畢后請求又會以相反的方向返回給用戶最終的處理結果
public class Startup { private readonly IConfiguration _configuration; /// <summary> /// 通過構造函數注入,由運行時自動注入 /// </summary> /// <param name="configuration"></param> public Startup(IConfiguration configuration) { _configuration = configuration; var aa = _configuration["FyyAspnetcore:Name"];// 獲取 appsettings.json文件的數據 } #region 運行時同通過約定來調用這兩個方法。先調用 ConfigureServices、再調用 Configure. /// <summary> /// 負責依賴注入配置,宿主啟動后,會將服務都注冊好。 /// DI的優點: /// 1.解耦,沒有強依賴,Controller與具體的服務類解耦 /// 2.利於單元測試 /// 3.不需要了解具體的服務類:Controller 不需要了解服務類及其工作細節。 /// 4.也不需要管理服務類的生命周期:Controller 不需要管理服務類的生命周期,生命周期交給IOC容器DI來控制。 /// </summary> /// <param name="services"></param> public void ConfigureServices(IServiceCollection services) { //當IHelloService 被請求時,IOC容器會返回一個HelloService的實例。 //AddSingleton 表示所注冊的服務周期 是整個應用程序生存期間,整個應用程序只有一個實例,只有應用程序停止,才會被銷毀。 services.AddSingleton<IHelloService, HelloService>(); //所注冊的服務的生命周期是整個請求期間。一次web請求產生一個實例,web請求處理完的時候,生命周期就結束了。 //services.AddScoped<IHelloService, HelloService>; //所注冊的服務的生命周期是暫時的,服務每次沒請求的時候,都會實例化一個對象。 //services.AddTransient<IHelloService, HelloService>; //注冊webapi的服務 //services.AddControllers(); //注冊mvc的服務 //services.AddControllersWithViews(); //將配置文件的Json,映射到類中。(配置到類中,配置依賴注入) services.Configure<FyyAspnetcore>(_configuration.GetSection("FyyAspnetcore")); } /// <summary> /// Development環境變量時,走這個方法。可以針對不同的環境,使用不同的方法。 /// </summary> /// <param name="app"></param> /// <param name="env"></param> //public void ConfigureDevelopment(IApplicationBuilder app, IWebHostEnvironment env) //{ //} /// <summary> /// 負責配置了asp.netcore http請求管道的中間件。宿主啟動后,中間件進入工作就緒狀態。 /// http/https 請求通過管道進來后,Configure方法中的組件(中間件)將決定如何響應http/https請求 /// 請求從管道進來,處理完后再從管道出去,如果管道里什么都沒有,請求進來再回去,就什么都不會發生。 /// /// 當ASP.NETCORE 調用configure方法的時候,會分析方法的參數,如果asp.netcore能解析這些參數,就會傳入實現了該接口的服務(類) /// </summary> public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IConfiguration configuration, IHelloService helloService, ILogger<Startup> logger) { /* 參數解釋: IApplicationBuilder app:應用程序構建器,使用它來配置中間件。一般用app.use...這些方法來配置。由運行時注入。 IWebHostEnvironment env:通過這個服務,獲取應用程序運行的環境。由運行時注入 IConfiguration configuration:通過這個服務,可獲取配置文件appsetting.json 內容。由運行時注入。 ILogger<Startup> logger:日志服務,由於運行時注入。 IHelloService helloService:手動在 ConfigureServices 方法中注入。 */ //判斷環境變量 //env.IsEnvironment("OK"); 判斷自定義環境變量 if (env.IsDevelopment()) { //開發模式下插入到管道的第一個中間件。 //異常處理中間件:用於捕獲管道中,位置在它之后的中間件拋出的異常。並返回開發者異常頁面。 app.UseDeveloperExceptionPage(); } else//非開發環境 { app.UseExceptionHandler("/Home/Error"); } //使用授權中間件 // app.UseAuthentication(); //這種寫法,比 app.Use...更底層。 RequestDelegate 傳進的參數是 httpcontext //這里 next 代表着在管道里下一個將要執行的中間件。 app.Use( //以next 為開始的這個方法,只在啟動管道的時候走一遍。 next => { logger.LogInformation("--中間件准備就緒,只執行一次-----------"); return //這個才是中間件的代碼,如果之前沒有其他中間件攔截的話,每次請求都會進來 async httpContext => { logger.LogInformation("--中間件開始-----------"); if (httpContext.Request.Path.StartsWithSegments("/first")) { logger.LogInformation("--22222-----------"); await httpContext.Response.WriteAsync("first"); } else { logger.LogInformation("--33333-----------"); await next(httpContext); } }; }); app.UseHttpsRedirection();//https 重定向中間件,強制客戶端使用ssl協議。 /*使用這個中間件 會將wwwroot文件夾中的內容對外可見(對外伺服)。如果不使用這個中間件,客戶端就訪問不了wwwroot中的靜態文件,如JS,CSS,圖片等靜態文件。*/ app.UseStaticFiles();
app.UseStaticFiles(requestPath:"/StaticFiles"); //添加其他對外伺服文件夾
//或者這樣寫
app.UseStaticFiles(new StaticFileOptions{
RequestPath="/Staticfiles",
FileProvider=new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "StaticFiles"))
}); app.UseRouting();//路由中間件。會檢查在應用中已經注冊的端點。 //app.UseWelcomePage();//配置 歡迎頁 中間件。配置后,會改變 請求路由的endpoint app.UseWelcomePage(new WelcomePageOptions { Path = "/1234" //當請求路徑的endpoint 是"/1234"時,會執行這個中間件,並且會在這里短路返回。 }); app.UseEndpoints(endpoints => //注冊端點,端點就是進來的http請求的url的結尾那部分。這部分由端點中間件處理。 { logger.LogInformation("ttttttttttt"); endpoints.MapGet("/", async context =>// 以/結尾的url,映射到下面的表達式中。 { throw new Exception("拋出異常啦");//會被捕獲。 var helloWorld = configuration["Hello"]; //由於 IHelloService 並沒有被 運行時默認注冊,所以需要在ConfigureServices 進行手動注冊。讓.netcore知道傳遞的是哪個具體的服務(實現類)。 //否則不會將實現了IHelloService接口的服務傳遞進來。會報異常,說不能解析 IHelloService類型的服務 helloService var helloWorld1 = helloService.GetMsg(); //configuration asp.netcore 運行時自動默認注冊進來,不需要手動注冊。 //下一個反編譯.net reflactor 來了解一下configuration的配置原理 //以后面的加載的為准。 await context.Response.WriteAsync(helloWorld + "----" + helloWorld1); }); //MVC的路由端點,路由模板,路由表的形式 //endpoints.MapControllerRoute( // name:"default", // pattern:"{controller=Home}/{action=Index}/{id?}" // ); //使用這種方式,可以在controller或action上添加路由,不需要添加路由表。 // endpoints.MapControllers(); }); } #endregion }
類 HelloService 和接口 IHelloService
public class HelloService : IHelloService { public string GetMsg() { return "HelloWorld not rejected by runtime"; } } public interface IHelloService { string GetMsg(); }
類: FyyAspnetcore
public class FyyAspnetcore { public string Name { get; set; } public int Age { get; set; } }
appsettings.json
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*", "FyyAspnetcore": { "Name": "Fengyinyong", "Age": 30 },
"Hello":"hello hehehehehe" }
使用這個中間件,會將wwwroot文件夾的內容對外伺服,即對外可見。