深入淺出Dotnet Core的項(xiàng)目結(jié)構(gòu)變化
本文轉(zhuǎn)載自微信公眾號(hào)「老王Plus」,作者老王Plus的老王 。轉(zhuǎn)載本文請(qǐng)聯(lián)系老王Plus公眾號(hào)。
前幾天Review一個(gè)項(xiàng)目的代碼,發(fā)現(xiàn)非常基礎(chǔ)的內(nèi)容,也會(huì)有人理解出錯(cuò)。
今天,就著這個(gè)點(diǎn),寫(xiě)一下Dotnet Core的主要類(lèi)型的項(xiàng)目結(jié)構(gòu),以及之間的轉(zhuǎn)換和演化。
一、最基礎(chǔ)的應(yīng)用Console
控制臺(tái)應(yīng)用,是Dotnet Core乃至前邊的Dotnet Framework中,最基礎(chǔ)的項(xiàng)目。
我們來(lái)創(chuàng)建一個(gè)Console項(xiàng)目看一下:
- % dotnet new console -o demo
創(chuàng)建完成后,打開(kāi)工程。工程里只有一個(gè)文件Program.cs,里面只有一個(gè)方法Main:
- namespace demo
- {
- class Program
- {
- static void Main(string[] args)
- {
- Console.WriteLine("Hello World!");
- }
- }
- }
在Dotnet Core所有類(lèi)型的項(xiàng)目中,Program.cs都是最開(kāi)始的入口,main方法,也是最開(kāi)始的入口方法。
這個(gè)工程中,還有一個(gè)文件也需要了解一下,demo.csproj,這是這個(gè)項(xiàng)目的定義文件:
- <Project Sdk="Microsoft.NET.Sdk">
- <PropertyGroup>
- <OutputType>Exe</OutputType>
- <TargetFramework>net5.0</TargetFramework>
- </PropertyGroup>
- </Project>
這里面,OutputType告訴編輯器這個(gè)工程編譯后可以直接執(zhí)行,TargetFramework定義運(yùn)行的框架。
注意,這個(gè)框架字串有個(gè)對(duì)照表:net5.0對(duì)應(yīng)的是.Net 5.0;如果你想用Dotnet Core 3.1,對(duì)應(yīng)的字符串是netcoreapp3.1,而不是net3.1。準(zhǔn)確的說(shuō),3.1是.Net Core 3.1,而5.0是.Net 5.0。不用太糾結(jié),微軟的命名規(guī)則而已。
這就是控制臺(tái)應(yīng)用Console的初始狀態(tài)。
下面,我們看看這個(gè)工程如何轉(zhuǎn)變?yōu)閃eb應(yīng)用。
二、轉(zhuǎn)為Web應(yīng)用
第一件事,我們需要改動(dòng)demo.csproj項(xiàng)目定義文件。
Web應(yīng)用跑在WebHost上面,而不是從直接執(zhí)行。所以,我們需要把OutputType項(xiàng)去掉。
另外,SDK也需要改一下。Console我們用的是Microsoft.NET.Sdk,Web應(yīng)用要改成Microsoft.NET.Sdk.Web:
- <Project Sdk="Microsoft.NET.Sdk.Web">
- <PropertyGroup>
- <TargetFramework>net5.0</TargetFramework>
- </PropertyGroup>
- </Project>
改完保存。
這時(shí)候,應(yīng)該可以注意到,項(xiàng)目的發(fā)生了變化:
- 依賴(lài)的框架從Microsoft.NETCore.App變成了兩個(gè),多了一個(gè)Microsoft.AspNetCore.App,表明現(xiàn)在這是一個(gè)Asp.net Core的應(yīng)用;
- 項(xiàng)目中自動(dòng)生成了一個(gè)目錄Properties,下面多了一個(gè)文件launchSettings.json。這個(gè)文件大家應(yīng)該很熟悉,就不解釋了。
這時(shí)候,應(yīng)用已經(jīng)從Console轉(zhuǎn)為了Web應(yīng)用。
Asp.Net Core框架提供了Host供Web加載。我們需要做的,是把Host構(gòu)建器加到程序中。通常,我們需要兩個(gè)構(gòu)建器:
- 通用主機(jī) Generic host builder
- Web主機(jī) Web host builder
1. 配置通用主機(jī)
通用主機(jī)在Microsoft.Extensions.Hosting.Host中,主要給Web應(yīng)用提供以下功能:
- 依賴(lài)注入
- 日志
- 配置 IConfiguration
- IHostedService實(shí)現(xiàn)
加入通用主機(jī)很簡(jiǎn)單,就一個(gè)方法CreateDefaultBuilder:
- class Program
- {
- static void Main(string[] args)
- {
- Host.CreateDefaultBuilder(args)
- .Build()
- .Run();
- }
- }
2. 配置Web主機(jī)
Web主機(jī)才是真正與Web相關(guān)的內(nèi)容,主要實(shí)現(xiàn):
- Http支持
- 設(shè)置Kestrol服務(wù)器為Web服務(wù)器
- 添加IIS支持
加入Web主機(jī),也是一個(gè)方法ConfigureWebHostDefaults:
- class Program
- {
- static void Main(string[] args)
- {
- Host.CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(webBuilder =>
- {
- })
- .Build()
- .Run();
- }
- }
這個(gè)方法用來(lái)添加Http請(qǐng)求管道并注入我們需要的服務(wù)。而注入我們需要的服務(wù),就是我們最常見(jiàn)的Startup.cs的內(nèi)容。
下面,我們先創(chuàng)建Startup.cs,
- namespace demo
- {
- public class Startup
- {
- }
- }
在前邊ConfigureWebHostDefaults中,加入Startup,并補(bǔ)齊代碼:
- class Program
- {
- static void Main(string[] args)
- {
- Host.CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(webBuilder =>
- {
- webBuilder.UseStartup<Startup>();
- })
- .Build()
- .Run();
- }
- }
這就是Program.cs中的完整代碼了。整理一下,就是我們常見(jiàn)的樣子:
- public class Program
- {
- public static void Main(string[] args)
- {
- CreateHostBuilder(args).Build().Run();
- }
- public static IHostBuilder CreateHostBuilder(string[] args) =>
- Host.CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(webBuilder =>
- {
- webBuilder.UseStartup<Startup>();
- });
- }
不過(guò),到這兒還不能正常運(yùn)行,因?yàn)镾tartup.cs現(xiàn)在還是空的。
3. 補(bǔ)齊Startup類(lèi)
Startup類(lèi)在Asp.net Core應(yīng)用中有著重要的作用。這個(gè)類(lèi)用于:
- 使用DI容器注入服務(wù)
- 設(shè)置Http Request管道以插入中間件
下面我們補(bǔ)齊所需的方法:
- namespace demo
- {
- public class Startup
- {
- public void ConfigureServices(IServiceCollection services)
- {
- }
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
- {
- }
- }
- }
運(yùn)行,到這兒,Web應(yīng)用已經(jīng)可以正常啟動(dòng)了。
4. 給應(yīng)用添加路由
Web應(yīng)用啟動(dòng)了,但里面什么也沒(méi)有,是空的。
要訪問(wèn)Web應(yīng)用中的任何資源,需要配置路由。這兒的路由,基本上就是傳入Http請(qǐng)求與資源之間的映射。
我們可以用下面的中間件來(lái)啟動(dòng)路由:
- UseRouting
- UseEndpoints
加一下試試:
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
- {
- app.UseRouting();
- app.UseEndpoints(endpoint => {
- endpoint.MapGet("/", async context =>
- {
- await context.Response.WriteAsync("Hello from Demo");
- });
- });
- }
這次運(yùn)行,瀏覽器中就看到正確的輸出了。
我們可以用MapGet映射更多資源:
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
- {
- app.UseRouting();
- app.UseEndpoints(endpoint =>
- {
- endpoint.MapGet("/", async context =>
- {
- await context.Response.WriteAsync("Hello from Demo");
- });
- endpoint.MapGet("/test", async context =>
- {
- await context.Response.WriteAsync("Hello from Demo.Test");
- });
- endpoint.MapGet("/about", async context =>
- {
- await context.Response.WriteAsync("Hello from Demo.About");
- });
- });
- }
到這兒,我們成功地把Console應(yīng)用轉(zhuǎn)為了Web應(yīng)用。
三、延伸內(nèi)容
上面完成的Web應(yīng)用,算是Web應(yīng)用中的基礎(chǔ)。基于這個(gè)內(nèi)容,我們還可以擴(kuò)展到別的項(xiàng)目結(jié)構(gòu)。
1. 改為MVC應(yīng)用
需要在ConfigureServices中注入AddControllersWithViews,并在Configure中添加MapDefaultControllerRoute:
- public class Startup
- {
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddControllersWithViews();
- }
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
- {
- app.UseRouting();
- app.UseEndpoints(endpoint =>
- {
- endpoint.MapDefaultControllerRoute();
- });
- }
- }
2. 改為WebAPI應(yīng)用
需要注入AddControllers和MapControllers:
- public class Startup
- {
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddControllers();
- }
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
- {
- app.UseRouting();
- app.UseEndpoints(endpoint =>
- {
- endpoint.MapControllers();
- });
- }
- }
3. 改為Razor應(yīng)用
需要注入AddRazorPages和MapRazorPages:
- public class Startup
- {
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddRazorPages();
- }
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
- {
- app.UseRouting();
- app.UseEndpoints(endpoint =>
- {
- endpoint.MapRazorPages();
- });
- }
- }
四、總結(jié)
看下來(lái),其實(shí)過(guò)程很簡(jiǎn)單。通過(guò)這種方式,能更進(jìn)一步理解Dotnet Core的項(xiàng)目結(jié)構(gòu)以及應(yīng)用的運(yùn)行過(guò)程。
希望對(duì)大家能有所幫助。
?
本文的配套代碼在:https://github.com/humornif/Demo-Code/tree/master/0038/demo