因爲ASP.NET Core框架在本質上就是由服務器和中間件構建的消息處理管道,因此在它上面構建的應用開發框架都是創建在某種類型的中間件上,整個ASP.NET Core MVC開發框架就是創建在用來實現路由的EndpointRoutingMiddleware和EndpointMiddleware中間件上。ASP.NET Core MVC利用路由系統爲它分發請求,並在此基礎上實現針對目標Controller的激活、Action方法的選擇和執行,以及最終對於執行結果的響應。在介紹的實例演示中,咱們將對上面建立的ASP.NET Core做進一步改造,使之轉變成一個MVC應用。html
ASP.NET Core框架內置了一個原生的依賴注入框架,該框架利用一個依賴注入容器提供管道在構建以及請求處理過程當中所需的服務,而這些服務須要在應用啓動的時候被預先註冊。對於ASP.NET Core MVC框架來講,它在處理HTTP請求的過程當中所需的一系列服務一樣須要預先註冊。對這個概念有了基本的瞭解以後,相信讀者朋友們對以下所示的代碼就容易理解了。web
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; namespace helloworld { class Program { static void Main() { Host.CreateDefaultBuilder() .ConfigureWebHostDefaults(webHostBuilder => webHostBuilder .ConfigureServices(servicecs => servicecs .AddRouting() .AddControllersWithViews()) .Configure(app => app .UseRouting() .UseEndpoints(endpoints => endpoints.MapControllers()))) .Build() .Run(); } } }
整個ASP.NET MVC框架創建在EndpointRoutingMiddleware和EndpointMiddleware中間件構建的路由系統上,這兩個中間件採用「終結點(Endpoint)映射」的方式實現針對HTTP請求的路由。這裏所謂的終結點能夠視爲應用程序提供的針對HTTP請求的處理器,這兩個終結點經過預先設置的規則將具備某些特徵的請求(好比路徑、HTTP方法等)映射到對應的終結點,進而實現路由的功能。對於一個MVC應用程序來講,咱們能夠將定義在Controller類型中的Action方法視爲一個終結點,那麼路由映射最終體如今HTTP請求與目標Action方法的映射上。編程
如上面的代碼片斷所示,咱們前後調用了IApplicationBuilder接口的UseRouting和UseEndpoints擴展方法註冊了EndpointRoutingMiddleware和EndpointMiddleware中間件。在調用UseEndpoints方法的時候,咱們利用指定的Action<IEndpointRouteBuilder>委託對象調用了IEndpointRouteBuilder接口的MapControllers擴展方法完成了針對定義在Controller類型中全部Action方法的映射。瀏覽器
因爲註冊的中間件具備對其餘服務的依賴,咱們須要預先將這些服務註冊到依賴注入框架中。依賴服務的註冊經過調用IWebHostBuilder的ConfigureServices方法來完成,該方法的參數類型爲Action<IServiceCollection>,添加的服務註冊就保存在IServiceCollection接口表示的集合中。在上面的演示程序中,兩個中間件依賴的服務是經過調用IServiceCollection接口的AddRouting和AddControllersWithViews方法進行註冊的。服務器
以下所示的HelloController是咱們定義的Controller類型。按照約定,全部的Controller類型名稱都應該以「Controller」字符做爲後綴。與以前版本的ASP.NET MVC不一樣,ASP.NET Core MVC下的Controller類型並不要求強制繼承某個基類。咱們在HelloController中定義了一個惟一的Action方法SayHello,該方法直接返回一個內容爲「Hello World」的字符串。app
public class HelloController { [HttpGet("/hello")] public string SayHello() => "Hello World."; }
咱們在Action方法SayHello上經過標註的HttpGetAttribute特性註冊了一個模板爲「/hello」的路由,意味着請求地址爲「/hello」的GET請求最終會被路由到這個Action方法上,而該方法執行的結果將做爲請求的響應內容。因此啓動該程序後使用瀏覽器訪問地址「http://localhost:5000/hello」,咱們依然會獲得以下圖所示的輸出結果。框架
上面這個程序並無涉及視圖,因此算不上一個典型的MVC應用,接下來咱們對它作進一步改造。爲了讓HelloController具備視圖呈現的能力,咱們讓它派生於基類Controller。Action方法SayHello的返回類型被修改成IActionResult接口,它表示Action方法執行的結果。咱們爲該方法定義了一個表示姓名的參數name,經過HttpGetAttribute特性註冊的路由模板(「/hello/{name}」)中具備與之對應的路由參數。換句話說,知足該路徑模式的請求URL攜帶的姓名將自動綁定到該Action方法的name參數上。在SayHello方法中,咱們利用ViewBag將表明姓名的name參數值傳遞給呈現的視圖,該方法最終調用View方法返回當前Action方法對應的ViewResult對象。ide
public class HelloController : Controller { [HttpGet("/hello/{name}")] public IActionResult SayHello(string name) { ViewBag.Name = name; return View(); } }
因爲咱們調用View方法時沒有顯式指定視圖的名稱,因此視圖引擎會將當前Action的名稱(「SayHello」)做爲視圖的名稱。若是該視圖尚未通過編譯(部署時針對View的預編譯,或者在這以前針對該View的動態編譯),視圖引擎將從若干候選的路徑中讀取對應的.cshtml 文件進行編譯,其中首選的路徑爲「{ContentRoot}\Views\{ControllerName}\{ViewName}.cshtml」。爲了迎合視圖引擎定位視圖文件的規則,咱們須要將SayHello對應的視圖文件(SayHello.cshtml)定義在目錄「\Views\Hello\」下。ui
以下所示的就是SayHello.cshtml這個文件的內容,這是一個針對Razor引擎的視圖文件。從文件的擴展名(.cshtml)咱們看出能夠這樣的文件能夠同時包含HTML標籤和C#代碼。總的來講,視圖文件會在服務端生成最終在瀏覽器呈現出來的HTML,咱們能夠在這個文件中直接提供原樣輸出的HTML標籤,也能夠內嵌一段動態執行的C#代碼。雖然Razor引擎對View文件的編寫制定了嚴格的語法,可是我我的以爲沒有必要在Razor語法上花太多的精力,由於Razor語法的目的就是讓咱們很「天然」地將動態C#代碼和靜態HTML標籤結合起來,並最終生成一份完整的HTML文檔,所以它的語法和普通的思惟基本是一致。好比下面這個View最終會生成一個完整的HTML文檔,其主體部分只有一個<p>標籤。該標籤的內容是動態的,由於包含利用ViewBag從Controller傳進來的姓名。spa
<html> <head> <title>Hello World</title> </head> <body> <p>Hello, @ViewBag.Name</p> </body> </html>
再次運行該程序後,咱們利用瀏覽器訪問地址「http://localhost:5000/hello/foobar」。因爲請求地址與Action方法SayHello上的路由規則相匹配,因此路徑攜帶的姓名(foobar)會綁定到該方法的name參數上,因此咱們最終將在瀏覽器上獲得以下圖所示的輸出結果。
任何一個ASP.NET Core應用在初始化的時候都會根據請求處理的需求註冊對應的中間件。在前面演示的實例中,咱們都是直接調用IWebHostBuilder的Configure擴展方法來註冊所需的中間件,可是在大部分真實的開發場景中咱們通常會將中間件以及依賴服務的註冊定義在一個單獨的類型中。按照約定,咱們一般會將這個類型命名爲Startup,好比咱們演示實例中針對服務和中間件的註冊就能夠放在以下定義的這個Startup類中。
public class Startup { public void ConfigureServices(IServiceCollection services) => services .AddRouting() .AddControllersWithViews(); public void Configure(IApplicationBuilder app) => app .UseRouting() .UseEndpoints(endpoints => endpoints.MapControllers()); }
如上面的代碼片斷所示,咱們不須要讓Startup類實現某個預約義的接口或者繼承某個預約義基類,所採用的徹底是一種基於「約定」的定義方式。隨着對ASP.NET Core框架認識的加深,咱們會發現這種「約定優於配置」的設計普遍地應用在整個框架之中。按照約定,服務註冊和中間件註冊分別實如今ConfigureServices和Configure方法中,它們的第一個參數類型分別爲IServiceCollection和IApplicationBuilder接口。因爲已經將兩種核心的操做轉移到了Startup類型中,因此咱們須要註冊該類型。Startup類型能夠調用IWebHostBuilder接口的UseStartup<TStartup>擴展方法進行註冊。
class Program { static void Main() { Host.CreateDefaultBuilder() .ConfigureWebHostDefaults(webHostBuilder => webHostBuilder.UseStartup<Startup>()) .Build() .Run(); } }
咱們在前面的內容中對.NET Core、ASP.NET Core以及ASP.NET Core MVC應用的編程做了初步的體驗,可是這僅僅限於咱們熟悉的Windows平臺。做爲一個號稱跨平臺的開發框架,咱們有必要在其餘操做系統平臺上體驗一下.NET Core開發的樂趣。
[ASP.NET Core 3框架揭祕] 跨平臺開發體驗: Windows [上篇]
[ASP.NET Core 3框架揭祕] 跨平臺開發體驗: Windows [中篇]
[ASP.NET Core 3框架揭祕] 跨平臺開發體驗: Windows [下篇]
[ASP.NET Core 3框架揭祕] 跨平臺開發體驗: Mac OS
[ASP.NET Core 3框架揭祕] 跨平臺開發體驗: Linux
[ASP.NET Core 3框架揭祕] 跨平臺開發體驗: Docker
原文出處:https://www.cnblogs.com/artech/p/inside-asp-net-core-01-03.html