1. 程式人生 > 其它 >第二章:建立你的第一個應用程式(ASP.NET Core in Action)

第二章:建立你的第一個應用程式(ASP.NET Core in Action)

本章要點

  • 建立第一個ASP.NET Core web應用程式
  • 執行應用程式
  • 瞭解應用程式的元件

 讀完第1章後,您應該對ASP.NET Core應用程式的工作原理以及何時使用它們有了大致的瞭解。您還應該設定了一個開發環境,可以用來開始構建應用程式。

提示:有關安裝.NET 5.0 SDK和選擇編輯器/IDE的指南,請參閱附錄A。

在本章中,您將通過建立第一個web應用程式來深入瞭解並感受一下它是如何工作的。在後面的章節中,我將向你展示如何定製和構建自己的應用程式。

在完成本章的工作時,您應該開始掌握構成ASP.NET Core應用程式的各種元件,並瞭解一般應用程式構建過程。您建立的大多數應用程式都將從類似的模板開始,因此儘快熟悉相關設定過程是一個不錯的主意。

定義:模板提供構建應用程式所需的基本程式碼。您可以使用模板作為構建自己應用程式的起點。

我將首先向您展示如何使用Visual Studio模板之一建立基本ASP.NET Core應用程式。如果您使用的是其他工具,如.NET CLI,則可以使用類似的模板。在本章中,我將Visual Studio 2019和ASP.NET Core 5.0與.NET 5.0一起使用,但我也提供了使用.NET CLI的提示。

提示:您可以在本書的GitHub儲存庫中檢視本章的應用程式程式碼,網址為https://github.com/andrewlock/asp-dot-net-core-in-action-2e。

建立應用程式後,我將向您展示如何恢復所有必要的依賴關係、編譯應用程式並執行它以檢視HTML輸出。該應用程式在某些方面很簡單,它只有兩個不同的頁面,但它將是一個完全配置的ASP.NET Core應用程式。

執行完應用程式後,下一步將是瞭解發生了什麼!我們將學習ASP.NET Core應用程式的所有主要部分,瞭解如何配置web伺服器、中介軟體管道和HTML生成等。在這個階段我們將不詳細介紹,但您將瞭解它們是如何協同工作以建立完整的應用程式的。

我們將從開始一個新專案時建立的大量檔案開始,您將瞭解典型的ASP.NET Core應用程式是如何佈局的。特別是,我將重點介紹Program.cs和Startup.cs檔案。實際上,應用程式的整個配置都發生在這兩個檔案中,因此最好了解它們的用途和使用方式。您將看到如何為應用程式定義中介軟體管道,以及如何自定義它。

最後,您將看到應用程式如何響應請求生成HTML,並檢視構成RazorPages端點的每個元件。您將看到它如何控制響應請求執行的程式碼,以及如何定義應為特定請求返回的HTML。

在這個階段,如果你發現專案的某些部分令人困惑或複雜,不要擔心;在閱讀本書時,您將詳細探究每一部分。在本章結束時,您應該基本瞭解ASP.NET Core應用程式是如何組合在一起的,從應用程式首次執行到生成響應。在開始之前,我們將回顧ASP.NET Core應用程式如何處理請求。

 2.1 ASP.NET Core應用程式的簡要概述

在第1章中,我描述了瀏覽器如何向伺服器發出HTTP請求並接收響應,該響應用於在頁面上呈現HTML。ASP.NET Core允許您根據請求的詳細資訊動態生成HTML,因此,例如,您可以根據當前登入的使用者顯示不同的資料。

假設您想建立一個web應用程式來顯示有關您公司的資訊。您可以建立一個簡單的ASP.NET Core應用程式來實現這一點;稍後,您可以嚮應用程式新增動態功能。圖2.1顯示了應用程式如何處理應用程式中的頁面請求。

 圖2.1 ASP.NET Core應用程式概述。ASP.NET Core應用程式從瀏覽器接收傳入的HTTP請求。每個請求都傳遞到中介軟體管道,後者可能會對其進行修改,然後將其傳遞到管道末端的端點中介軟體以生成響應。響應通過中介軟體傳遞迴伺服器,最後傳遞到瀏覽器。

從第1章的圖1.8中,您應該對該圖的大部分內容很熟悉;請求和響應、反向代理和ASP.NET Core web伺服器都仍然存在,但您會注意到我已經擴充套件了ASP.NET Core應用程式本身,以顯示中介軟體管道和端點中介軟體。這是應用程式中用於生成請求響應的主要自定義部分。

反向代理轉發請求後的第一個呼叫埠是ASP.NET Core web伺服器,這是預設的跨平臺Kestrel伺服器。Kestrel接收原始傳入網路請求,並使用它生成一個HttpContext物件,應用程式的其餘部分可以使用該物件。

HttpContext物件
ASP.NET Core web伺服器構建的HttpContext被應用程式用作單個請求的儲存盒。特定於此特定請求和後續響應的任何內容都可以與之關聯並存儲在其中。這可能包括請求的屬性、特定於請求的服務、已載入的資料或發生的錯誤。web伺服器用原始HTTP請求的詳細資訊和其他配置詳細資訊填充初始HttpContext,並將其傳遞給應用程式的其餘部分。

注:Kestrel不是ASP.NET Core中唯一可用的HTTP伺服器,但它是效能最高的,而且是跨平臺的。我只會在全書中提到凱斯特爾。主要替代方案HTTP.sys僅在Windows上執行,不能與IIS一起使用。

 Kestrel負責接收請求資料並構造請求的C#表示,但它不嘗試直接生成響應。為此,Kestrel將HttpContext交給ASP.NET Core應用程式中的中介軟體管道。這是一系列元件,用於處理傳入請求以執行常見操作,如日誌記錄、處理異常或提供靜態檔案。

注意:您將在下一章詳細瞭解中介軟體管道。

中介軟體管道的末端是端點中介軟體。這個中介軟體負責呼叫生成最終響應的程式碼。在大多數應用程式中,將是MVC或RazorPages塊。

RazorPages負責生成構成典型ASP.NET Core web應用程式頁面的HTML。它們通常也是應用程式的大部分業務邏輯所在,呼叫各種服務以響應原始請求中包含的資料。並非每個應用程式都需要MVC或RazorPages塊,但這通常是構建大多數向用戶顯示HTML的應用程式的方式。

注:我將在第4章中介紹RazorPages和MVC控制器,包括如何在它們之間進行選擇。我在第7章和第8章中介紹了生成HTML。

大多數ASP.NET Core應用程式都遵循這個基本架構,本章中的示例也沒有什麼不同。首先,您將看到如何建立和執行應用程式,然後我們將檢視程式碼如何與圖2.1中的大綱相對應。不用再多說,讓我們建立一個應用程式!

2.2 建立第一個ASP.NET Core應用程式

您可以根據所使用的工具和作業系統,以多種不同的方式開始使用ASP.NET Core構建應用程式。每一組工具都有稍微不同的模板,但它們有很多相似之處。本章中使用的示例基於Visual Studio 2019模板,但您可以很容易地使用.NET CLI或Visual Studio for Mac中的模板。

提醒:本章使用Visual Studio 2019和ASP.NET Core 5.0以及.NET 5.0。

啟動和執行應用程式通常涉及四個基本步驟,我們將在本章中介紹這些步驟:

  1. 生成——從模板建立基礎應用程式以開始。
  2. 還原——使用NuGet將所有包和依賴項還原到本地專案資料夾。
  3. 編譯——應用程式並生成所有必要的中間程式碼。
  4. 執行——執行編譯的應用程式。

Visual Studio和.NET CLI包含許多ASP.NET Core模板,用於構建不同型別的應用程式。例如:

  • RazorPages web應用程式-RazorPage應用程式在伺服器上生成HTML,並設計為使用者可以直接在web瀏覽器中檢視。
  • MVC(模型-檢視-控制器)應用程式-MVC應用程式與RazorPages應用程式相似,因為它們在伺服器上生成HTML,並設計為使用者可以直接在web瀏覽器中檢視。他們使用傳統的MVC控制器而不是RazorPages。
  • Web API應用程式Web API應用以可供單頁應用程式(SPA)和API使用的格式返回資料。它們通常與Angular和React.js等客戶端應用程式或移動應用程式結合使用。

 我們將在本書中介紹每種應用程式型別,但在本章中,我們將重點介紹RazorPages模板。

2.2.1 使用模板開始

使用模板可以快速啟動並執行應用程式,自動配置許多基本部分。Visual Studio和.NET CLI都附帶了許多用於構建web應用程式、控制檯應用程式和類庫的標準模板。

提示:在.NET中,專案是一個部署單元,它將被編譯為.dll檔案或可執行檔案。每個單獨的應用程式都是一個單獨的專案。一個解決方案中可以同時構建和開發多個專案。

要建立第一個web應用程式,請開啟Visual Studio並執行以下步驟:

1. 從啟動螢幕中選擇“建立新專案”,或從Visual Studio主螢幕中選擇檔案>新建>專案。
2. 從模板列表中,選擇ASP.NET Core Web Application,確保選擇C#語言模板,如圖2.2所示。單擊Next。

 圖2.2 新專案對話方塊。從右側的列表中選擇C#ASP.NET Core Web應用程式模板。下次建立新專案時,可以從左側的最近模板列表中進行選擇。

3. 在下一個螢幕上,輸入專案名稱、位置和解決方案名稱,然後單擊Create,如圖2.3所示。例如,使用WebApplication1作為專案和解決方案的名稱。

 圖2.3“配置新專案”對話方塊。要建立新的.NET 5.0應用程式,請從模板螢幕中選擇ASP.NET Core Web應用程式。在下面的螢幕上,輸入專案名稱、位置和解決方案名稱,然後單擊“建立”。

4. 在以下螢幕上(圖2.4):
    – 確保已選擇.NET Core。
    – 選擇ASP.NET Core 5.0。如果此選項不可用,請確保已安裝.NET 5.0。有關配置環境的詳細資訊,請參閱附錄A。
    – 選擇ASP.NET Core Web App以建立RazorPages Web應用程式。
    – 確保未指定身份驗證。在第14章中,您將學習如何將使用者新增到應用程式。
    – 確保選中了Configure for HTTPS。
    – 確保未選中“啟用Docker支援”。
    – 單擊“建立”。

 圖2.4 web應用程式模板螢幕。此螢幕位於“配置您的專案”對話方塊之後,允許您自定義將生成應用程式的模板。對於這個初學者專案,您將建立一個沒有身份驗證的RazorPages web應用程式。

5. 等待Visual Studio從模板生成應用程式。Visual Studio完成後,您將看到一個關於ASP.NET Core的介紹頁面,您應該能夠看到Visual Studio已經建立並向您的專案添加了許多檔案,如圖2.5所示。 

 圖2.5 從模板建立新ASP.NET Core應用程式後的Visual Studio。解決方案資源管理器顯示新建立的專案。介紹頁面提供了有關ASP.NET Core的有用連結。

如果未使用Visual Studio,則可以使用.NET CLI建立類似的模板。建立資料夾以儲存新專案。在資料夾(在Windows上)或終端會話(在Linux或macOS上)中開啟PowerShell或cmd提示符,然後執行以下列表中的命令。

Listing 2.1 Creating a new RazorPage application with the .NET CLI

dotnet new sln -n WebApplication1     //Create a solution file called WebApplication1 in the current folder.
dotnet new webapp -o WebApplication1   //Create a RazorPages project in a subfolder, WebApplication1.
dotnet sln add WebApplication1    //Add the new project to the solution file.

無論您使用Visual Studio還是.NET CLI,現在都已具備構建和執行第一個ASP.NET Core應用程式所需的基本檔案。

2.2.2 構建應用程式

此時,您已經擁有執行應用程式所需的大部分檔案,但還剩下兩個步驟。首先,您需要確保將專案使用的所有依賴項複製到本地目錄,其次,您需要編譯應用程式,以便它可以執行。

這些步驟中的第一步並不是絕對必要的,因為Visual Studio和.NET CLI在第一次建立專案時都會自動還原包,但最好了解情況。在2.0之前的.NET CLI早期版本中,您需要使用dotnet還原手動還原包。

您可以通過選擇Build>Build Solution、使用快捷鍵Ctrl-Shift-B或從命令列執行dotnet Build來編譯應用程式。如果您從Visual Studio構建,輸出視窗將顯示構建的進度,並且假設一切都很好,將編譯您的應用程式,準備執行。

您還可以從Visual Studio中的包管理器控制檯執行dotnet構建控制檯命令。

提示:如果Visual Studio和.NET CLI工具檢測到檔案已更改,則在您執行應用程式時,它們將自動構建應用程式,因此您通常不需要自己明確執行此步驟。

NuGet包和.NET命令列介面
.NET 5.0跨平臺開發的基本元件之一是.NET命令列介面(CLI)。這為建立、構建和執行.NET 5.0應用程式提供了幾個基本命令。VisualStudio有效地自動呼叫這些,但如果使用不同的編輯器,也可以直接從命令列呼叫它們。開發過程中最常用的命令是
dotnet restore
dotnet build
dotnet run
這些命令中的每一個都應在專案資料夾中執行,並將單獨對該專案執行。
大多數ASP.NET Core應用程式依賴於各種外部庫,這些庫通過NuGet包管理器進行管理。專案中列出了這些依賴項,但不包括庫本身的檔案。在構建和執行應用程式之前,需要確保專案資料夾中有每個依賴項的本地副本。第一個命令dotnet restore確保將應用程式的NuGet依賴項複製到專案資料夾中。
ASP.NET Core專案在專案的.csproj檔案中列出其依賴項。這是一個XML檔案,將每個依賴項作為PackageReference節點列出。當您執行dotnet還原時,它使用此檔案來確定要下載哪些NuGet包並將其複製到專案資料夾。列出的任何依賴項都可以在應用程式中使用。
還原過程通常在構建或執行應用程式時隱式發生,但有時在連續整合構建管道中顯式執行它會很有用。
您可以使用dotnet build編譯應用程式。這將檢查應用程式中的任何錯誤,如果沒有問題,將生成可以使用dotnet執行的輸出。
每個命令都包含許多可以修改其行為的開關。要檢視可用命令的完整列表,請執行
dotnet --help
或檢視特定命令的可用選項,例如,執行
dotnet new --help

2.3 執行web應用程式

 您已經準備好執行第一個應用程式,有許多不同的方法可以實現。在Visual Studio中,您可以單擊IIS Express旁邊工具欄上的綠色箭頭,也可以按F5快捷鍵。Visual Studio將使用適當的URL自動為您開啟一個web瀏覽器視窗,一兩秒鐘後,您將看到全新的應用程式,如圖2.6所示。或者,您可以使用dotnet run從命令列使用.NET CLI工具執行應用程式,並在web瀏覽器中手動開啟URL,使用命令列上提供的地址。

 圖2.6新ASP.NET Core應用程式的主頁。當您從Visual Studio執行它時,預設情況下,IIS Express會選擇一個隨機埠。如果您從命令列執行dotnet run,您的應用程式將在http://localhost:5000和https://localhost:5001.

 提示:首次從Visual Studio執行應用程式時,將提示您安裝開發證書。這樣做可以確保您的瀏覽器不會顯示有關無效證書的警告。2有關HTTPS證書的更多資訊,請參閱第18章。(您可以在Windows和macOS上安裝開發證書。有關在Linux上信任證書的說明,請參閱發行版的說明。並非所有瀏覽器(例如Mozilla Firefox)都使用證書儲存,因此請遵循瀏覽器信任證書的指南。如果您仍有困難,請參閱http://mng.bz/1rmy.)

 預設情況下,此頁面顯示一個簡單的歡迎橫幅和指向ASP.NET Core官方Microsoft文件的連結。頁面頂部有兩個連結:主頁和隱私。Home連結是您當前所在的頁面。單擊Privacy將轉到一個新頁面,如圖2.7所示。不久您將看到,您可以在應用程式中使用RazorPages來定義這兩個頁面並構建它們顯示的HTML。

  圖2.7 應用程式的Privacy頁面。您可以使用應用程式標題中的Home和Privacy連結在應用程式的兩個頁面之間導航。該應用程式使用RazorPages生成頁面內容。

在這一點上,你需要注意一些事情。首先,包含連結和應用程式標題“WebApplication1”的標題在兩個頁面上是相同的。第二,頁面的標題(如瀏覽器的選項卡中所示)將更改以匹配當前頁面。在第7章中,當我們討論使用Razor模板對HTML進行排序時,您將看到如何實現這些功能。

注:您只能在當前執行該應用程式的同一臺計算機上檢視該應用程式;您的應用程式尚未暴露在網際網路上。您將在第16章中學習如何釋出和部署應用程式。

在這個階段,應用程式的使用者體驗沒有任何變化。單擊一下,一旦你對應用程式的行為感到滿意,捲起袖子,是時候看看一些程式碼了!

2.4 瞭解專案佈局

當您剛接觸框架時,從這樣的模板建立應用程式可能是一件喜憂參半的事情。一方面,您可以快速啟動並執行應用程式,而無需輸入任何資訊。相反,檔案的數量有時會讓人應接不暇,讓你絞盡腦汁想從哪裡開始。基本的web應用程式模板不包含大量的檔案和資料夾,如圖2.8所示,但我將詳細介紹主要的模板,以使您瞭解方向。

 圖2.8 新ASP.NET Core應用程式的解決方案瀏覽器和磁碟上的資料夾。解決方案資源管理器還顯示“連線的服務”和“依賴項”節點,其中列出了NuGet和其他依賴項,儘管磁碟上不存在資料夾本身。

首先要注意的是,主專案WebApplication1巢狀在具有解決方案名稱的頂層目錄中,在本例中也是WebApplication1。在這個頂級資料夾中,您還可以找到Visual Studio使用的解決方案(.sln)檔案以及與Git版本控制相關的檔案,儘管這些檔案隱藏在Visual Studio的解決方案資源管理器檢視中。

注意:Visual Studio使用解決方案的概念來處理多個專案。示例解決方案僅由.sln檔案中列出的單個專案組成。如果使用CLI模板建立專案,則不會有.sln或Git檔案,除非使用其他.NET CLI模板顯式生成它們。

在解決方案資料夾中,您將找到專案資料夾,該資料夾依次包含三個子資料夾Pages、Properties和wwwroot。Pages(毫不奇怪)包含用於構建應用程式的RazorPages檔案。Properties資料夾包含一個檔案launchSettings.json,它控制Visual Studio如何執行和除錯應用程式。wwwroot資料夾很特殊,因為它是應用程式中唯一允許瀏覽器在瀏覽web應用程式時直接訪問的資料夾。您可以將CSS、JavaScript、影象或靜態HTML檔案儲存在此處,瀏覽器將能夠訪問它們。他們將無法訪問wwwroot之外的任何檔案。

雖然wwwroot和Properties資料夾存在於磁碟上,但您可以看到Solution Explorer將它們顯示為特殊節點,按字母順序排列,位於專案頂部附近。專案中還有兩個特殊節點,即Dependencies和Connected Services,但它們在磁碟上沒有相應的資料夾。相反,它們顯示了專案所依賴的所有依賴項的集合,例如NuGet包和遠端服務。

在專案資料夾的根目錄中,您將找到兩個JSON檔案:appsettings.json和appsettings.Development.json。這些提供了在執行時用於控制應用程式行為的配置設定。

專案中最重要的檔案是WebApplication1.csproj,因為它描述瞭如何構建專案。Visual Studio沒有顯式顯示.csproj檔案,但如果在解決方案資源管理器中雙擊專案名稱,則可以對其進行編輯。我們將在下一節中詳細瞭解這個專案檔案。

最後,Visual Studio在專案資料夾Program.cs和Startup.cs中顯示了兩個C#檔案。在第2.6節和第2.7節中,您將看到這些基本類如何負責配置和執行應用程式。

2.5 .csproj專案檔案:定義依賴項

.csproj檔案是.NET應用程式的專案檔案,包含.NET工具構建專案所需的詳細資訊。它定義了正在構建的專案型別(web應用程式、控制檯應用程式或庫)、專案目標平臺(.NET Core 3.1、.NET 5.0等)以及專案所依賴的NuGet包。

該專案檔案一直是.NET應用程式的主流,但在ASP.NET Core中,它進行了一次改版,使其更易於閱讀和編輯。這些變化包括

  • No GUID——以前,全域性唯一識別符號(GUID)用於許多事情,但現在很少在專案檔案中使用。
  • Implicit file includes——以前,專案中的每個檔案都必須列在.csproj檔案中,才能包含在構建中。現在,檔案被自動編譯。
  • No paths to NuGet package .dll files——以前,您必須在.csproj中包含NuGet包中包含的.dll檔案的路徑,並在包中列出depen-dencies。配置檔案。現在,您可以直接在.csproj中引用NuGet包,而不需要指定磁碟上的路徑。

所有這些更改結合在一起,使專案檔案比以前的.NET專案更加緊湊。下面的列表顯示了示例應用程式的整個.csproj檔案。

Listing 2.2 The .csproj project file, showing SDK, target framework, and references    
<Project Sdk="Microsoft.NET.Sdk.Web">    //The SDK attribute specifies the type of project you’re building.
    <PropertyGroup>
        <TargetFramework>net5.0</TargetFramework>
    </PropertyGroup>
</Project>    //The TargetFramework is the framework you’ll run on, in this case, .NET 5.0.

 對於簡單的應用程式,您可能不需要太多地更改專案檔案。Project元素上的Sdk屬性包括描述如何構建專案的預設設定,而TargetFramework元素描述應用程式將在其上執行的框架。對於.NET Core 3.1專案,這將具有netcore-app3.1值;如果您在.NET 5.0上執行,則這將是net5.0。

提示:使用新的csproj樣式,Visual Studio使用者可以在解決方案資源管理器中雙擊專案以編輯.csproj檔案,而無需先關閉專案。

您將對專案檔案進行的最常見更改是使用PackageReference元素新增其他NuGet包。預設情況下,您的應用程式根本不引用任何NuGet包。

在專案中使用NuGet庫
儘管所有應用程式在某些方面都是獨一無二的,但它們也有共同的需求。例如,大多數應用程式需要訪問資料庫或為格式化資料處理JSON或XML。您應該使用現有的可重用庫,而不是在每個專案中重新建立程式碼。
NuGet是.NET的庫包管理器,其中庫被打包到NuGet包中併發布到https://nuget.org.通過引用.csproj檔案中的唯一包名,可以在專案中使用這些包。這些使包的名稱空間和類在程式碼檔案中可用。您可以將NuGet包釋出(並託管)到儲存庫,而不是https://nuget.org-參見https://docs.microsoft.com/nuget詳細資訊。
通過在專案資料夾中執行dotnet add package<packagename>,可以將NuGet引用新增到專案中。這將使用<PackageReference>節點更新專案檔案,並恢復專案的NuGet包。例如,安裝流行的Newtonsoft。Json圖書館,你會執行
dotnet add package Newtonsoft.Json
這將向專案檔案中新增對庫的最新版本的引用,如下圖所示,並使Newtonsoft。Json名稱空間在原始碼檔案中可用。
<Project Sdk=“Microsoft.NET.Sdk.Web”>
    <PropertyGroup>
        <TargetFramework>netcoreapp3.1</TargetFramework>
    </PropertyGroup>
    <ItemGroup>
        <PackageReference Include=“NewtonSoft.Json”版本=“12.0.3”/>
    </ItemGroup>
<Project>
如果您使用的是Visual Studio,則可以通過右鍵單擊解決方案名稱或專案並選擇“管理NuGet包”來使用NuGet包管理器管理包。
有趣的是,NuGet的發音沒有得到官方認可。歡迎使用流行的“noo-get”或“掘金”風格,或者如果你覺得特別時髦,“noo-jay”!

與以前的版本相比,簡化的專案檔案格式更易於手動編輯,如果您是跨平臺開發,這是非常好的。但如果您使用的是Visual Studio,則不必走這條路。您仍然可以使用GUI新增專案引用、排除檔案、管理NuGet包等。Visual Studio將一如既往地更新專案檔案本身。

提示:有關csproj格式更改的更多詳細資訊,請參閱http://mng.bz/PPGg.

專案檔案定義了Visual Studio和.NET CLI構建應用程式所需的一切。一切都是,除了程式碼!在下一節中,我們將檢視ASP.NET Core應用程式的入口點Program.cs類。

2.6 Program類:構建web主機

所有ASP.NET Core應用程式的啟動方式與.NET控制檯應用程式相同-使用Program.cs檔案。該檔案包含一個靜態void Main函式,這是控制檯應用程式的標準特性。此方法必須存在,並在啟動web應用程式時呼叫。

提示:.NET 5.0和C#9引入了“頂級語句”,它隱式地建立了Main入口點。我在本書中沒有使用頂級語句,但ASP.NET Core 5.0支援它們。有關詳細資訊,請參閱文件:http://mng.bz/JDaP.

在ASP.NET Core應用程式中,Main入口點用於構建和執行IHost例項,如以下列表所示,其中顯示了預設的Program.cs檔案。IHost是ASP.NET Core應用程式的核心,包含應用程式配置和偵聽請求併發送響應的Kestrel伺服器。

清單2.3 預設Program.cs檔案配置並執行IWebHost

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args)    //使用CreateHostBuilder方法建立IHostBuilder。
        .Build()    //從IHostBuilder生成並返回IHost的例項。
        .Run();     //執行IHost並開始偵聽請求並生成
    }
    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)    //使用預設配置建立IHostBuilder。
            .ConfigureWebHostDefaults(webBuilder =>    //配置應用程式以使用Kestrel並偵聽HTTP請求。
            {
                webBuilder.UseStartup<Startup>();      //Startup類定義了應用程式的大部分配置。
            };
    }
}

 Main函式包含建立web伺服器和開始偵聽請求所需的所有基本初始化程式碼。它使用通過呼叫CreateDefaultBuilder建立的IHostBuilder來定義如何配置IHost,然後通過呼叫Build()來例項化IHost。

注意:您會發現這種使用構建器物件來配置複雜物件的模式在ASP.NET Core框架中重複出現。這是一種有用的技術,允許使用者配置物件,將其建立延遲到所有配置完成。這是Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides(Addison Wesley,1994)在“Gang of Four”一書《Design Patterns: Elements of Reusable Object-Oriented Software》中描述的模式之一。

應用程式的大部分配置都是在呼叫CreateDefaultBuilder建立的IHostBuilder中進行的,但它將一些責任委託給了一個單獨的類Startup。通用UseStartup<>方法中引用的Startup類是配置應用程式服務和定義中介軟體管道的地方。在第2.7節中,我們將花一段時間深入研究這一關鍵課程。

此時,您可能想知道為什麼需要兩個類進行配置:Program和Startup。為什麼不在一個類或另一個類中包含應用程式的所有配置?

圖2.9顯示了Program和Startup之間配置元件的典型劃分。一般來說,Program是配置應用程式基礎結構的地方,例如HTTP伺服器、與IIS的整合以及配置源。相反,Startup是定義應用程式使用的元件和功能以及應用程式的中介軟體管道的地方。

圖2.9 Program和Startup配置範圍的差異。專案關注的是在整個專案生命週期內通常保持穩定的基礎設施配置。相反,您通常會修改Startup以新增新功能並更新應用程式行為。

兩個不同ASP.NET Core應用程式的Program類通常是相似的,但Startup類通常會有很大的不同(儘管它們通常遵循相似的模式,稍後您將看到)。您很少會發現,隨著應用程式的增長,您需要修改Program,而您通常會在新增其他功能時更新Startup。例如,如果您在專案中添加了新的NuGet依賴項,通常需要更新Startup以利用它。

Program類是進行大量應用程式配置的地方,但在預設模板中,這隱藏在CreateDefaultBuilder方法中。CreateDefaultBuilder是一個靜態幫助器方法,它通過使用一些常見配置建立IHostBuilder來簡化應用程式的引導。在第11章中,我們將深入瞭解此方法並探索配置系統,但現在只需記住圖2.9,並注意如果需要,您可以完全更改IHost配置。

預設情況下使用的另一個Helper方法是ConfigureWebHostDefaults。這使用WebHostBuilder物件來配置Kestrel以偵聽HTTP請求。

使用通用主機建立服務
您必須同時呼叫ConfigureWebHostDefaults和CreateDefaultBuilder,這可能看起來很奇怪。難道我們只有一個方法嗎?處理HTTP請求不是ASP.NET Core的全部目的嗎?
好吧,是的,也不是!ASP.NET Core 3.0引入了通用主機的概念。這允許您使用與ASP.NET Core應用程式相同的框架來編寫非HTTP應用程式。例如,這些應用程式可以作為控制檯應用程式執行,也可以作為Windows服務(或作為Linux上的systemd守護程式)安裝,以執行後臺任務或從訊息佇列讀取。
Kestrel和ASP.NET Core的web框架建立在ASP.NET Core 3.0中引入的通用主機功能之上。要配置典型的ASP.NET Core應用程式,您需要配置所有應用程式通用的通用主機特性;配置、日誌記錄和依賴服務等功能。對於web應用程式,您還可以配置處理web請求所需的服務,如Kestrel。
在第22章中,您將看到如何使用通用主機構建應用程式以執行計劃任務和構建服務。

一旦IHostBuilder的配置完成,對Build的呼叫將生成IHost例項,但應用程式仍然沒有處理HTTP請求。呼叫Run啟動HTTP伺服器偵聽。此時,您的應用程式已完全執行,可以響應來自遠端瀏覽器的第一個請求。

2.7 Startup類:配置應用程式

正如您所看到的,Program負責為您的應用程式配置許多基礎設施,但您需要在Startup中配置一些應用程式的行為。Startup類負責配置應用程式的兩個主要方面:

  • 服務註冊——所有應用程式依賴的類(包括提供框架使用的功能和特定於應用程式的功能)都必須註冊,以便在執行時正確例項化。
  • 中介軟體和端點——應用程式如何處理和響應請求。

您可以在Startup中使用自己的方法配置每個方面:ConfigureServices中的服務註冊,configure中的中介軟體配置。啟動的典型概要如下所示。

清單2.4  Startup.cs的概要,顯示如何配置每個方面

public class Startup
{
    public void ConfigureServices(IServiceCollection services)    //通過向IServiceCollection註冊服務來配置服務。
    {
        // method details
    }
    public void Configure(IApplicationBuilder app)    //配置用於處理HTTP請求的中介軟體管道。
    {
        // method details
    }
}

Program中建立的IHostBuilder呼叫ConfigureServices,然後呼叫Configure,如圖2.10所示。每個呼叫配置應用程式的不同部分,使其可用於後續方法呼叫。ConfigureServices方法中註冊的任何服務都可用於Configure方法。配置完成後,通過呼叫IHostBuilder上的Build()來建立IHost。 

圖2.10  IHostBuilder在Program.cs中建立,並在啟動時呼叫方法來配置應用程式的服務和中介軟體管道。配置完成後,通過呼叫IHostBuilder上的Build()來建立IHost。

Startup類的一個有趣之處是它沒有實現這樣的介面。相反,通過使用反射來呼叫這些方法,以查詢具有預定義名稱Configure和ConfigureServices的方法。這使類更加靈活,並允許您修改方法的簽名以接受自動實現的其他引數。我將在第10章中詳細介紹這是如何工作的;現在,只要知道ConfigureServices中配置的任何內容都可以通過Configure方法訪問就足夠了。

定義:.NET中的反射允許您在執行時獲取有關應用程式中型別的資訊。您可以使用反射在執行時建立類的例項,並呼叫和訪問它們。

因為Startup類是ASP.NET Core應用程式的基礎,所以第2.7節的其餘部分將指導您完成ConfigureServices和Configure,讓您瞭解如何使用它們。我不會詳細解釋它們(我們有本書的其餘部分!),但是您應該記住它們是如何相互繼承的,以及它們對整個應用程式配置的貢獻。

2.7.1 新增和配置服務

ASP.NET Core為每個不同的功能使用小型模組化元件。這允許單獨的功能單獨發展,只與其他功能鬆散耦合,通常認為這是良好的設計實踐。這種方法的缺點是,它給功能的使用者帶來了正確例項化功能的負擔。在應用程式中,這些模組化元件作為應用程式使用的一個或多個服務公開。

定義:在ASP.NET Core的上下文中,服務是指為應用程式提供功能的任何類。這些可能是您為應用程式編寫的庫或程式碼所公開的類。

例如,在電子商務應用程式中,您可能有一個TaxCalculator,它可以計算特定產品的應納稅額,同時考慮使用者在世界上的位置。或者您可能有一個ShippingCostService,它計算運送到使用者所在地的成本。第三個服務OrderTotalCalculatorService可能使用這兩個服務來計算使用者必須為訂單支付的總價。每個服務都提供一小部分獨立的功能,但您可以將它們組合起來建立一個完整的應用程式。這就是所謂的單一責任原則。

定義:單一責任原則(SRP)規定,每個類只應負責一部分功能,只有在所需功能發生變化時才需要更改。這是Robert C.Martin在《Agile Software Development, Principles, Patterns, and Practices》(Pearson,2013)中提出的五項主要設計原則之一。

OrderTotalCalculatorService需要訪問ShippingCostService和TaxCalculator的例項。解決這個問題的一種簡單方法是使用新關鍵字,並在需要時建立服務例項。不幸的是,這將您的程式碼與您正在使用的特定實現緊密結合,並可能會完全取消通過模組化功能實現的所有良好工作。在某些情況下,執行您建立的服務的初始化程式碼也可能破壞SRP。

解決這個問題的一個方法是讓它成為別人的問題。在編寫服務時,您可以宣告依賴項,並讓另一個類為您填充這些依賴項。然後,您的服務可以專注於它所設計的功能,而不是試圖找出如何構建其依賴關係。

他的技術被稱為依賴注入或控制反轉(IoC)原理,這是一種被廣泛使用的公認的設計模式。

定義:設計模式是常見軟體設計問題的解決方案。

通常,您會將應用程式的依賴項註冊到“容器”中,然後可以使用該容器建立任何服務。這對於您自己的自定義應用程式服務和ASP.NET Core使用的框架服務都是如此。您必須在容器中註冊每個服務,然後才能在應用程式中使用它。

注:我將在第10章詳細描述ASP.NET Core中使用的依賴反轉原理和IoC容器。

在ASP.NET Core應用程式中,此註冊是在ConfigureServices方法中執行的。每當您在應用程式中使用新的ASP.NET Core功能時,都需要返回此方法並新增必要的服務。這並不像聽起來那麼困難,如下面的列表(取自示例應用程式)所示。

清單2.5 Startup.ConfigureServices:向IoC容器新增服務

public class Startup
{
    // This method gets called by the runtime.
    // Use this method to add services to the container. 
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
    }
}

您可能會驚訝於,一個完整的Razor Pages應用程式只包含一個新增必要服務的呼叫,但AddRazorPage()方法是一個擴充套件方法,它封裝了設定Razor Pages服務所需的所有程式碼。在幕後,它添加了各種Razor服務,用於呈現HTML、格式化服務、路由服務等。 

除了註冊與框架相關的服務之外,此方法還可以註冊應用程式中的任何自定義服務,例如前面討論的示例TaxCalculator。IServiceCollection是應用程式需要使用的所有已知服務的列表。通過向其中新增新服務,可以確保每當類宣告對服務的依賴時,IoC容器都知道如何提供它。

所有服務都已配置完畢,現在是時候進入最後一個配置步驟了:定義應用程式如何響應HTTP請求。

2.7.2 定義如何使用中介軟體處理請求

到目前為止,在IHostBuilder和Startup類中,您已經定義了應用程式的基礎結構,並向IoC容器註冊了服務。在Startup類的最後一個配置方法Configure中,您為應用程式定義中介軟體管道,該管道定義應用程式如何處理HTTP請求。下面是模板應用程式的Configure方法。

清單2.6 Startup.Configure:定義中介軟體管道

public class Startup
{
    //IApplicationBuilder用於構建中介軟體管道。可以接受其他服務作為引數。
    public void Configure( IApplicationBuilder app, IWebHostEnvironment env)
    {
        //開發或生產時的不同行為
        if (env.IsDevelopment())
        {
            //僅在開發環境中執行
            app.UseDeveloperExceptionPage();
        }
        else
        {
            //僅在生產環境中執行
            app.UseExceptionHandler("/Error"); app.UseHsts();
        }
        app.UseHttpsRedirection(); 
        //新增靜態檔案中介軟體
        app.UseStaticFiles(); 
        //新增端點路由中介軟體,該中介軟體決定要執行哪個端點
        app.UseRouting();   
        //新增授權中介軟體,它可以根據需要阻止對特定頁面的訪問
        app.UseAuthorization();
        //新增端點中介軟體,該中介軟體執行RazorPage以生成HTML響應
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
        }
    }
}

如前所述,中介軟體由小元件組成,當應用程式接收到HTTP請求時,這些元件按順序執行。它們可以執行一整套功能,例如日誌記錄、識別請求的當前使用者、提供靜態檔案和處理錯誤。

傳遞給Configure方法的IApplicationBuilder用於定義中介軟體的執行順序。此方法中呼叫的順序很重要,因為它們新增到生成器的順序就是它們在最終管道中執行的順序。中介軟體只能在管道中使用以前的中介軟體建立的物件,而不能訪問後來的中介軟體所建立的物件。

警告:在將中介軟體新增到管道中時,務必考慮中介軟體的順序。中介軟體只能使用管道中早期中介軟體建立的物件。

您還應該注意,IWebHostEnvironment引數用於在開發環境中提供不同的行為。當您在開發中執行時(當EnvironmentName設定為“development”時),Configure方法將一個異常處理中介軟體新增到管道中;在生產中,它添加了一個不同的。

IWebHostEnvironment物件包含由程式中的IHostBuilder確定的當前環境的詳細資訊。它公開了許多屬性:

  • ContentRootPath——應用程式的工作目錄的位置,通常是執行應用程式的資料夾
  • WebRootPath——包含靜態檔案的wwwroot資料夾的位置
  • EnvironmentName——當前環境是開發環境還是生產環境

IWebHostEnvironment在呼叫Startup時已設定;無法使用“Startup”中的應用程式設定更改這些值。EnvironmentName通常在應用程式啟動時使用環境變數從外部設定。

注:您將在第11章中瞭解託管環境以及如何更改當前環境。

在開發中,DeveloperExceptionPageMiddleware(由UseDeveloperExcessionPage()呼叫新增)確保如果應用程式丟擲未捕獲的異常,瀏覽器中會顯示儘可能多的資訊來診斷問題,如圖2.11所示,但這次是白色的,不是黃色的。

圖2.11開發人員異常頁面包含許多不同的資訊源以幫助您診斷問題,包括異常堆疊跟蹤和生成異常的請求的詳細資訊。

注意:預設模板也會在生產中新增HstsMiddleware,它會根據行業最佳實踐在響應中設定安全標頭。請參閱第18章,瞭解有關此和其他安全相關中介軟體的詳細資訊。

當您在生產環境中執行時,將大量資料暴露給使用者將是一個巨大的安全風險。相反,ExceptionHandlerMiddleware是註冊的,這樣,如果使用者在您的方法中遇到異常,將向他們顯示一個友好的錯誤頁面,該頁面不會顯示問題的來源。如果在生產模式下執行預設模板並觸發錯誤,則將顯示圖2.12所示的訊息。顯然,您需要更新此頁面以使其更具視覺吸引力和使用者友好,但至少它不會揭示應用程式的內部工作方式。

新增到管道中的下一個中介軟體是HttpsDirectionMiddleware,使用以下語句:

app.UseHttpsRedirection();

這確保您的應用程式只響應安全(HTTPS)請求,是行業最佳做法。我們將在第18章中詳細介紹HTTPS。

圖2.12 預設異常處理頁面。與開發人員異常頁面不同的是,此頁面不會向用戶透露任何有關應用程式的詳細資訊。事實上,您可以將訊息更新為更方便使用者的內容。

StaticFileMiddleware將新增到管道中,接下來是以下語句:

app.UseStaticFiles();

他的中介軟體負責處理靜態檔案(如CSS檔案、JavaScript檔案和影象)的請求。當請求到達中介軟體時,它會檢查該請求是否針對現有檔案。如果是,中介軟體將返回檔案。如果沒有,則忽略該請求,下一個中介軟體可以嘗試處理該請求。圖2.13顯示了在請求靜態檔案時如何處理請求。當靜態檔案中介軟體處理請求時,管道中稍後出現的其他中介軟體(如路由中介軟體或端點中介軟體)根本不會被呼叫。

圖2.13 /css/site上的靜態檔案請求概述。css用於ASP.NET Core應用程式。請求通過中介軟體管道,直到由靜態檔案中介軟體處理。這將返回請求的CSS檔案作為響應,並將其傳遞迴web伺服器。端點中介軟體從未被呼叫,也從未看到請求。

現在,我們來看看管道中最重要的中介軟體:路由中介軟體和端點中介軟體。這對中介軟體一起負責解釋請求以確定要呼叫哪個Razor Page,從請求中讀取引數,並生成最終的HTML。需要非常簡單的配置,您只需要將中介軟體新增到管道中,並通過呼叫MapRazorPages指定您希望使用Razor Page端點。對於每個請求,路由中介軟體使用請求的URL來確定要呼叫哪個Razor Page。端點中介軟體實際上執行Razor Page以生成HTML響應。

注意:預設模板還將在路由中介軟體和端點中介軟體之間新增AuthorizationMiddleware。這允許身份驗證中介軟體在執行RazorPage之前決定是否允許訪問。您將在關於路由的第5章和關於授權的第15章中瞭解有關此方法的更多資訊。

哈哈!您終於完成了應用程式所需的所有設定、服務和中介軟體的配置。配置應用程式涉及廣泛的不同主題,我們將在本書中進一步深入討論,因此如果您還沒有完全理解所有步驟,請不要擔心。

一旦配置了應用程式,它就可以開始處理請求。但它是如何處理它們的?我已經提到了StaticFileMiddleware,它將向用戶提供影象和CSS檔案,但是需要HTML響應的請求呢?在本章的其餘部分,我將向您介紹Razor Pages及其如何生成HTML。

2.8 使用Razor Pages生成響應

當ASP.NET Core應用程式收到請求時,它通過中介軟體管道前進,直到中介軟體元件能夠處理它,如圖2.13所示。通常,管道中的最後一塊中介軟體是端點中介軟體。該中介軟體與路由中介軟體一起工作,以將請求URL的路徑匹配到已配置的路由,該路由定義要呼叫哪個Razor Page。

定義刪除域後,路徑是請求URL的剩餘部分。例如,對於傳送到www.microsoft.com/account/manage的請求,路徑為/account/manage。

一旦選擇了Razor Page,路由中介軟體就會在請求的HttpContext中記錄所選的Razor Page,並繼續執行中介軟體管道。最終,請求將到達端點中介軟體。端點中介軟體執行Razor Page以生成HTML響應並將其傳送回瀏覽器,如圖2.14所示。

圖2.14 將Razor模板渲染為HTML。Razo rPage是基於URL頁面/Privacy選擇的,並被執行以生成HTML。

在下一節中,我們將研究Razor Pages如何使用Razor語法生成HTML。之後,我們將研究如何使用頁面處理程式將業務邏輯和行為新增到Razor Pages。

2.8.1 使用Razor Page生成HTML

Razor Pages儲存在專案Pages資料夾中的.cshtml檔案(.cs和.html的組合)中。通常,路由中介軟體通過在專案的Pages資料夾中查詢具有相同路徑的Razor Page,將請求URL路徑對映到單個RazorPage。例如,您可以在圖2.14中看到,應用程式的Privacy頁面對應於瀏覽器位址列中的路徑/Privacy。如果您檢視專案的Pages資料夾,您會發現Privacy.cshtml檔案,如以下列表所示。

清單2.7 Privacy.cshtml Razor頁面

@page    // 指示這是RazorPage
@model PrivacyModel    // 將Razor Page連結到特定的PageModel
@{
    ViewData["Title"] = "Privacy Policy";    // 不寫入響應的C#程式碼
}
<h1>@ViewData["Title"]</h1>    //將動態C#值寫入響應的HTML
<p>Use this page to detail your site's privacy policy.</p>    //獨立的靜態HTML

Razor Pages使用名為Razor的模板語法,將靜態HTML與動態C#程式碼和HTML生成相結合。Razor Page第一行的@page指令是最重要的。該指令必須始終放在檔案的第一行,因為它告訴ASP.NET Core .cshtml檔案是RazorPage。如果沒有它,您將無法正確檢視頁面。

Razor Page的下一行定義了Razor Page與專案中的哪個PageModel關聯:

@model PrivacyModel

在這種情況下,PageModel被稱為PrivacyModel,它遵循命名Razor Page模型的標準慣例。您可以在Privacy.cshtml中找到該檔案,如圖2.15所示。Visual Studio將這些檔案巢狀在Solution Explorer中的RazorPage.cshtml檔案下面。我們將在下一節中檢視頁面模型。

圖2.15按照慣例,Razor Pages的頁面模型放置在與RazorPage同名的檔案中,並附加.cs字尾。Visual Studio將這些檔案巢狀在解決方案資源管理器中的Razor Page下。

除了@page和@model指令之外,您可以看到靜態HTML在RazorPage中始終有效,並將在響應中“原樣”呈現。

<p>Use this page to detail your site’s privacy policy.</p>

您還可以使用以下構造在Razor模板中編寫普通的C#程式碼:

@{ /* C# code here */ }

大括號之間的任何程式碼都將被執行,但不會寫入響應。在列表中,您通過向ViewData字典寫入關鍵字來設定頁面標題,但此時沒有向響應寫入任何內容:

@{
    ViewData["Title"] = "Privacy Policy";
}

此模板中顯示的另一個特性是,您可以使用@符號將C#變數動態寫入HTML流。這種結合動態和靜態標記的能力正是Razor Pages的強大之處。在本例中,您從ViewData字典中獲取“Title”值,並將這些值寫入<h1>標記中的響應:

<h1>@ViewData["Title"]</h1>

此時,當與圖2.14所示的輸出進行比較時,您可能會對清單2.7中的模板感到有點困惑。列表和圖中都顯示了標題和靜態HTML內容,但最終網頁的某些部分沒有顯示在模板中。這怎麼可能?

Razor Pages具有佈局的概念,它是定義應用程式常見元素(如頁首和頁尾)的“基本”模板。佈局的HTML與RazorPage模板相結合,生成傳送到瀏覽器的最終HTML。這防止了您必須在每個頁面中複製頁首和頁尾的程式碼,這意味著,如果您需要調整某些內容,您只需要在一個位置進行調整。

注:我將在第7章詳細介紹Razor模板,包括佈局。您可以在專案的Pages/Shared資料夾中找到佈局。

正如您已經看到的,您可以通過使用花括號@{}在RazorPages中包含C#程式碼,但一般來說,您希望將.cshtml檔案中的程式碼僅限於顯示內容。複雜的邏輯、訪問服務(如資料庫)的程式碼和資料操作應該在PageModel中處理。

2.8.2 使用PageModel和處理程式處理請求邏輯

正如您已經看到的,.cshtml檔案中的@page指令將頁面標記為Razor Page,但大多數Razor Pages也有關聯的頁面模型。按照慣例,這被放置在一個通常稱為“程式碼隱藏”檔案的檔案中,該檔案具有.cs副檔名,如圖2.15所示。頁面模型應該派生自PageModel基類,它們通常包含一個或多個稱為頁面處理程式的方法,這些方法定義如何處理對Razor Page的請求。

定義:頁面處理程式是響應請求而執行的方法。Razor Page模型必須從PageModel類派生。它們可以包含多個頁面處理程式,但通常只包含一個或兩個。

下面的列表顯示了Privacy.cshtml RazorPage的頁面模型,位於檔案Privacy.cshtml.cs中。

清單2.8 Privacy中的PrivacyModel.cshtmlcs——RazorPage頁面模型

//RazorPages必須繼承自PageModel。
public class PrivacyModel: PageModel
{
    private readonly ILogger<PrivacyModel> _logger; 
    //可以使用依賴注入在建構函式中提供服務。
    public PrivacyModel(ILogger<PrivacyModel> logger)
    {
        _logger = logger;
    }
    //預設的頁面處理程式是OnGet。返回void表示應生成HTML。
    public void OnGet()
    {
    }
}

這個頁面模型非常簡單,但它展示了幾個重要的點:

  • 頁面處理程式由約定驅動。
  • 頁面模型可以使用依賴注入與其他服務互動。

頁面處理程式通常根據其響應的HTTP謂詞按慣例命名。它們返回void(表示應呈現Razor Page的模板)或IActionResult(包含生成響應的其他指令,例如將使用者重定向到其他頁面)。

定義:每個HTTP請求都包含一個表示請求“型別”的動詞。瀏覽網站時,預設動詞是GET,它從伺服器獲取資源,以便您檢視。第二個最常見的動詞是POST,它用於向伺服器傳送資料,例如在完成表單時。

PrivacyModel包含一個處理程式OnGet,該處理程式指示它應該響應頁面的GET請求而執行。當方法返回void時,執行處理程式將為頁面執行關聯的Razor模板以生成HTML。

注意:Razor Pages專注於構建基於頁面的應用程式,因此您通常希望返回HTML而不是JSON或XML。但是,您也可以使用IActionResult返回任何型別的資料,將使用者重定向到新頁面,或傳送錯誤。您將在第4章中瞭解有關IActionResults的更多資訊。

依賴注入用於將ILogger<PrivacyModel>例項注入到頁面模型的建構函式中。此示例中未使用該服務,但它可以用於將有用資訊記錄到各種目的地,例如控制檯、檔案或遠端日誌記錄服務。您可以通過在建構函式中接受其他服務作為引數來訪問頁面模型中的其他服務。ASP.NET Core框架將負責配置和注入您請求的任何服務的例項。

注:我在第10章詳細描述了ASP.NET Core中使用的依賴性反轉原理和IoC容器。第17章介紹了日誌記錄。

顯然,PrivacyModel頁面模型在這種情況下做不了什麼,您可能會想為什麼值得擁有它。如果他們所做的只是告訴Razor Page生成HTML,那麼我們為什麼需要頁面模型呢?

這裡要記住的關鍵點是,您現在有了一個框架,可以響應請求執行任意複雜的功能。您可以很容易地更新handler方法以從資料庫載入資料、傳送電子郵件、將產品新增到購物籃或建立發票,所有這些都是響應簡單的HTTP請求。這種可擴充套件性是Razor Pages(以及MVC模式)的強大之處。

另一個重要的點是,您將這些方法的執行與HTML本身的生成分離開來。如果邏輯發生變化,並且需要向頁面處理程式新增行為,則不需要修改HTML生成程式碼,因此不太可能引入錯誤。相反,如果需要稍微更改UI,例如更改標題的顏色,則處理程式方法邏輯是安全的。

這就是一個完整的ASP.NET Core Razor Pages應用程式!在繼續之前,讓我們最後看一下應用程式如何處理請求。圖2.16顯示了示例應用程式正在處理的對/隱私路徑的請求。您已經看到了這裡的所有內容,因此處理請求的過程應該很熟悉。它顯示了請求在被端點中介軟體處理之前如何通過中介軟體管道。Privacy.cshtml RazorPage執行OnGet處理程式並生成HTML響應,該響應在傳送到使用者瀏覽器之前通過中介軟體傳遞迴ASP.NET Core web伺服器。

這是一次非常緊張的旅程,但現在您可以很好地瞭解整個應用程式是如何配置的,以及它如何使用RazorPages處理請求。在下一章中,您將進一步瞭解所有ASP.NET Core應用程式中存在的中介軟體管道。您將瞭解它是如何組成的,如何使用它為應用程式新增功能,以及如何使用它建立簡單的HTTP服務。

圖2.16示例ASP.NET RazorPages應用程式的/Privacy URL請求概述。路由中介軟體將請求路由到Privacy.cshtml.cs RazorPage的OnGet處理程式。RazorPage通過在Privacy.cshtml中執行Razor模板生成HTML響應,並通過中介軟體管道將響應傳遞迴瀏覽器。

總結

  • .csproj檔案包含如何構建專案的詳細資訊,包括它所依賴的NuGet包。Visual Studio和.NET CLI使用它來構建應用程式。
  • 恢復ASP.NET Core應用程式的NuGet包將下載專案的所有依賴項,以便可以構建和執行。
  • Programcs定義應用程式的靜態void Main入口點。此功能在應用程式啟動時執行,與控制檯應用程式相同。
  • Programcs是使用IHostBuilder構建IHost例項的地方。助手方法HostCreateDefaultBuilder()建立一個IHostBuilder,用於載入配置設定並設定日誌記錄。呼叫Build()將建立IHost例項。
  • ConfigureWebHostDefaults擴充套件方法使用WebHostBuilder配置通用主機。它配置Kestrel HTTP伺服器,必要時新增IIS整合,並指定應用程式的Startup類。
  • 您可以通過在IHost上呼叫Run來啟動web伺服器並開始接受HTTP請求。
  • Startup負責服務配置和定義中介軟體管道。
  • 所有服務(包括框架服務和自定義應用程式服務)必須在ConfigureServices呼叫中註冊,以便稍後在應用程式中訪問。
  • 中介軟體通過IApplicationBuilder新增到應用程式管道中。中介軟體定義應用程式如何響應請求。
  • 中介軟體的註冊順序定義了應用程式中介軟體管道的最終順序。通常,EndpointMiddleware是管道中的最後一箇中間件。早期的中介軟體,如StaticFileMiddle-ware,將嘗試首先處理請求。如果處理了請求,EndpointMiddleware將永遠不會接收到請求。
  • Razor Pages位於Pages資料夾中,通常根據其處理的URL路徑命名。例如,Privacy.cshtml處理路徑/Privacy。
  • Razor Pages必須包含@page指令作為檔案的第一行。
  • 頁面模型派生自PageModel基類幷包含頁面處理程式。頁面處理程式是使用指示其處理的HTTP謂詞的約定命名的方法。例如,OnGet處理GET動詞。
  • Razor模板可以包含獨立的C#、獨立的HTML和從C#值生成的動態HTML。通過將這三者結合起來,您可以構建高度動態的應用程式。
  • Razor佈局定義網頁的常見元素,如頁首和頁尾。它們允許您將此程式碼提取到一個檔案中,因此您不必在每個Razor模板中複製它。