- ASP.NET Core 教程
- ASP.NET Core - 首頁
- ASP.NET Core - 概述
- ASP.NET Core - 環境設定
- ASP.NET Core - 新建專案
- ASP.NET Core - 專案佈局
- ASP.NET Core - Project.Json
- ASP.NET Core - 配置
- ASP.NET Core - 中介軟體
- ASP.NET Core - 異常
- ASP.NET Core - 靜態檔案
- ASP.NET Core - 設定 MVC
- ASP.NET Core - MVC 設計模式
- ASP.NET Core - 路由
- ASP.NET Core - 屬性路由
- ASP.NET Core - 操作結果
- ASP.NET Core - 檢視
- 設定 Entity Framework
- ASP.NET Core - DBContext
- ASP.NET Core - Razor 佈局檢視
- ASP.NET Core - Razor 檢視啟動
- ASP.NET Core - Razor 檢視匯入
- ASP.NET Core - Razor 標籤助手
- ASP.NET Core - Razor 編輯表單
- ASP.NET Core - 身份概述
- ASP.NET Core - 授權屬性
- 身份配置
- ASP.NET Core - 身份遷移
- ASP.NET Core - 使用者註冊
- ASP.NET Core - 建立使用者
- ASP.NET Core - 登入和登出
- ASP.NET Core 有用資源
- ASP.NET Core - 快速指南
- ASP.NET Core - 有用資源
- ASP.NET Core - 討論
ASP.NET Core - 快速指南
ASP.NET Core - 概述
ASP.NET Core 是微軟的新一代 Web 框架。它從頭開始進行了重新設計,旨在快速、靈活、現代,並在不同平臺上執行。展望未來,ASP.NET Core 是可以用於使用 .NET 進行 Web 開發的框架。如果您在過去幾年中對 MVC 或 Web API 有任何經驗,您會注意到一些熟悉的功能。在本教程結束時,您將擁有開始使用 ASP.NET Core 並編寫應用程式所需的一切,該應用程式可以建立、編輯和檢視資料庫中的資料。
ASP.NET 簡史
多年來,ASP.NET 一直用於開發 Web 應用程式。從那時起,該框架經歷了穩定的演變,最終導致了其最新的後代 ASP.NET Core 1.0。
ASP.NET Core 1.0 不是 ASP.NET 4.6 的延續。
它是一個全新的框架,一個並排的專案,可以與我們知道的所有其他內容愉快地共存。
它是當前 ASP.NET 4.6 框架的實際重寫,但更小且模組化程度更高。
有些人認為很多東西保持不變,但這並非完全正確。ASP.NET Core 1.0 對 ASP.NET 格局是一個重大的根本性變化。
什麼是 ASP.NET Core
ASP.NET Core 是一個開源且針對雲進行最佳化的 Web 框架,用於開發可在 Windows、Linux 和 Mac 上開發和執行的現代 Web 應用程式。它包括 MVC 框架,該框架現在將 MVC 和 Web API 的功能組合到一個 Web 程式設計框架中。
ASP.NET Core 應用程式可以在 .NET Core 或完整的 .NET Framework 上執行。
它的架構旨在為部署到雲或在本地執行的應用程式提供最佳化的開發框架。
它由具有最少開銷的模組化元件組成,因此您在構建解決方案時可以保留靈活性。
您可以在 Windows、Mac 和 Linux 上跨平臺開發和執行您的 ASP.NET Core 應用程式。
ASP.NET Core 的優勢
ASP.NET Core 具有以下優勢 -
ASP.NET Core 進行了許多架構更改,從而產生了更精簡且模組化的框架。
ASP.NET Core 不再基於 System.Web.dll。它基於一組粒度細化且經過良好分解的 NuGet 包。
這使您可以最佳化您的應用程式,使其僅包含您需要的 NuGet 包。
較小的應用程式表面積的好處包括更嚴格的安全、減少服務、改進的效能和降低的成本
使用 ASP.NET Core,您可以獲得以下改進 -
在 Windows、Mac 和 Linux 上構建和執行跨平臺 ASP.NET 應用程式。
構建在 .NET Core 上,支援真正的並排應用程式版本控制。
簡化現代 Web 開發的新工具。
用於 Web UI 和 Web API 的單個對齊 Web 堆疊。
基於雲就緒的環境配置。
內建支援依賴項注入。
標籤助手使 Razor 標記與 HTML 更加自然。
能夠在 IIS 上託管或在您自己的程序中進行自託管。
ASP.NET Core - 環境設定
ASP.NET Core 是 ASP.NET 的重大重新設計。本主題介紹了 ASP.NET Core 中的新概念,並解釋了它們如何幫助您開發現代 Web 應用程式。
要在您的應用程式中使用 ASP.NET Core,必須在您的系統中安裝以下內容 -
- Microsoft Visual Studio 2015
- Microsoft .NET Core 1.0.0 - VS 2015 工具預覽版 2
Microsoft 提供 Visual Studio 的免費版本,其中還包含 SQL Server,可以從 www.visualstudio.com/en-us/downloads/downloadvisual-studio-vs.aspx 下載,並且 Microsoft .NET Core 1.0.0 - VS 2015 工具預覽版 2 可以從 https://go.microsoft.com/fwlink/?LinkId=817245. 下載。
Microsoft Visual Studio 2015 的安裝
現在讓我們瞭解安裝中涉及的步驟
步驟 1 - 下載完成後,執行安裝程式。將顯示以下對話方塊。
步驟 2 - 單擊上面的螢幕截圖中的“安裝”按鈕。然後安裝過程將開始。
步驟 3 - 安裝過程成功完成後,您將看到以下對話方塊。
步驟 4 - 關閉此對話方塊,並在需要時重新啟動計算機。
步驟 5 - 從“開始”選單開啟 Visual Studio。這將開啟以下對話方塊,並且第一次需要一些時間(僅用於準備)。
步驟 6 - 現在您將看到 Visual Studio 的主視窗。
步驟 7 - 安裝 Visual Studio 後,關閉 Visual Studio 並啟動 Microsoft .NET Core 1.0.0 - VS 2015 工具預覽版 2。
步驟 8 - 選中複選框並單擊“安裝”。
步驟 9 - 安裝完成後,您將看到以下訊息。
步驟 10 - 現在您可以使用 ASP.NET Core 開始您的應用程式了。
ASP.NET Core - 新建專案
在本章中,我們將討論如何在 Visual Studio 中建立新專案。
安裝 Visual Studio 2015 工具後,您可以從檔案→新建專案選單選項開始構建新的 ASP.NET Core 應用程式。
在“新建專案”對話方塊中,您將看到以下三個不同的 Web 專案模板 -
ASP.NET Web 應用程式 - 簡單 ASP.NET 應用程式模板。
ASP.NET Core Web 應用程式 (.NET Core) - 這將使用可在 .NET Core 框架上執行的跨平臺相容專案啟動您。
ASP.NET Core Web 應用程式 (.NET Framework) - 這將在 Windows 上的標準 .NET Framework 上啟動一個新專案。
在左側窗格中,選擇模板→Visual C#→Web,在中間窗格中選擇 ASP.NET Core Web 應用程式 (.NET Core) 模板。讓我們將此應用程式稱為FirstAppDemo,併為您的 ASP.NET Core 專案指定位置,然後單擊“確定”。
在上面的對話方塊中,您可以從可用的 ASP.NET Core 模板中選擇 ASP.NET 應用程式的特定模板。
ASP.NET Core 模板當前包含三個不同的模板。其中,Web 應用程式模板將幫助您在檔案系統上佈置大量檔案。這還允許您立即使用 ASP.NET MVC。
在這裡,我們將從空模板開始。這將幫助我們從頭開始構建它。讓我們選擇“空”模板,關閉“在雲中託管”並單擊“確定”。
Visual Studio 現在將在一段時間後啟動專案。在“解決方案資源管理器”視窗中,您將看到此專案中的所有檔案。
讓我們執行此應用程式,您可以透過按 Ctrl+F5 或轉到“除錯”選單來執行此操作。轉到“除錯”選單後,選擇“不除錯啟動”。
此應用程式只能顯示“Hello World!”。它在localhost:57741上執行。在視窗系統托盤中,您還可以看到 IIS Express 正在執行。
並且站點的名稱為FirstAppDemo。如果您之前使用過 ASP.NET 框架的早期版本進行程式設計,那麼您與 Visual Studio 的互動方式以及 Visual Studio 使用 IIS Express 託管應用程式的方式,所有這些方面都將很熟悉。
ASP.NET Core - 專案佈局
在本章中,我們將討論 ASP.NET Core 專案在檔案系統上的顯示方式以及不同的檔案和目錄如何協同工作。
讓我們開啟上一章中建立的FirstAppDemo專案。
在“解決方案資源管理器”視窗中,右鍵單擊“解決方案”節點,然後選擇“在檔案資源管理器中開啟資料夾”。
您現在將看到根目錄中包含兩個檔案:FirstAppDemo.sln 和global.json。
FirstAppDemo.sln 是一個解決方案檔案。Visual Studio 多年來一直預設使用此副檔名,如果您想在 Studio 中開啟應用程式並對其進行操作,可以雙擊該檔案。
還有一個global.json檔案。讓我們在 Visual Studio 中開啟此檔案。
在檔案中,專案的設定非常重要。此專案設定告訴 ASP.NET 在哪裡查詢您的原始碼以及哪些資料夾包含您的專案。
有兩個可能的資料夾“src”用於原始碼和“test”資料夾。除非您的專案和原始碼位於這兩個資料夾之一中,否則程式碼將不可用於構建。如果需要,您可以更改這些設定。
Windows 資源管理器在磁碟上具有“src”資料夾。您沒有測試資料夾。在測試資料夾中,您可以放置單元測試專案。讓我們雙擊“src”資料夾。
您可以看到 FirstAppDemo 專案和 Web 應用程式。現在,雙擊該資料夾。
這些是應用程式的原始碼檔案,您也可以在“解決方案資源管理器”視窗中看到此資料夾結構。這是因為在當前版本的 ASP.NET Core 中,檔案系統決定了專案中的內容。
如果向磁碟新增新檔案,則該檔案將新增到專案中。如果刪除檔案,則該檔案將從專案中刪除。所有內容都保持同步,這與早期版本的 ASP.NET Core 略有不同,在早期版本中,專案檔案(一個 *.cs proj 檔案)包含專案中所有內容的清單。
ASP.NET Core 還會在檔案更改或出現新檔案時編譯應用程式。
示例
讓我們透過在文字編輯器中開啟 **Startup.cs** 檔案來看一個簡單的示例。
正是這行程式碼響應了對應用程式的每個 HTTP 請求,並且它只是響應“Hello World!”。
讓我們更改上面截圖中的字串,將其改為“**Hello World! This ASP.NET Core Application**”,如下面的程式所示。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace FirstAppDemo {
public class Startup {
// This method gets called by the runtime.
// Use this method to add services to the container.
// For more information on how to configure your application,
// visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services) {
}
// This method gets called by the runtime.
// Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app,
IHostingEnvironment env, ILoggerFactory loggerFactory) {
loggerFactory.AddConsole();
if (env.IsDevelopment()){
app.UseDeveloperExceptionPage();
}
app.Run(async (context) => {
await context.Response.WriteAsync(
"Hello World! This ASP.NET Core Application");
});
}
}
}
在文字編輯器中按 Ctrl + S 儲存此檔案,然後返回到 Web 瀏覽器並重新整理應用程式。
您現在可以看到您的更改已反映在瀏覽器中。
這是因為 ASP.NET 將監視檔案系統並在檔案更改時自動重新編譯應用程式。您無需在 Visual Studio 中顯式構建應用程式。
事實上,您可以使用完全不同的編輯器,例如 Visual Studio Code。
您需要使用 Visual Studio 做的就是透過執行(不使用偵錯程式)啟動 Web 伺服器。您也可以按 Ctrl + F5,並可以編輯檔案、儲存檔案,然後只需重新整理瀏覽器即可檢視更改。
這是一種使用像 C# 這樣的編譯語言構建 Web 應用程式的不錯的工作流程。
ASP.NET Core - Project.Json
在本章中,我們將討論 **project.json** 檔案。此檔案使用 JavaScript 物件表示法來儲存配置資訊,它確實是 .NET 應用程式的核心。如果沒有此檔案,您將沒有 ASP.NET Core 專案。在這裡,我們將討論此檔案的一些最重要的功能。讓我們雙擊 **project.json** 檔案。
目前,project.json 檔案中的預設程式碼實現如下:
{
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.0.0",
"type": "platform"
},
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0"
},
"tools": {
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"
},
"frameworks": {
"netcoreapp1.0": {
"imports": ["dotnet5.6", "portable-net45+win8"]
}
},
"buildOptions": {
"emitEntryPoint": true,
"preserveCompilationContext": true
},
"runtimeOptions": {
"configProperties": {
"System.GC.Server": true
}
},
"publishOptions": {
"include": ["wwwroot", "web.config" ]
},
"scripts": {
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath%
--framework %publish:FullTargetFramework%" ]
}
}
如我們所見,我們在該檔案的頂部有版本資訊。這是您在構建應用程式時將使用的版本號。
版本為 1.0.0,但此檔案最重要的部分是依賴項。
如果您的應用程式要執行任何有用的工作,那麼您將需要庫和框架來完成這項工作,例如將資料儲存到資料庫或從資料庫檢索資料,或呈現複雜的 HTML。
在此版本的 ASP.NET Core 中,所有依賴項都透過 NuGet 包管理器進行管理。
NuGet 已經在 .NET 領域存在了幾年,但現在管理所有依賴項的主要方式是使用作為 NuGet 包封裝的庫和框架。
應用程式需要的所有頂級 NuGet 包都將儲存在此 project.json 檔案中。
"Microsoft.AspNetCore.Diagnostics": "1.0.0", "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", "Microsoft.AspNetCore.Server.Kestrel": "1.0.0", "Microsoft.Extensions.Logging.Console": "1.0.0
您可以看到我們在該檔案中有一些依賴項,並且確切的依賴項可能會在 ASP.NET 的最終版本中發生變化。當您想要新增新的依賴項(例如 ASP.NET MVC 框架)時,您可以輕鬆地在此 project.json 檔案中鍵入,您還將獲得一些 **IntelliSense** 幫助,包括不僅包名稱而且版本號,如下面的螢幕截圖所示。
您也可以使用 UI,方法是右鍵單擊解決方案資源管理器中的“引用”,然後選擇“管理 NuGet 包”。您現在可以看到當前安裝的包。
這些包與 project.json 檔案中的包相同,您也可以轉到瀏覽器並新增其他包,包括預釋出包,例如,將 MVC 框架安裝到此專案中。
如果您現在使用“安裝”按鈕安裝此包,則此包將儲存在 project.json 中。“框架”部分是 project.json 的另一個重要部分,此部分告訴 ASP.NET 您的應用程式可以使用哪些 .NET 框架。
"frameworks": {
"netcoreapp1.0": {
"imports": [
"dotnet5.6",
"portable-net45+win8"
]
}
},
在這種情況下,您將看到“**netcoreapp1.0**”是專案中使用的框架,您還可以包含在安裝 Visual Studio 時安裝的完整 .NET Framework。
它與安裝 Windows 作業系統的許多版本時包含的 .NET Framework 相同。
它是已經存在 15 年的 .NET Framework,它包含從 Web 程式設計到桌面程式設計的所有功能的框架。
這是一個龐大的框架,只能在 Windows 上執行。
“**netcoreapp1.0**”是 .NET Core 框架。它是一個跨平臺框架,可以在各種平臺上執行,不僅包括 Windows,還包括 OS X 和 Linux。
此框架的功能少於完整的 .NET Framework,但它確實具有我們進行 ASP.NET Core Web 開發所需的所有功能。
ASP.NET Core - 配置
在本章中,我們將討論與 ASP.NET Core 專案相關的配置。在解決方案資源管理器中,您將看到 Startup.cs 檔案。如果您使用過早期版本的 ASP.NET Core,您可能希望看到 global.asax 檔案,該檔案是可以在其中編寫程式碼以在 Web 應用程式啟動期間執行的一個位置。
您還希望看到一個 web.config 檔案,其中包含應用程式執行所需的所有配置引數。
在 ASP.NET Core 中,這些檔案都消失了,取而代之的是從 Startup.cs 載入配置和啟動程式碼。
檔案中有一個 Startup 類,在此類中,您可以配置應用程式,甚至可以配置配置源。
以下是 **Startup.cs 檔案**中的預設實現。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace FirstAppDemo {
public class Startup {
// This method gets called by the runtime.
// Use this method to add services to the container.
// For more information on how to configure your application,
// visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services) {
}
// This method gets called by the runtime. Use this method to configure
// the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory) {
loggerFactory.AddConsole();
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
}
app.Run(async (context) => {
await context.Response.WriteAsync("Hello World!");
});
}
}
}
在 Startup 類中,有兩個方法是大多數工作將發生的地方。類的 Configure 方法是構建 HTTP 處理管道的所在。
這定義了應用程式如何響應請求。目前,此應用程式只能顯示“Hello World!”,如果我們希望應用程式的行為有所不同,則需要透過在此 Configure 方法中新增其他程式碼來更改管道。
例如,如果我們想要提供靜態檔案(例如 index.html 檔案),則需要在 Configure 方法中新增一些程式碼。
您還可以擁有錯誤頁面或將請求路由到 ASP.NET MVC 控制器;這兩種情況都需要在此 Configure 方法中進行一些工作。
在 Startup 類中,您還將看到 **ConfigureServices()** 方法。這有助於您為應用程式配置元件。
現在,我們為每個響應都使用了硬編碼字串——“**Hello World**!”字串。我們不希望硬編碼字串,而是希望從知道我們要顯示的文字的某個元件載入此字串。
此其他元件可能會從資料庫、Web 服務或 JSON 檔案載入該文字,確切位置並不重要。
我們只需要設定一個場景,以便我們沒有這個硬編碼字串。
在解決方案資源管理器中,右鍵單擊專案節點,然後選擇“新增”→“新建項”。
在左側窗格中,選擇“已安裝”→“程式碼”,然後在中間窗格中,選擇 JSON 檔案。將此檔案命名為 **AppSettings.json**,然後單擊“新增”按鈕,如上圖所示。
我們還可以讓程式從檔案中讀取文字,而不是在 Startup.cs 中使用“Hello World!”字串。讓我們在 **AppSettings.json 檔案**中新增以下程式碼。
{
"message": "Hello, World! this message is from configuration file..."
}
現在我們需要從 Startup.cs 檔案訪問此訊息。以下是將從 JSON 檔案讀取上述訊息的 **Startup.cs** 檔案的實現。
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
namespace FirstAppDemo {
public class Startup {
public Startup() {
var builder = new ConfigurationBuilder()
.AddJsonFile("AppSettings.json");
Configuration = builder.Build();
}
public IConfiguration Configuration { get; set; }
// This method gets called by the runtime.
// Use this method to add services to the container.
// For more information on how to configure your application,
// visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services) {
}
// This method gets called by the runtime.
// Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app) {
app.UseIISPlatformHandler();
app.Run(async (context) => {
var msg = Configuration["message"];
await context.Response.WriteAsync(msg);
});
}
// Entry point for the application.
public static void Main(string[] args) =7gt; WebApplication.Run<Startup>(args);
}
}
現在讓我們執行應用程式。執行應用程式後,它將產生以下輸出。
ASP.NET Core - 中介軟體
在本章中,我們將瞭解如何設定中介軟體。ASP.NET Core 中的中介軟體控制我們的應用程式如何響應 HTTP 請求。它還可以控制應用程式在發生錯誤時的外觀,並且是我們如何對使用者進行身份驗證和授權以執行特定操作的關鍵部分。
中介軟體是軟體元件,這些元件組裝到應用程式管道中以處理請求和響應。
每個元件都會選擇是否將請求傳遞到管道中的下一個元件,並且可以在呼叫管道中的下一個元件之前和之後執行某些操作。
請求委託用於構建請求管道。請求委託處理每個 HTTP 請求。
ASP.NET Core 中的每個中介軟體都是一個物件,並且每個中介軟體都具有非常具體、集中和有限的作用。
最終,我們需要許多中介軟體才能使應用程式正常執行。
現在讓我們假設我們希望將有關每個請求的資訊記錄到我們的應用程式中。
在這種情況下,我們可能安裝到應用程式中的第一個中介軟體是一個日誌記錄元件。
此記錄器可以檢視有關傳入請求的所有資訊,但記錄器很可能只是記錄一些資訊,然後將此請求傳遞給下一個中介軟體。
中介軟體是此處理管道中的一系列元件。
我們安裝到應用程式中的下一個中介軟體是授權器。
授權器可能正在 HTTP 標頭中查詢特定的 Cookie 或訪問令牌。
如果授權器找到令牌,則允許請求繼續。否則,授權器本身可能會使用 HTTP 錯誤程式碼或重定向程式碼響應請求,以將使用者傳送到登入頁面。
但是,否則,授權器會將請求傳遞給下一個中介軟體,即路由器。
路由器檢視 URL 並確定您的下一步操作。
路由器檢視應用程式以查詢要響應的內容,如果路由器找不到要響應的內容,則路由器本身可能會返回 **404 未找到錯誤**。
示例
現在讓我們舉一個簡單的例子來進一步瞭解中介軟體。我們使用 **Startup 類**的 Configure 方法在 ASP.NET 中設定中介軟體。
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
namespace FirstAppDemo {
public class Startup {
public Startup() {
var builder = new ConfigurationBuilder()
.AddJsonFile("AppSettings.json");
Configuration = builder.Build();
}
public IConfiguration Configuration { get; set; }
// This method gets called by the runtime.
// Use this method to add services to the container.
// For more information on how to configure your application,
// visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services) {
}
// This method gets called by the runtime.
// Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app) {
app.UseIISPlatformHandler();
app.Run(async (context) => {
var msg = Configuration["message"];
await context.Response.WriteAsync(msg);
});
}
// Entry point for the application.
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}
}
在 **Configure()** 方法內部,我們將對 IApplicationBuilder 介面上的擴充套件方法進行呼叫以新增中介軟體。
預設情況下,一個新的空專案中包含兩個中介軟體:
- IISPlatformHandler
- 使用 app.Run 註冊的中介軟體
IISPlatformHandler
IISPlatformHandler 允許我們使用 Windows 身份驗證。它會檢視每個傳入請求,並檢查是否有任何與該請求關聯的 Windows 身份資訊,然後呼叫下一個中介軟體。
使用 app.Run 註冊的中介軟體
在本例中,下一個中介軟體是使用 app.Run 註冊的中介軟體。Run 方法允許我們傳入另一個方法,我們可以用它來處理每個響應。Run 不是我們經常見到的,它被稱為終端中介軟體。
使用 Run 註冊的中介軟體將永遠沒有機會呼叫另一箇中間件,它只接收請求,然後必須生成某種響應。
您還可以訪問 Response 物件,並且可以使用 Response 物件來寫入字串。
如果您想在 app.Run 之後註冊另一箇中間件,則該中介軟體將永遠不會被呼叫,因為,同樣,Run 是一個終端中介軟體。它永遠不會呼叫下一個中介軟體。
如何新增另一箇中間件
讓我們按照以下步驟新增另一箇中間件:
步驟 1 - 要新增另一箇中間件,請右鍵單擊專案並選擇“管理 NuGet 包”。
步驟 2 - 搜尋 Microsoft.aspnet.diagnostics,它實際上是用於異常處理、異常顯示頁面和診斷資訊的 ASP.NET Core 中介軟體。此特定包包含我們可以使用的許多不同的中介軟體。
步驟 3 - 如果您的專案中未安裝該包,請安裝它。
步驟 4 - 現在讓我們轉到 Configure() 方法並呼叫 app.UseWelcomePage 中介軟體。
// This method gets called by the runtime.
// Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app) {
app.UseIISPlatformHandler();
app.UseWelcomePage();
app.Run(async (context) => {
var msg = Configuration["message"];
await context.Response.WriteAsync(msg);
});
}
步驟 5 - 執行您的應用程式,您將看到以下歡迎螢幕。
此歡迎螢幕可能不是很有用。
步驟 6 - 讓我們嘗試一些可能更有用的東西。我們將使用 RuntimeInfoPage 而不是使用歡迎頁面。
// This method gets called by the runtime.
// Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app) {
app.UseIISPlatformHandler();
app.UseRuntimeInfoPage();
app.Run(async (context) => {
var msg = Configuration["message"];
await context.Response.WriteAsync(msg);
});
}
步驟 7 - 儲存您的 Startup.cs 頁面並重新整理瀏覽器,您將看到以下頁面。
此 RuntimeInfoPage 是一箇中間件,它只會響應針對特定 URL 的請求。如果傳入請求與該 URL 不匹配,則此中介軟體只會讓請求傳遞到下一個中介軟體。請求將透過 IISPlatformHandler 中介軟體,然後轉到 UseRuntimeInfoPage 中介軟體。它不會建立響應,因此它將轉到我們的 app.Run 並顯示字串。
步驟 8 - 讓我們在 URL 的末尾新增“/runtimeinfo”。您現在將看到由該執行時資訊頁面中介軟體生成的頁面。
您現在將看到一個響應,該響應提供了一些關於您的執行時環境的資訊,例如作業系統、執行時版本、體系結構、型別以及您正在使用的所有包等。
ASP.NET Core - 異常
在本章中,我們將討論異常和錯誤處理。當您的 ASP.NET Core 應用程式中發生錯誤時,您可以透過多種方式處理它們。讓我們看看診斷包中提供的另一箇中間件。此中介軟體將幫助我們處理錯誤。
為了模擬錯誤,讓我們轉到 app.Run 並檢視如果我們每次點選此中介軟體時都丟擲異常,應用程式的行為如何。
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
namespace FirstAppDemo {
public class Startup {
public Startup() {
var builder = new ConfigurationBuilder()
.AddJsonFile("AppSettings.json");
Configuration = builder.Build();
}
public IConfiguration Configuration { get; set; }
// This method gets called by the runtime.
// Use this method to add services to the container.
// For more information on how to configure your application,
// visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services) {
}
// This method gets called by the runtime.
// Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app) {
app.UseIISPlatformHandler();
app.UseRuntimeInfoPage();
app.Run(async (context) => {
throw new System.Exception("Throw Exception");
var msg = Configuration["message"];
await context.Response.WriteAsync(msg);
});
}
// Entry point for the application.
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}
}
它只會丟擲一個帶有非常通用訊息的異常。儲存 Startup.cs 頁面並執行您的應用程式。
您將看到我們無法載入此資源。出現了一個 HTTP 500 錯誤,一個內部伺服器錯誤,這並沒有什麼幫助。獲取一些異常資訊可能會更好。
讓我們新增另一箇中間件,即 UseDeveloperExceptionPage。
// This method gets called by the runtime.
// Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app) {
app.UseIISPlatformHandler();
app.UseDeveloperExceptionPage();
app.UseRuntimeInfoPage();
app.Run(async (context) => {
throw new System.Exception("Throw Exception");
var msg = Configuration["message"];
await context.Response.WriteAsync(msg);
});
}
此中介軟體與其他中介軟體略有不同,其他中介軟體通常會檢視傳入請求並對該請求做出一些決定。
UseDeveloperExceptionPage 不太關心傳入請求,而關心管道中稍後發生的事情。
它將呼叫下一個中介軟體,但隨後它將等待檢視管道中稍後是否有任何內容生成異常,如果存在異常,則此中介軟體將為您提供一個錯誤頁面,其中包含有關該異常的其他資訊。
現在讓我們再次執行應用程式。它將生成如下螢幕截圖所示的輸出。
現在,您將看到一些在開發中出現錯誤時預期的資訊。您還將獲得堆疊跟蹤,並且可以看到在 Startup.cs 的第 37 行丟擲了一個未處理的異常。
您還可以看到原始異常詳細資訊,所有這些資訊對開發人員都非常有用。實際上,我們可能只想在開發人員執行應用程式時顯示此資訊。
ASP.NET Core - 靜態檔案
在本章中,我們將學習如何處理檔案。幾乎每個 Web 應用程式都需要的一個重要功能是從檔案系統提供檔案(靜態檔案)。
靜態檔案(如 JavaScript 檔案、影像、CSS 檔案)是我們檔案系統上儲存的資產,ASP.NET Core 應用程式可以直接將其提供給客戶端。
靜態檔案通常位於 Web 根目錄 (wwwroot) 資料夾中。
預設情況下,這是我們唯一可以直接從檔案系統提供檔案的位置。
示例
現在讓我們舉一個簡單的例子,在這個例子中,我們將瞭解如何在我們的應用程式中提供這些檔案。
在這裡,我們想向我們的 FirstAppDemo 應用程式新增一個簡單的 HTML 檔案,並且此 HTML 檔案必須進入 Web 根目錄 (wwwroot) 資料夾。在解決方案資源管理器中右鍵單擊 wwwroot 資料夾,然後選擇新增→新建項。
在中間窗格中,選擇HTML 頁面並將其命名為index.html,然後單擊新增按鈕。
您將看到一個簡單的index.html檔案。讓我們新增一些簡單的文字和標題,如下所示。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Welcome to ASP.NET Core</title>
</head>
<body>
Hello, Wolrd! this message is from our first static HTML file.
</body>
</html>
當您執行應用程式並在瀏覽器中轉到index.html時,您會看到app.Run中介軟體丟擲一個異常,因為當前我們的應用程式中沒有任何內容。
沒有中介軟體會去查詢檔案系統上的任何檔案以提供服務。要解決此問題,請透過右鍵單擊解決方案資源管理器中的專案並選擇管理 NuGet 包來轉到NuGet 包管理器。
搜尋Microsoft.AspNet.StaticFiles,它將找到靜態檔案中介軟體。讓我們安裝此 nuget 包,現在我們應該有其他方法可以在 Configure 方法中使用來註冊中介軟體。
讓我們在 Configure 方法中新增UseStaticFiles中介軟體,如下面的程式所示。
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
namespace FirstAppDemo {
public class Startup {
public Startup() {
var builder = new ConfigurationBuilder()
.AddJsonFile("AppSettings.json");
Configuration = builder.Build();
}
public IConfiguration Configuration { get; set; }
// This method gets called by the runtime.
// Use this method to add services to the container.
// For more information on how to configure your application,
// visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services) {
}
// This method gets called by the runtime.
// Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app) {
app.UseIISPlatformHandler();
app.UseDeveloperExceptionPage(); app.UseRuntimeInfoPage();
app.UseStaticFiles();
app.Run(async (context) => {
throw new System.Exception("Throw Exception");
var msg = Configuration["message"];
await context.Response.WriteAsync(msg);
});
}
// Entry point for the application.
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}
}
除非您覆蓋選項並傳入一些不同的配置引數,否則靜態檔案對於給定的請求將執行的操作是檢視請求路徑。然後將此請求路徑與檔案系統和檔案系統上的內容進行比較。
如果靜態檔案看到它可以使用的檔案,它將提供該檔案,並且不會呼叫下一個中介軟體。
如果它找不到匹配的檔案,則它將簡單地繼續執行下一個中介軟體。
讓我們儲存Startup.cs檔案並重新整理瀏覽器。
您現在可以看到 index.html 檔案。您在 wwwroot 中放置的任何內容 - 任何 JavaScript 檔案或 CSS 檔案或 HTML 檔案,您都能夠提供它們。
現在,如果您希望 index.html 成為您的預設檔案,這是一個 IIS 一直具有的功能。
您始終可以向 IIS 提供一個要查詢的預設檔案列表。如果有人訪問目錄的根目錄或在本例中訪問網站的根目錄,並且 IIS 找到名為 index.html 的檔案,它將自動提供該檔案。
現在讓我們從進行一些更改開始。首先,我們需要刪除強制錯誤,然後新增另一箇中間件,即 UseDefaultFiles。以下是 Configure 方法的實現。
// This method gets called by the runtime.
// Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app) {
app.UseIISPlatformHandler();
app.UseDeveloperExceptionPage();
app.UseRuntimeInfoPage();
app.UseDefaultFiles();
app.UseStaticFiles();
app.Run(async (context) => {
var msg = Configuration["message"];
await context.Response.WriteAsync(msg);
});
}
此中介軟體將檢視傳入請求,並檢視它是否是針對目錄的根目錄,以及是否存在任何匹配的預設檔案。
您可以覆蓋此中介軟體的選項,以告知它要查詢哪些預設檔案,但 Index.html 預設情況下是預設檔案之一。
讓我們儲存Startup.cs檔案,然後轉到瀏覽器中的 Web 應用程式的根目錄。
您現在可以看到 index.html 是您的預設檔案。安裝中介軟體的順序很重要,因為如果將 UseDefaultFiles 放在 UseStaticFiles 之後,您將無法獲得相同的結果。
如果您要使用 UseDefaultFiles 和 UseStaticFiles,您可能還需要另一個位於 Microsoft.aspnet.staticfiles NuGet 包中的中介軟體,即FileServer 中介軟體。這實質上以正確的順序包含了 Default Files 和 Static Files。
// This method gets called by the runtime.
// Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app) {
app.UseIISPlatformHandler();
app.UseDeveloperExceptionPage();
app.UseRuntimeInfoPage();
app. UseFileServer();
app.Run(async (context) => {
var msg = Configuration["message"];
await context.Response.WriteAsync(msg);
});
}
讓我們再次儲存Startup.cs檔案。重新整理瀏覽器後,您將看到與以下螢幕截圖中顯示的結果相同。
ASP.NET Core - 設定 MVC
在本章中,我們將在 FirstAppDemo 應用程式中設定 MVC 框架。我們將透過在 ASP.NET Core 之上構建 Web 應用程式來進行操作,更具體地說,是 ASP.NET Core MVC 框架。從技術上講,我們可以僅使用中介軟體構建整個應用程式,但 ASP.NET Core MVC 為我們提供了可以用來輕鬆建立 HTML 頁面和基於 HTTP 的 API 的功能。
要在我們的空專案中設定 MVC 框架,請執行以下步驟:
安裝Microsoft.AspNet.Mvc包,它使我們可以訪問框架提供的程式集和類。
安裝包後,我們需要在執行時註冊 ASP.NET MVC 所需的所有服務。我們將在ConfigureServices方法中執行此操作。
最後,我們需要為 ASP.NET MVC 新增中介軟體以接收請求。從本質上講,此中介軟體獲取 HTTP 請求,並嘗試將該請求定向到我們將編寫的 C# 類。
步驟 1 - 讓我們轉到 NuGet 包管理器,方法是右鍵單擊“管理 NuGet 包”。安裝 Microsoft.AspNet.Mvc 包,它使我們可以訪問框架提供的程式集和類。
步驟 2 - 安裝 Microsoft.AspNet.Mvc 包後,我們需要在執行時註冊 ASP.NET Core MVC 所需的所有服務。我們將使用 ConfigureServices 方法執行此操作。我們還將新增一個簡單的控制器,並檢視該控制器的一些輸出。
讓我們向此專案新增一個新資料夾,並將其命名為Controllers。我們可以在此資料夾中放置多個控制器,如下面的解決方案資源管理器所示。
現在右鍵單擊 Controllers 資料夾,然後選擇新增→類選單選項。
步驟 3 - 在這裡,我們想新增一個簡單的C#類,並將此類命名為HomeController,然後單擊新增按鈕,如上圖所示。
這將是我們的預設頁面。
步驟 4 - 讓我們定義一個返回字串的單個公共方法,並將該方法命名為 Index,如下面的程式所示。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace FirstAppdemo.Controllers {
public class HomeController {
public string Index() {
return "Hello, World! this message is from Home Controller...";
}
}
}
步驟 5 - 當您轉到網站的根目錄時,您希望看到控制器響應。目前,我們將提供我們的 index.html 檔案。
讓我們進入網站的根目錄並刪除 index.html 檔案。我們希望控制器做出響應,而不是由index.html檔案響應。
步驟 6 − 現在,轉到 Startup 類中的 Configure 方法,並新增UseMvcWithDefaultRoute中介軟體。
步驟 7 − 現在重新整理網站根目錄下的應用程式。
您將遇到 500 錯誤。錯誤指出框架無法找到所需的 ASP.NET Core MVC 服務。
ASP.NET Core 框架本身由不同的小型元件組成,這些元件具有非常集中的職責。
例如,有一個元件必須找到並例項化控制器。
為了使 ASP.NET Core MVC 正確執行,該元件需要位於 ASP.NET Core MVC 的服務集合中。
步驟 8 − 除了新增 NuGet 包和中介軟體之外,我們還需要在 ConfigureServices 中新增 AddMvc 服務。以下是 Startup 類的完整實現。
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
namespace FirstAppDemo {
public class Startup {
public Startup() {
var builder = new ConfigurationBuilder() .AddJsonFile("AppSettings.json");
Configuration = builder.Build();
}
public IConfiguration Configuration { get; set; }
// This method gets called by the runtime.
// Use this method to add services to the container.
// For more information on how to configure your application,
// visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services) {
services.AddMvc();
}
// This method gets called by the runtime.
// Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app) {
app.UseIISPlatformHandler();
app.UseDeveloperExceptionPage();
app.UseRuntimeInfoPage();
app.UseFileServer();
app.UseMvcWithDefaultRoute();
app.Run(async (context) => {
var msg = Configuration["message"];
await context.Response.WriteAsync(msg);
});
}
// Entry point for the application.
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}
}
步驟 9 − 儲存Startup.cs檔案,然後轉到瀏覽器並重新整理它。您現在將收到來自主頁控制器的響應。
ASP.NET Core - MVC 設計模式
MVC(模型-檢視-控制器)設計模式是一種設計模式,實際上已經存在了幾十年,並且已在許多不同的技術中使用,從 Smalltalk 到 C++ 到 Java,現在在 C# 和 .NET 中用作構建使用者介面時的設計模式。
MVC 設計模式是軟體應用程式使用者介面層的常用設計模式。
在較大的應用程式中,通常會將模型-檢視-控制器 UI 層與應用程式中的其他設計模式(如資料訪問模式和訊息傳遞模式)結合使用。
所有這些將共同構建完整的應用程式堆疊。
MVC 將應用程式的使用者介面 (UI) 分為以下三個部分:
模型 − 一組描述您正在處理的資料以及業務邏輯的類。
檢視 − 定義應用程式的 UI 將如何顯示。它是一個純 HTML,決定 UI 的外觀。
控制器 − 一組處理使用者通訊、整體應用程式流程和應用程式特定邏輯的類。
MVC 的理念
現在讓我們瞭解 MVC 背後的理念。
其理念是,您將擁有一個名為檢視的元件,它完全負責呈現此使用者介面,無論它應該是 HTML 還是實際上應該是桌面應用程式上的 UI 小部件。
檢視與模型進行互動,而模型包含檢視需要顯示的所有資料。
在 Web 應用程式中,檢視可能根本沒有任何程式碼與之關聯。
它可能只包含 HTML,然後是一些表示式,用於說明從模型中獲取資料片段並將其插入到您在檢視中構建的 HTML 模板中的正確位置。
控制器組織所有內容。當 MVC 應用程式收到 HTTP 請求時,請求將路由到控制器,然後由控制器決定與資料庫、檔案系統或模型進行互動。
在 MVC 中,控制器接收 HTTP 請求,控制器必須弄清楚如何將資訊組合在一起以響應此請求。也許使用者正在將瀏覽器定向到應用程式的 /books URL。因此,控制器需要將資訊組合在一起以顯示書籍列表。在這種情況下,控制器將構建一個模型。
模型不知道任何有關 HTTP 請求或控制器的資訊。
模型僅負責儲存使用者想要檢視的書籍資訊以及與該書籍列表相關的任何邏輯。
模型只是我們可以使用的另一個 C# 類,如果您有複雜的模型,則可能有多個類。
模型組合在一起後,控制器就可以選擇一個檢視來呈現模型。
檢視將獲取模型中的資訊,例如所有書籍和每本書的標題等,並使用這些資訊構建 HTML 頁面。
然後,該 HTML 在 HTTP 響應中傳送回客戶端,並且整個 HTTP 請求和響應事務完成。
這些是 MVC 設計模式的基礎,並且此模式背後的理念是保持關注點分離。因此,控制器只負責接收請求和構建模型。模型承載我們需要的邏輯和資料進入檢視。然後,檢視僅負責將該模型轉換為 HTML。
ASP.NET Core - 路由
在 MVC 框架中,我們有三個元件,每個元件都專注於工作的特定部分。為了使所有這些都能正常工作,我們需要找到一種方法將這些 HTTP 請求傳送到正確的控制器。在 ASP.NET Core MVC 中,此過程稱為路由。路由是將 HTTP 請求定向到控制器的過程。
現在讓我們瞭解如何將請求路由到不同的控制器。
ASP.NET Core 中介軟體需要一種方法來確定是否應將給定的 HTTP 請求傳送到控制器進行處理。
MVC 中介軟體將根據 URL 和我們提供的一些配置資訊做出此決定。在本章中,我們將定義此配置資訊或您可以在 Startup.cs 中新增 MVC 中介軟體時所說的路由資訊。
這種方法通常稱為基於約定的路由。以下是基於約定的路由的程式碼片段。
routeBuilder.MapRoute("Default", "{controller=Home}/{action=Index}/{id?}");
在這種方法中,我們定義模板來告訴 MVC 如何檢視 URL 並查詢控制器名稱和操作名稱,其中控制器是 C# 類,操作是該類上的公共方法。
在上一章中,我們在應用程式中建立了一個控制器(HomeController),它是一個 C# 類,不需要派生自基類或實現介面或具有任何特殊屬性。它是一個普通的 C# 類,具有名稱 HomeController,並且包含返回字串的 Index 方法。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace FirstAppdemo.Controllers {
public class HomeController {
public string Index() {
return "Hello, World! this message is from Home Controller...";
}
}
}
在這裡,我們將重點關注路由到控制器。我們還將嘗試瞭解路由的工作原理。
現在讓我們回到Startup 類,我們在其中將 MVC 中介軟體配置到我們的應用程式中。在 Configure 方法內部,我們使用了一個方法UseMvcWithDefaultRoute。
public void Configure(IApplicationBuilder app) {
app.UseIISPlatformHandler();
app.UseDeveloperExceptionPage();
app.UseRuntimeInfoPage();
app.UseFileServer();
app.UseMvcWithDefaultRoute();
app.Run(async (context) => {
var msg = Configuration["message"];
await context.Response.WriteAsync(msg);
});
}
這為我們提供了一個預設路由規則,允許我們訪問HomeController。與其使用UseMvcWithDefaultRoute,不如使用UseMvc,然後使用名為ConfigureRoute的方法在此處配置路由。以下是 Startup.cs 檔案的實現。
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.AspNet.Routing;
using System;
namespace FirstAppDemo {
public class Startup {
public Startup() {
var builder = new ConfigurationBuilder() .AddJsonFile("AppSettings.json");
Configuration = builder.Build();
}
public IConfiguration Configuration { get; set; }
// This method gets called by the runtime.
// Use this method to add services to the container.
// For more information on how to configure your application,
// visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services) {
services.AddMvc();
}
// This method gets called by the runtime.
// Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app) {
app.UseIISPlatformHandler();
app.UseDeveloperExceptionPage();
app.UseRuntimeInfoPage();
app.UseFileServer();
app.UseMvc(ConfigureRoute);
app.Run(async (context) => {
var msg = Configuration["message"];
await context.Response.WriteAsync(msg);
});
}
private void ConfigureRoute(IRouteBuilder routeBuilder) {
//Home/Index
routeBuilder.MapRoute("Default", "{controller = Home}/{action = Index}/{id?}");
}
// Entry point for the application.
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}
}
在ConfigureRoute方法內部,您可以配置路由;您可以看到此方法必須採用 IRouteBuilder 型別的引數。路由的目標是描述 ASP.NET Core MVC 將用於處理 HTTP 請求並查詢可以響應該請求的控制器的規則。
您可以有一條路由可以將請求對映到不同的控制器。
我們可以告訴 routeBuilder 我們想要對映一條新路由,其名稱為“Default”,然後提供最重要的路由資訊,即模板。
模板是一個字串,它將向 ASP.NET Core MVC 描述如何拆分 URL。
在最後一個示例中,我們添加了一個 HomeController,因此您還可以請求以下任何 URL,它們也將被定向到 HomeController 上的 Index 操作。
- https://:49940
- https://:49940/Home
- https://:49940/Home/Index
當瀏覽器請求http://mysite/或 http://mysite/Home時,它會獲取來自 HomeController 的 Index 方法的輸出。
您也可以透過更改瀏覽器中的 URL 來嘗試此操作。在此示例中,它是https://:49940/,只是埠可能不同。
如果將 /Home 或 /Home/Index 附加到 URL 並按下 Enter 鍵,您將看到相同的結果。
ID 末尾的問號表示此引數是可選的。換句話說,ASP.NET Core MVC 不必在這裡看到某種 ID,它可能是數字、字串或 GUID。
讓我們在瀏覽器中執行應用程式。應用程式執行後,您將看到以下輸出。
您可以看到 app.Run 中介軟體彈出的訊息,我們收到此訊息的原因是 MVC 中介軟體看到了該 URL。這是對網站根目錄的請求,在 URL 中找不到控制器名稱或操作名稱。網站根目錄放棄了處理該請求,並將請求傳遞到下一段中介軟體,即app.Run程式碼。我們指定的路由模板與預設模板非常不同。
在預設模板中,如果未找到控制器和操作名稱,則會應用一些預設值。如果請求進入網站的根目錄,則預設控制器名稱將為 Home。您可以將其更改為您想要的任何其他控制器,並且預設操作名稱可以是 Index。如果需要,您還可以更改預設操作,如下面的程式所示。
private void ConfigureRoute(IRouteBuilder routeBuilder) {
//Home/Index
routeBuilder.MapRoute("Default", "{controller = Home}/{action = Index}/{id?}");
}
如果請求進入網站的根目錄,MVC 不會看到控制器/操作型別的 URL,但它可以使用這些預設值。
讓我們儲存 Startup.cs 檔案並重新整理瀏覽器到網站的根目錄。
您現在將看到來自控制器的響應,您還可以轉到 /home,這將呼叫預設操作,即 index。您還可以轉到 /home/index,現在 MVC 將從 URL 中提取控制器名稱和操作名稱。
讓我們透過新增另一個類並將其稱為AboutController來建立另一個控制器。
讓我們新增一些簡單的操作方法,這些方法將返回字串,如下面的程式所示。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace FirstAppDemo.Controllers {
public class AboutController {
public string Phone() {
return "+49-333-3333333";
}
public string Country() {
return "Germany";
}
}
}
在此控制器中,您可以看到兩個操作方法:Phone 和 Country,它們將分別返回電話號碼和國家/地區名稱。我們稍後會介紹花哨的 HTML。讓我們儲存此檔案並在根 URL 的末尾指定 /about/phone。
您可以看到上面的螢幕截圖中的電話號碼。如果指定/about/country,您也將看到國家/地區的名稱。
如果轉到/about,它將再次透過中介軟體並轉到您的 app.Run 中介軟體,您將看到以下頁面。
在這裡,ASP.NET Core MVC 轉到 AboutController,但未找到指定的動作。因此,它將預設為 Index,並且此控制器沒有 Index 方法,然後請求將轉到下一段中介軟體。
ASP.NET Core - 屬性路由
在本章中,我們將學習另一種路由方法,即基於屬性的路由。使用基於屬性的路由,我們可以在控制器類以及這些類內部的方法上使用 C# 屬性。這些屬性具有元資料,告訴 ASP.NET Core 何時呼叫特定控制器。
它是基於約定的路由的替代方法。
路由的評估順序是它們出現的順序,也就是你註冊它們的順序,但對映多個路由的情況非常常見,尤其是在你希望在 URL 中擁有不同的引數或不同的文字時。
示例
讓我們來看一個簡單的例子。開啟**FirstAppDemo**專案並在瀏覽器中執行應用程式。當你指定** /about**時,它將產生以下輸出:
我們這裡想要的是,當我們指定** /about**時,應用程式應該呼叫AboutController的Phone操作。在這裡,我們可以使用Route屬性為該控制器強制執行一些顯式的路由。此屬性位於名稱空間**Microsoft.AspNet.Mvc**中。
以下是**AboutController**的實現,其中添加了屬性路由。
using Microsoft.AspNet.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace FirstAppDemo.Controllers {
[Route("about")]
public class AboutController {
[Route ("")]
public string Phone() {
return "+49-333-3333333";
}
[Route("country")]
public string Country() {
return "Germany";
}
}
}
在這裡,我們希望這條路由看起來像about,對於Phone操作,我們指定了一個空字串,這意味著我們不需要指定操作來獲取此方法。使用者只需要訪問 /about即可。對於Country操作,我們在路由屬性中指定了“country”。讓我們儲存AboutController,重新整理瀏覽器並轉到 /about,它應該會給你Phone操作的結果。
讓我們指定** /about/country**。這將允許你訪問Country操作。
如果你希望 URL 的一部分包含控制器的名稱,你可以做的是,而不是顯式地使用控制器名稱,你可以在方括號內使用一個標記controller。這告訴ASP.NET MVC在這個位置使用此控制器的名稱,如下面的程式所示。
using Microsoft.AspNet.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace FirstAppDemo.Controllers {
[Route("[controller]")]
public class AboutController {
[Route ("")]
public string Phone() {
return "+49-333-3333333";
}
[Route("[action]")]
public string Country() {
return "Germany";
}
}
}
這樣,如果你重新命名了控制器,你就不必記住更改路由。對於操作也是如此,並且在控制器和操作之間隱含有一個斜槓(/)。它就像URL內部一樣,是控制器和操作之間的一種層次關係。讓我們再次儲存此控制器。很可能,你會看到相同的結果。
讓我們指定 /about/country。這將允許你訪問Country操作。
ASP.NET Core - 操作結果
在本章中,我們將討論操作結果。在前面的章節中,我們一直在使用簡單的C#類作為控制器。這些類沒有從基類派生,你可以在MVC中使用這種方法,但更常見的是從Microsoft.AspNet.Mvc名稱空間中提供的控制器基類派生控制器。
這個基類使我們可以訪問有關請求的大量上下文資訊,以及幫助我們構建結果以傳送回客戶端的方法。
你可以在響應中傳送回簡單的字串和整數。你還可以傳送回覆雜的物件,例如表示學生、大學或餐廳等的物件,以及與該物件關聯的所有資料。
這些結果通常封裝在一個實現IActionResult介面的物件中。
有許多不同的結果型別實現了此介面——可以包含模型或要下載的檔案內容的結果型別。
這些不同的結果型別允許我們向客戶端傳送回JSON或XML或構建HTML的檢視。
操作基本上返回不同型別的操作結果。ActionResult類是所有操作結果的基類。以下是不同型別操作結果及其行為的列表。
| 名稱 | 行為 |
|---|---|
| ContentResult | 返回字串 |
| FileContentResult | 返回檔案內容 |
| FilePathResult | 返回檔案內容 |
| FileStreamResult | 返回檔案內容。 |
| EmptyResult | 不返回任何內容 |
| JavaScriptResult | 返回要執行的指令碼 |
| JsonResult | 返回JSON格式的資料 |
| RedirectToResult | 重定向到指定的URL |
| HttpUnauthorizedResult | 返回403 HTTP狀態程式碼 |
| RedirectToRouteResult | 重定向到不同的操作/不同的控制器操作 |
| ViewResult | 作為檢視引擎的響應接收 |
| PartialViewResult | 作為檢視引擎的響應接收 |
示例1
讓我們透過開啟**HomeController**類並從基於控制器的類派生來執行一個簡單的示例。此基類位於**Microsoft.AspNet.Mvc**名稱空間中。以下是HomeController類的實現。
using Microsoft.AspNet.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace FirstAppdemo.Controllers {
public class HomeController : Controller {
public ContentResult Index() {
return Content("Hello, World! this message is from
Home Controller using the Action Result");
}
}
}
你現在可以看到index方法返回ContentResult,它是結果型別之一,所有這些結果型別最終都實現了介面,即**ActionResult**。
在Index方法中,我們將一個字串傳遞給Content方法。此Content方法產生一個ContentResult;這意味著Index方法現在將返回**ContentResult**。
讓我們儲存**HomeController**類並在瀏覽器中執行應用程式。它將生成以下頁面。
你現在可以看到一個響應,它看起來與我們之前看到的響應沒有區別。它仍然只是一個純文字響應。
你可能想知道使用生成**ActionResult**的東西有什麼好處。
典型的優勢在於,它只是一種正式的方式來封裝控制器的決策。
控制器決定接下來做什麼,要麼返回字串或HTML,要麼返回一個可能被序列化成JSON等的模型物件。
控制器只需要做出這個決定,並且控制器不必直接寫入響應其決定的結果。
它只需要返回決定,然後是框架將獲取結果並理解如何將該結果轉換為可以透過HTTP傳送回的內容。
示例2
讓我們再舉一個例子。在專案中建立一個新資料夾並將其命名為**Models**。在Models資料夾中,我們想要新增一個可以表示員工的類。
在“名稱”欄位中輸入**Employee.cs**,如上圖所示。這裡,Employee類的實現包含兩個屬性。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace FirstAppDemo.Models {
public class Employee {
public int ID { get; set; }
public string Name { get; set}
}
}
在**HomeController**的Index操作方法內部,我們想要返回一個Employee物件。以下是HomeController的實現。
using FirstAppDemo.Models;
using Microsoft.AspNet.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace FirstAppdemo.Controllers {
public class HomeController : Controller {
public ObjectResult Index() {
var employee = new Employee { ID = 1, Name = "Mark Upston"};
return new ObjectResult(employee);
}
}
}
現在,我們將不再返回Content,而是返回另一種型別的結果,稱為**ObjectResult**。如果我們想要一個ObjectResult,我們需要建立一個或例項化一個ObjectResult並將一些**model**物件傳遞給它。
ObjectResult在MVC框架中是特殊的,因為當我們返回一個ObjectResult時,MVC框架會檢視此物件。此物件需要在HTTP響應中表示。
此物件應該被序列化成XML或JSON或其他某種格式,最終,決策將根據你在啟動時提供給MVC的配置資訊做出。如果你不配置任何內容,你只會得到一些預設值,預設值是JSON響應。
儲存所有檔案並重新整理瀏覽器。你將看到以下輸出。
ASP.NET Core - 檢視
在ASP.NET Core MVC應用程式中,沒有像頁面這樣的東西,並且當你在URL中指定路徑時,它也不包含任何直接對應於頁面的內容。在ASP.NET Core MVC應用程式中最接近頁面的東西稱為檢視。
如你所知,在ASP.NET MVC應用程式中,所有傳入的瀏覽器請求都由控制器處理,這些請求被對映到控制器操作。
控制器操作可能會返回一個檢視,或者它也可能執行其他型別的操作,例如重定向到另一個控制器操作。
使用MVC框架,建立HTML最流行的方法是使用ASP.NET MVC的Razor檢視引擎。
要使用此檢視引擎,控制器操作會生成一個**ViewResult**物件,而ViewResult可以攜帶我們想要使用的Razor檢視的名稱。
該檢視將是檔案系統上的一個檔案,並且ViewResult還可以將模型物件傳遞給檢視,並且檢視在建立HTML時可以使用此模型物件。
當MVC框架看到你的控制器操作生成了一個ViewResult時,框架將在檔案系統上找到該檢視,執行該檢視,該檢視生成HTML,並且正是這個HTML框架傳送回客戶端。
示例
現在讓我們來看一個簡單的例子,以瞭解這在我們的應用程式中是如何工作的,方法是更改HomeController Index方法的實現,如下面的程式所示。
using FirstAppDemo.Models;
using Microsoft.AspNet.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace FirstAppdemo.Controllers {
public class HomeController : Controller {
public ViewResult Index() {
var employee = new Employee { ID = 1, Name = "Mark Upston"};
return View();
}
}
}
在**HomeController**中,我們不再生成**ObjectResult**,而是隻返回**View()**方法返回的內容。View方法不返回ObjectResult。它建立了一個新的ViewResult,所以我們也將Index方法的返回型別更改為ViewResult。View方法在這裡接受一些引數。我們將在此方法中不帶任何其他引數地呼叫它。讓我們儲存你的檔案並重新整理瀏覽器。
這是因為MVC框架必須出去找到該檢視,但現在還沒有檢視。
預設情況下,在C# ASP.NET專案中的檢視是具有*.cshtml副檔名的檔案,並且這些檢視遵循特定的約定。預設情況下,所有檢視都位於專案中的Views資料夾中。
如果不對其提供任何其他資訊,ASP.NET MVC將派生檢視位置和檢視檔名。
如果我們需要從HomeController的Index操作渲染一個檢視,MVC框架首先查詢該檢視的位置是在Views資料夾中。
它將進入一個Home資料夾,然後查詢一個名為Index.cshtml的檔案——檔名以Index開頭,因為我們在Index操作中。
MVC框架還將在Shared資料夾中查詢,並且你放置在Shared資料夾中的檢視可以在應用程式中的任何地方使用。
為了使我們的檢視結果正常工作,讓我們在正確的位置建立此Index.cshtml檔案。因此,在我們的專案中,我們首先需要新增一個資料夾來包含我們所有的檢視,並將其命名為Views。在Views資料夾中,我們將為與我們的HomeController關聯的檢視新增另一個資料夾,並將該資料夾命名為Home。右鍵單擊Home資料夾並選擇**新增**→**新建項**。
在左側窗格中,選擇MVC檢視頁面,在名稱欄位中輸入**index.cshtml**,然後單擊“新增”按鈕。
讓我們在index.cshtml檔案中新增以下程式碼。
<html xmlns = "http://www.w3.org/1999/xhtml">
<head>
<title>Home</title>
</head>
<body>
<h1>Welcome!</h1>
<div>
This message is from the View...
</div>
</body>
</html>
你現在可以看到一個** *.cshtml檔案**。它可以包含HTML標記以及我們在此檔案中包含的任何標記,這些標記將直接傳送到客戶端。儲存此檔案並重新整理瀏覽器。
現在,Home控制器透過ViewResult已將此檢視呈現給客戶端,並且index.cshtml檔案中包含的所有標記,都是傳送給客戶端的內容。
讓我們回到HomeController和View方法。此View方法有幾個不同的過載,並將employee模型作為引數傳遞。
using FirstAppDemo.Models;
using Microsoft.AspNet.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace FirstAppdemo.Controllers {
public class HomeController : Controller {
public ViewResult Index() {
var employee = new Employee { ID = 1, Name = "Mark Upston"};
return View(employee);
}
}
}
View方法只接受一個模型物件,並且將使用預設檢視,即Index。在這裡,我們只想傳入該模型資訊並在Index.cshtml中使用該模型,如下面的程式所示。
<html xmlns = "http://www.w3.org/1999/xhtml">
<head>
<title>Home</title>
</head>
<body>
<h1>Welcome!</h1>
<div>
@Model.Name
</div>
</body>
</html>
當我們在**Razor檢視**中使用@符號時,Razor檢視引擎將把鍵入的內容視為C#表示式。Razor檢視包含一些我們可以訪問的內建成員,這些成員可以在C#表示式中使用。其中最重要的成員是Model。當你使用@Model時,你將獲得從控制器傳遞到檢視的模型物件。因此,這裡的@Model.Name將在檢視中顯示員工姓名。
現在讓我們儲存所有檔案。之後,重新整理瀏覽器以檢視以下輸出。
你現在可以看到員工姓名,如上圖所示。
ASP.NET Core - 設定實體框架
在本節中,我們將設定並配置我們的應用程式,以便從 SQL Server 資料庫儲存和讀取資料。
為了使用資料庫,我們將使用 Entity Framework,它已重新編寫以與新的 .NET Framework 協同工作。如果您以前使用過 EF,您會看到許多熟悉的部分。
在此應用程式中,我們將使用 SQL Server LocalDB。如果您不熟悉 SQL Server,您可以使用任何您喜歡的資料庫,例如本地資料庫、遠端資料庫,只要您有權在例項上建立新資料庫即可。
LocalDB 是 SQL Server 的一個特殊版本,針對開發人員進行了最佳化。
Visual Studio 2015 甚至其 Community 版本預設情況下都會安裝 LocalDB。
要檢查 LocalDB,請轉到 Visual Studio 中的**檢視 → SQL Server 物件資源管理器**選單選項。
如果您必須使用 SQL Server,這是一個很棒的工具,因為它允許您瀏覽資料庫和資料,甚至在資料庫內建立資料。第一次開啟時,可能需要一點時間,但它應該會自動連線到 LocalDB。
安裝 Entity Framework
使用 Entity Framework 的第一步是從 NuGet 包管理器安裝 Entity Framework NuGet 包,或透過直接編輯**project.json**檔案來安裝。
現在讓我們透過新增以下兩個包來直接編輯 project.json 檔案。
**EntityFramework.Commands**包幫助我們執行 Entity Framework 的任務,例如根據我們的 C# 實體類建立資料庫模式,這些任務可從命令列工具中使用,其中邏輯位於 EntityFramework.Commands 包中。
為了使用此命令列工具,我們需要在 project.json 的 commands 部分中新增一個額外的條目,如下面的螢幕截圖所示。
我們只是將其命名為“ef”,它將對映到此 EntityFramework.Commands 包。我們可以使用此“ef”來訪問 EntityFramework.Commands 中的一些可用邏輯。
以下是 project.json 檔案的實現。
{
"version": "1.0.0-*",
"compilationOptions": {
"emitEntryPoint": true
},
"dependencies": {
"Microsoft.AspNet.Mvc": "6.0.0-rc1-final",
"Microsoft.AspNet.Diagnostics": "1.0.0-rc1-final",
"Microsoft.AspNet.IISPlatformHandler": "1.0.0-rc1-final",
"Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final",
"Microsoft.AspNet.StaticFiles": "1.0.0-rc1-final",
"EntityFramework.MicrosoftSqlServer": "7.0.0-rc1-final",
"EntityFramework.Commands": "7.0.0-rc1-final"
}
"commands": {
"web": "Microsoft.AspNet.Server.Kestrel"
},
"frameworks": {
"dnx451": { },
"dnxcore50": { }
},
"exclude": [
"wwwroot",
"node_modules"
],
"publishExclude": [
"**.user",
"**.vspscc"
]
}
ASP.NET Core - DBContext
Entity Framework 使您能夠使用稱為實體的公共語言執行時 (CLR) 物件查詢、插入、更新和刪除資料。Entity Framework 將模型中定義的實體和關係對映到資料庫。它還提供以下功能:−
將從資料庫返回的資料具體化為實體物件。
跟蹤對物件所做的更改。
處理併發。
將物件更改傳播回資料庫。
將物件繫結到控制元件。
負責以物件形式與資料互動的主要類是 DbContext。使用上下文推薦的方法是定義一個從 DbContext 派生的類,並公開表示上下文中指定實體集合的 DbSet 屬性。
在邏輯上,DBContext 對映到具有 DBContext 理解的架構的特定資料庫。並且在該 DBContext 類上,您可以建立型別為 DbSet<T> 的屬性。泛型型別引數 T 將是實體型別,例如 Employee 是 FirstAppDemo 應用程式中的實體。
示例
讓我們舉一個簡單的例子,我們將建立一個 DbContext 類。在這裡,我們需要在 Models 資料夾中新增一個新類,並將其命名為**FirstAppDempDbContext**。即使此類本身不是模型,它也確實將所有模型組合在一起,以便我們可以將它們與資料庫一起使用。
從位於 Miscrosoft.Data.Entity 名稱空間中的 DbContext 類繼承您的上下文類。現在在該類上實現 Employee 的 DbSet。
每個 DbSet 將對映到資料庫中的一個表。如果您有一個 Employee 的 DbSet 屬性,並且該屬性的名稱為 Employees,則 Entity Framework 預設情況下會在資料庫中查詢 Employees 表。
using FirstAppDemo.Models;
using Microsoft.Data.Entity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace OdeToFood.Models {
public class FirstAppDemoDbContext : DbContext {
public DbSet<Employee> Employees { get; set; }
}
}
實現非常簡單,因為我們只有一個模型要處理。我們只需要一個屬性,Employee 的**DbSet**,我們可以將此屬性命名為**Employees**。
現在讓我們將此類直接插入控制器,然後控制器可以使用**FirstAppDemoDbContext**查詢資料庫。我們將透過在 HomeController 類中新增一個新類來簡化所有這些操作,在該類中我們實現新增員工和獲取員工的方法,如下面的程式所示。
using Microsoft.AspNet.Mvc;
using FirstAppDemo.ViewModels;
using FirstAppDemo.Services;
using FirstAppDemo.Entities;
using FirstAppDemo.Models;
using System.Collections.Generic;
using System.Linq;
namespace FirstAppDemo.Controllers {
public class HomeController : Controller {
public ViewResult Index() {
var model = new HomePageViewModel();
using (var context = new FirstAppDemoDbContext()) {
SQLEmployeeData sqlData = new SQLEmployeeData(context);
model.Employees = sqlData.GetAll();
}
return View(model);
}
}
public class SQLEmployeeData {
private FirstAppDemoDbContext _context { get; set; }
public SQLEmployeeData(FirstAppDemoDbContext context) {
_context = context;
}
public void Add(Employee emp) {
_context.Add(emp);
_context.SaveChanges();
}
public Employee Get(int ID) {
return _context.Employees.FirstOrDefault(e => e.Id == ID);
}
public IEnumerable<Employee> GetAll() {
return _context.Employees.ToList<Employee>();
}
}
public class HomePageViewModel {
public IEnumerable<Employee> Employees { get; set; }
}
}
在上面的 SQLEmployeeData 類中,您可以看到我們定義了 Add 方法,該方法會將新的員工物件新增到上下文中,然後儲存更改。在 Get 方法中,它將根據 ID 返回員工。而在 GetAll 方法中,它將返回資料庫中所有員工的列表。
配置 Entity Framework 服務
為了擁有可用的 Entity Framework DBContext,我們需要更改應用程式的配置。我們需要新增連線字串,以便我們的 DBContext 知道要連線到哪個伺服器以及要查詢哪個資料庫。
我們將連線字串放在 JSON 配置檔案中。
我們還需要在 Startup 類的 ConfigureServices 方法中新增更多服務。
Entity Framework 就像 ASP.NET 和 MVC 框架一樣,Entity Framework 依賴於依賴項注入,為了使注入工作,執行時需要了解 Entity Framework 使用的各種服務。
有一個簡單的配置 API 將新增我們所需的所有預設服務。
讓我們轉到 AppSettings.json 檔案並新增連線字串,如下面的程式所示。
{
"message": "Hello, World! this message is from configuration file...",
"database": {
"connection": "Data Source=(localdb)\\mssqllocaldb;Initial Catalog=FirstAppDemo"
}
}
現在讓我們轉到 Startup 類,我們需要為 Entity Framework 正確工作新增一些額外的服務。具體來說,我們需要做三件事與 Entity Framework 相關:−
我們需要新增核心 Entity Framework 服務。
我們還需要新增與 SQL Server 相關的 Entity Framework 服務。
我們需要告訴 Entity Framework 我們的 DBContext。
所有這些都可以透過作為擴充套件方法在**IServiceCollection**上可用的一些方法來完成,如下面的程式所示。
public void ConfigureServices(IServiceCollection services) {
services.AddMvc();
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<FirstAppDemoDbContext>
(option => option.UseSqlServer(Configuration["database:connection"]));
}
第一個方法是**AddEntityFramework**。這將新增核心 Entity Framework 服務,即預設服務。
但是由於 Entity Framework 現在設計為與各種資料庫(包括非關係資料庫)協同工作,因此我們需要進行第二次呼叫以告訴 Entity Framework 新增其預設的與 SQL Server 相關的服務。
然後我們還需要告訴 Entity Framework 我的**DBContext**類,以便它可以適當地構造該類的例項,我們可以透過第三種方法**AddDbContext**方法來做到這一點。
此方法採用一個泛型型別引數,我們在這裡指定 DBContext 派生類的型別,即**FirstAppDemoDbContext**。
在 AddDbContext 內部,我們需要描述 DBContext 的選項。
這可以透過**lambda 表示式**來完成;它是一個操作,我們接收一個選項引數,並且 Entity Framework 可以支援不同的資料庫。我們只需要告訴 Entity Framework 此特定的 DBContext 將**UseSqlServer**即可。
此方法需要一個引數,即要使用的**connectionString**。
以下是**Startup.cs**檔案的完整實現。
using Microsoft.AspNet.Mvc;
using FirstAppDemo.ViewModels;
using FirstAppDemo.Services;
using FirstAppDemo.Entities;
using FirstAppDemo.Models;
using System.Collections.Generic;
using System.Linq;
namespace FirstAppDemo.Controllers {
public class HomeController : Controller {
public ViewResult Index() {
var employee = new Employee { Id = 1, Name = "Mark Upston1" };
using (var context = new
FirstAppDemoDbContext()) {
SQLEmployeeData sqlData = new SQLEmployeeData(context);
sqlData.Add(employee);
}
//var employee = new Employee { ID = 1, Name = "Mark Upston" };
return View(employee);
}
}
public class SQLEmployeeData {
private FirstAppDemoDbContext _context { get; set; }
public SQLEmployeeData(FirstAppDemoDbContext context) {
_context = context;
}
public void Add(Employee emp) {
_context.Add(emp);
_context.SaveChanges();
}
public Employee Get(int ID) {
return _context.Employees.FirstOrDefault(e => e.Id == ID);
}
public IEnumerable<Employee> GetAll() {
return _context.Employees.ToList<Employee>();
}
}
}
現在我們需要設定資料庫。設定資料庫的一種方法是使用 Entity Framework 建立資料庫,這是一個兩步過程:−
第一步
這包括以下內容:−
將遷移程式碼新增到我們的專案中。
遷移程式碼是**C#**程式碼。這可以執行以在資料庫中建立資料庫架構。
Entity Framework 可以為我們生成此遷移程式碼。
Entity Framework 檢視資料庫和我們的模型,並確定使應用程式工作所需的架構更改。
因此,當我們新增其他模型或對現有模型(如 Employee 類)進行更改時,我們可以繼續向專案新增遷移並使資料庫架構保持同步。
第二步
這包括以下內容:−
在這裡,我們需要顯式應用這些遷移來更新資料庫。
這兩項任務都可以透過在控制檯視窗中使用一些簡單的命令來實現。
我們已經建立了 project.json。
這就是為什麼我們建立了 project.json 以新增一個命令,其中“ef”對映到 EntityFramework.Commands。
讓我們開啟 Visual Studio 的開發者命令提示符以執行我們需要新增遷移和應用遷移的命令。最簡單的方法是轉到應用程式根目錄。
如果您位於包含 project.json 檔案的資料夾中,則您位於正確的資料夾中。在這裡,我們需要執行一個名為 dnvm 的命令。這是 .NET 版本管理器,它將告訴系統我們想要使用哪個執行時。
現在讓我們使用以下命令。
dnvm list
當您按下 Enter 鍵時,您將看到以下輸出。
我們需要告訴**dnvm**我們想要使用特定的執行時。這將使我們能夠訪問我們想要執行的 dotnet 命令或 dnx 命令。
執行以下命令。
dnvm use1.0.0-rc1-update1 -p
按 Enter 鍵。
**dnvm**將設定我們的路徑和環境變數以包含一個 bin 目錄,這將使我們能夠訪問此 dnx 實用程式。讓我們執行**dnx ef**命令。
這是 .NET 執行環境,使用 dnx,我們可以呼叫我們在 project.json 檔案中列出的命令。執行這些命令通常非常簡單。當您鍵入 dnx ef 時,您將獲得一個幫助螢幕。您不必記住所有選項。您可以從 Entity Framework Commands 中檢視可用的命令,其中有三個。
首先,我們需要新增遷移以執行以下命令。
dnx ef migrations add v1
按 Enter 鍵。
Entity Framework 將找到該上下文並檢視其中的模型。它將知道沒有以前的遷移,因此它將生成第一個遷移。這裡,v1 是資料庫的版本 1。它將在解決方案資源管理器中建立一個新資料夾並生成程式碼。
遷移本質上是用於生成 SQL 命令以修改 SQL 資料庫中架構的 C# 程式碼。
using System;
using System.Collections.Generic;
using Microsoft.Data.Entity.Migrations;
using Microsoft.Data.Entity.Metadata;
namespace FirstAppDemo.Migrations {
public partial class v1 : Migration {
protected override void Up(MigrationBuilder migrationBuilder) {
migrationBuilder.CreateTable(name: "Employee", columns: table => new {
Id = table.Column<int>(nullable: false)
.Annotation("SqlServer:ValueGenerationStrategy",
SqlServerValueGenerationStrategy.IdentityColumn),
Name = table.Column<string>(nullable: true)
},
constraints: table => {
table.PrimaryKey("PK_Employee", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder) {
migrationBuilder.DropTable("Employee");
}
}
}
您可以看到它將建立一個名為 Employees 的表。
此表格應該有兩列——一個 ID 列和一個 Name 列。
按照慣例,當 Entity Framework 看到您有一個名為 Id 的屬性時,它會將該屬性,或者更確切地說,將該列設為資料庫中的主鍵。
這裡,我們將使用 SQL Server。預設情況下,Entity Framework 會將其設為 IdentityColumn,這意味著 SQL Server 會為我們生成 ID。
讓我們透過鍵入“dnx ef database update”命令將這些 ID 應用到資料庫中。
您可以看到該命令已應用遷移。
現在讓我們轉到 SQL Server 物件資源管理器,並重新整理資料庫,您現在可以看到我們有一個 FirstAppDemo 資料庫。
您還可以看到我們的 Employee 表,我們甚至可以檢視該表中的列,其中 ID 列是主鍵。
讓我們右鍵單擊 dbo.Employee 表並選擇“檢視資料”。
在執行應用程式之前,讓我們新增一些資料。當我們啟動應用程式時,應該會看到資料庫中的一些資料。
讓我們在這裡新增幾行資料。
現在讓我們更新 index.cshtml 檔案。它以表格形式顯示所有資料。
@model FirstAppDemo.Controllers.HomePageViewModel
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Home</title>
</head>
<body>
<h1>Welcome!</h1>
<table>
@foreach (var employee in Model.Employees) {
<tr>
<td>
@Html.ActionLink(employee.Id.ToString(), "Details", new
{ id = employee.Id })
</td>
<td>@employee.Name</td>
</tr>
}
</table>
</body>
</html>
執行應用程式後,它應該會產生以下輸出。
ASP.NET Core - Razor 佈局檢視
在本章中,我們將瞭解 Razor 佈局檢視。大多數網站和 Web 應用程式都希望建立呈現一些公共元素的頁面。
您通常在每個頁面的頂部區域顯示徽標和導航選單。
您可能還會在側邊欄中提供其他連結和資訊,以及可能在頁面底部帶有某些內容的頁尾。
應用程式的每個頁面都希望擁有這些共同因素。在這裡,我們利用佈局檢視來避免在編寫的每個頁面中重複這些因素。
佈局檢視
現在讓我們瞭解什麼是佈局檢視。
佈局檢視是一個具有 *.cshtml 副檔名的 Razor 檢視。您可以選擇以您想要的方式命名佈局檢視。在本章中,我們將使用名為 _Layout.cshtml 的佈局檢視。
這是佈局檢視的常用名稱,前導下劃線不是必需的。這只是許多開發人員遵循的約定,用於識別不是檢視的檢視;您將其作為控制器操作的檢視結果呈現。
這是一種特殊的檢視,但是一旦我們有了佈局檢視,我們就可以設定我們的控制器檢視,例如主頁的 Index 檢視。
我們可以設定此檢視以在特定位置的佈局檢視內呈現。
這種佈局檢視方法意味著 Index.cshtml 不需要了解任何關於徽標或頂級導航的資訊。
Index 檢視只需要呈現控制器操作為此檢視提供的模型的特定內容,而佈局檢視則負責處理其他所有事情。
示例
讓我們舉一個簡單的例子。
如果您有多個檢視,您會發現所有檢視都包含一定數量的重複標記。它們都將具有一個開始的 HTML 標籤、一個 head 標籤和一個 body 標籤。
即使我們在這個應用程式中沒有導航選單,但在實際應用程式中它很可能也會可用,我們不想在每個檢視中重複該標記。
讓我們建立一個佈局檢視,並將佈局檢視新增到 Views 資料夾內名為 Shared 的新資料夾中。這是一個 MVC 框架知道的約定資料夾。它知道此處的檢視可能被應用程式中多個控制器的使用。讓我們右鍵單擊 Shared 資料夾並選擇“新增”→“新建項”。
在中間窗格中,選擇 MVC 檢視佈局頁面。此處的預設名稱為 _Layout.cshtml。根據使用者選擇要執行時使用的佈局檢視。現在,單擊“新增”按鈕。這是您為新的佈局檢視預設獲得的內容。
我們希望佈局檢視負責管理 head 和 body。現在,由於此檢視位於 Razor 檢視中,因此我們可以使用 C# 表示式。我們仍然可以新增文字。現在我們有一個顯示 DateTime.Now 的 div。現在讓我們只新增 Year。
<!DOCTYPE html>
<html>
<head>
<meta name = "viewport" content = "width = device-width" />
<title>@ViewBag.Title</title>
</head>
<body>
<div>
@DateTime.Now
</div>
<div>
@RenderBody()
</div>
</body>
</html>
在上面的程式碼中,您將看到 RenderBody 和 ViewBag.Title 等表示式。當 MVC 控制器操作呈現 Index 檢視時,並且其中包含佈局頁面;然後 Index 檢視及其生成的 HTML 將放置在 Index 檢視中。
這就是對 RenderBody 進行方法呼叫的位置。我們可以預期我們應用程式中的所有內容檢視都將出現在呼叫 RenderBody 的 div 內部。
此檔案中的另一個表示式是 ViewBag.Title。ViewBag 是一個數據結構,可以新增到任何屬性和任何您想要新增到 ViewBag 中的資料。我們可以新增 ViewBag.Title、ViewBag.CurrentDate 或我們想要的任何屬性到 ViewBag 上。
現在讓我們轉到 index.cshtml 檔案。
@model FirstAppDemo.Controllers.HomePageViewModel
<html xmlns = "http://www.w3.org/1999/xhtml">
<head>
<title>Home</title>
</head>
<body>
<h1>Welcome!</h1>
<table>
@foreach (var employee in Model.Employees) {
<tr>
<td>
@Html.ActionLink(employee.Id.ToString(), "Details", new
{ id = employee.Id })
</td>
<td>@employee.Name</td>
</tr>
}
</table>
</body>
</html>
刪除我們不再需要在 Index 檢視中使用的標記。因此,我們可以刪除 HTML 標籤和 head 標籤之類的東西。我們也不需要開始的 body 元素或結束標籤,如下面的程式所示。
@model FirstAppDemo.Controllers.HomePageViewModel
@{
ViewBag.Title = "Home";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Welcome!</h1>
<table>
@foreach (var employee in Model.Employees) {
<tr>
<td>
@Html.ActionLink(employee.Id.ToString(), "Details", new { id = employee.Id })
</td>
<td>@employee.Name</td>
</tr>
}
</table>
我們仍然需要做兩件事:
首先,我們需要告訴 MVC 框架我們想要從這個檢視中使用佈局檢視。
其次,我們需要透過向 ViewBag 中新增一些資訊來設定適當的標題,如上面的程式碼所示。
讓我們儲存所有檔案並執行應用程式。執行應用程式後,您將看到以下主頁。
ASP.NET Core - Razor 檢視啟動
在本章中,我們將討論 Razor 檢視啟動。MVC 中的 Razor 檢視引擎有一個約定,即它會查詢任何名為 _ViewStart.cshtml 的檔案並在執行單個檢視內的程式碼之前執行此檔案內的程式碼。
ViewStart 檔案中的程式碼不能呈現到頁面的 HTML 輸出中,但可以用來從單個檢視內的程式碼塊中刪除重複的程式碼。
在我們的示例中,如果我們希望每個檢視都使用我們在上一章中建立的佈局檢視,我們可以將設定佈局檢視的程式碼放在 ViewStart 中,而不是將程式碼放在每個檢視中。
示例
讓我們舉一個簡單的例子來了解它是如何工作的。在我們的應用程式中,我們不希望每個檢視都指定其佈局檢視為 _Layout.cshtml。因此,右鍵單擊 Views 資料夾並選擇“新增”→“新建項”。
ASP.NET MVC 中有一個用於 ViewStart 頁面的特定模板,因此在中間窗格中選擇 MVC 檢視啟動頁面。這裡最重要的部分是此檔名為 _ViewStart.cshtml。現在單擊“新增”按鈕。
ViewStart 檔案的主要用途是設定佈局檢視。
現在讓我們轉到 Index.cshtml 檔案並將 Layout 行剪下,然後將其新增到 ViewStart 檔案中,如下面的程式所示。
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
當 MVC 框架要呈現檢視時,它會檢視資料夾層次結構中的某個位置是否存在 ViewStart 檔案。
我們已將 _ViewStart 直接放入我們的 Views 資料夾中。這將影響 Views 資料夾內所有資料夾中的所有檢視,以及 Home 資料夾和 Shared 資料夾內的檢視,以及我們將來可能新增的任何其他控制器資料夾。
如果我們獲取 ViewStart 並將其僅放置在 Home 資料夾中,則僅當我們呈現 Home 資料夾中這些檢視之一時,這段程式碼才會執行。
我們甚至可以有多個 ViewStart 檔案,因此我們可以在 Views 資料夾中有一個 ViewStart.cshtml,它為所有檢視設定佈局檢視。
但是,如果我們想更改 Home 資料夾中所有檢視的預設值,我們可以在 Home 資料夾中新增另一個 ViewStart,將佈局設定為其他內容。
讓我們儲存所有檔案並執行應用程式。
您會看到您的主頁仍然以與之前相同的方式呈現,並且我們仍然啟用了佈局檢視。
ASP.NET Core - Razor 檢視匯入
在本章中,我們將討論 Razor 檢視匯入。除了 ViewStart 檔案外,還有一個 ViewImports 檔案,MVC 框架在呈現任何檢視時都會查詢該檔案。
與 ViewStart 檔案類似,我們可以將 ViewImports.cshtml 放入資料夾中,並且 ViewImports 檔案可以影響資料夾層次結構中的所有檢視
此檢視是 MVC 的此版本的新增功能,在以前版本的 MVC 中,我們可以使用 XML 配置檔案來配置 Razor 檢視引擎的某些方面。
這些 XML 檔案現在消失了,我們使用程式碼代替。
ViewImports 檔案是我們編寫程式碼並放置常用指令以引入檢視所需的名稱空間的地方。
如果我們在檢視中經常使用某些名稱空間,我們可以讓 using 指令在我們的 ViewImports 檔案中出現一次,而不是在每個檢視中都使用 using 指令或鍵入類的完整名稱空間。
示例
讓我們舉一個簡單的例子來了解如何將我們的 using 指令移到 ViewImports 中。在 Index 檢視中,我們有一個 using 指令來引入名稱空間 FirstAppDemo.Controllers,如下面的程式所示。
@using FirstAppDemo.Controllers
@model HomePageViewModel
@{
ViewBag.Title = "Home";
}
<h1>Welcome!</h1>
<table>
@foreach (var employee in Model.Employees) {
<tr>
<td>
@Html.ActionLink(employee.Id.ToString(), "Details", new { id = employee.Id })
</td>
<td>@employee.Name</td>
</tr>
}
</table>
Using 指令將允許從 Razor 檢視生成的程式碼正確編譯。如果沒有 using 指令,C# 編譯器將無法找到此 Employee 型別。要檢視 employee 型別,讓我們從 Index.cshtml 檔案中刪除 using 指令。
@model HomePageViewModel
@{
ViewBag.Title = "Home";
}
<h1>Welcome!</h1>
<table>
@foreach (var employee in Model.Employees) {
<tr>
<td>
@Html.ActionLink(employee.Id.ToString(), "Details", new { id = employee.Id })
</td>
<td>@employee.Name</td>
</tr>
}
</table>
現在,執行應用程式。
您將看到其中一個錯誤,指出找不到型別或名稱空間 HomePageViewModel。這可能是因為您的幾個檢視需要相同的 using 指令。因此,與其將其放在每個檢視中,不如在 Views 資料夾中建立一個檢視匯入。這將透過右鍵單擊 Views 資料夾並選擇“新增”→“新建項”來向每個檢視新增 using 語句。
在中間窗格中,選擇 MVC 檢視匯入頁面。預設情況下,名稱為 _ViewImports.cshtml。就像 ViewStart 一樣,我們不能使用此檔案來呈現 HTML,因此讓我們單擊“新增”按鈕。
現在將 using 指令新增到此 _ViewImports.cshtml 檔案中,如下所示。
@using FirstAppDemo.Controllers
現在,出現在此資料夾或任何子資料夾中的所有檢視都能夠使用來自 FirstAppDemo.Controllers 的型別,而無需指定該確切的 using 語句。讓我們再次執行您的應用程式,您會看到該檢視現在正在工作。
ASP.NET Core - Razor 標籤助手
標籤助手使伺服器端程式碼能夠參與在 Razor 檔案中建立和呈現 HTML 元素。標籤助手是一項新功能,類似於 HTML 助手,可幫助我們呈現 HTML。
有許多用於常見任務的內建標籤助手,例如建立表單、連結、載入資產等。標籤助手以 C# 編寫,它們根據元素名稱、屬性名稱或父標記來定位 HTML 元素。
例如,內建的 LabelTagHelper 可以定位 HTML <label> 元素,當應用 LabelTagHelper 屬性時。
如果您熟悉 HTML 助手,標籤助手可以減少 Razor 檢視中 HTML 和 C# 之間的顯式轉換。
為了使用標籤助手,我們需要安裝一個 NuGet 庫,並向使用這些標籤助手的檢視或檢視新增 addTagHelper 指令。讓我們右鍵單擊解決方案資源管理器中的專案並選擇“管理 NuGet 包…”。
搜尋 **Microsoft.AspNet.Mvc.TagHelpers** 並點選安裝按鈕。
您將收到以下預覽對話方塊。
點選確定按鈕。
點選 **我接受** 按鈕。安裝 Microsoft.AspNet.Mvc.TagHelpers 後,轉到 project.json 檔案。
{
"version": "1.0.0-*",
"compilationOptions": {
"emitEntryPoint": true
},
"dependencies": {
"Microsoft.AspNet.Mvc": "6.0.0-rc1-final",
"Microsoft.AspNet.Diagnostics": "1.0.0-rc1-final",
"Microsoft.AspNet.IISPlatformHandler": "1.0.0-rc1-final",
"Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final",
"Microsoft.AspNet.StaticFiles": "1.0.0-rc1-final",
"EntityFramework.MicrosoftSqlServer": "7.0.0-rc1-final",
"EntityFramework.Commands": "7.0.0-rc1-final",
"Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-rc1-final"
},
"commands": {
"web": "Microsoft.AspNet.Server.Kestrel",
"ef": "EntityFramework.Commands"
},
"frameworks": {
"dnx451": { },
"dnxcore50": { }
},
"exclude": [
"wwwroot",
"node_modules"
],
"publishExclude": [
"**.user",
"**.vspscc"
]
}
在 dependencies 部分,您將看到添加了 **"Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-rc1-final"**。
現在任何人都可以編寫標籤助手,因此,如果您能想到需要的標籤助手,就可以編寫自己的標籤助手。
您可以將其直接放在應用程式專案中,但需要告訴 Razor 檢視引擎有關該標籤助手的資訊。
預設情況下,即使這些標籤助手看起來像是融合到 HTML 中,它們也不會被簡單地呈現到客戶端。
Razor 將呼叫一些程式碼來處理標籤助手;它可以從 HTML 中刪除自身,也可以新增其他 HTML。
使用標籤助手可以做很多很棒的事情,但是您需要將標籤助手註冊到 Razor,即使是 Microsoft 標籤助手,以便 Razor 能夠在標記中發現這些標籤助手並能夠呼叫處理標籤助手的程式碼。
執行此操作的指令是 addTagHelper,您可以將其放在單個檢視中,或者如果您計劃在整個應用程式中使用標籤助手,則可以使用 ViewImports 檔案中的 addTagHelper,如下所示。
@using FirstAppDemo.Controllers @addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"
註冊程式集中所有標籤助手的語法是使用星號逗號(*,)然後是程式集名稱 **Microsoft.AspNet.Mvc.TagHelpers**。因為這裡的第一部分是型別名稱,所以如果只想使用一個標籤助手,我們可以在此處列出特定的標籤助手。
但是,如果您只想獲取此程式集中的所有標籤助手,則可以使用 **星號(*)**。標籤助手庫中提供了許多標籤助手。讓我們看一下 Index 檢視。
@model HomePageViewModel
@{
ViewBag.Title = "Home";
}
<h1>Welcome!</h1>
<table>
@foreach (var employee in Model.Employees) {
<tr>
<td>
@Html.ActionLink(employee.Id.ToString(), "Details", new { id = employee.Id })
</td>
<td>@employee.Name</td>
</tr>
}
</table>
我們已經使用 **ActionLink** 使用了一個 HTML 助手來生成一個錨標記,該標記將指向允許我們獲取員工詳細資訊的 URL。
讓我們首先在主頁控制器中新增 Details 操作,如下面的程式所示。
public IActionResult Details(int id) {
var context = new FirstAppDemoDbContext();
SQLEmployeeData sqlData = new SQLEmployeeData(context);
var model = sqlData.Get(id);
if (model == null) {
return RedirectToAction("Index");
}
return View(model);
}
現在我們需要為 Details 操作新增一個檢視。讓我們在 Views → Home 資料夾中建立一個新檢視,並將其命名為 Details.cshtml,然後新增以下程式碼。
@model FirstAppDemo.Models.Employee
<html xmlns = "http://www.w3.org/1999/xhtml">
<head>
<title>@Model.Name</title>
</head>
<body>
<h1>@Model.Name</h1>
<div>Id: @Model.Id</div>
<div>
@Html.ActionLink("Home", "Index")
</div>
</body>
</html>
現在讓我們執行應用程式。
當您點選員工的 ID 時,它將帶您到詳細資訊檢視。
讓我們點選第一個員工 ID。
現在要為此使用標籤助手,讓我們在 index.cshtml 檔案中新增以下行並刪除 HTML 助手。
<a asp-action = "Details" asp-rout-id = "@employee.Id" >Details</a>
**asp-action = "Details"** 是我們要訪問的操作的名稱。如果要傳遞任何引數,則可以使用 asp-route 標籤助手,在這裡我們希望包含 ID 作為引數,因此我們可以使用 asp-route-Id 標籤助手。
以下是 index.cshtml 檔案的完整實現。
@model HomePageViewModel
@{
ViewBag.Title = "Home";
}
<h1>Welcome!</h1>
<table>
@foreach (var employee in Model.Employees) {
<tr>
<td>
<a asp-action="Details" asp-route-id="@employee.Id" >Details</a>
</td>
<td>@employee.Name</td>
</tr>
}
</table>
讓我們再次執行您的應用程式。執行應用程式後,您將看到以下頁面。
以前,我們將 ID 顯示為連結文字,但現在我們顯示文字 Details。現在,我們點選詳細資訊,並使用標籤助手而不是 HTML 助手建立正確的 URL。
無論您選擇使用 **HTML 助手** 還是 **標籤助手**,這實際上都取決於個人喜好。許多開發人員發現標籤助手更容易編寫和維護。
ASP.NET Core - Razor 編輯表單
在本章中,我們將繼續討論標籤助手。我們還將在應用程式中新增一個新功能,並使其能夠編輯現有員工的詳細資訊。我們將首先在每個員工旁邊新增一個連結,該連結將轉到 HomeController 上的 Edit 操作。
@model HomePageViewModel
@{
ViewBag.Title = "Home";
}
<h1>Welcome!</h1>
<table>
@foreach (var employee in Model.Employees) {
<tr>
<td>@employee.Name</td>
<td>
<a asp-controller = "Home" asp-action = "Details"
asp-routeid = "@employee.Id">Details</a>
<a asp-controller = "Home" asp-action = "Edit"
asp-routeid = "@employee.Id">Edit</a>
</td>
</tr>
}
</table>
我們還沒有 Edit 操作,但我們需要一個可以編輯的員工 ID。因此,讓我們首先透過右鍵單擊 **Views →Home** 資料夾並選擇 **新增 → 新建項** 來建立一個新檢視。
在中間窗格中,選擇 MVC 檢視頁面;將頁面命名為 Edit.cshtml。現在,點選新增按鈕。
在 **Edit.cshtml** 檔案中新增以下程式碼。
@model Employee
@{
ViewBag.Title = $"Edit {Model.Name}";
}
<h1>Edit @Model.Name</h1>
<form asp-action="Edit" method="post">
<div>
<label asp-for = "Name"></label>
<input asp-for = "Name" />
<span asp-validation-for = "Name"></span>
</div>
<div>
<input type = "submit" value = "Save" />
</div>
</form>
對於此頁面的標題,我們可以說我們想要編輯,然後提供員工姓名。
**Edit** 前面的美元符號將允許執行時用該屬性中的值(如員工姓名)替換 Model.Name。
在表單標記內,我們可以使用諸如 asp-action 和 asp-controller 之類的標籤助手。這樣,當用戶提交此表單時,它將直接轉到特定的控制器操作。
在這種情況下,我們希望轉到同一控制器的 Edit 操作,並且我們希望明確說明此表單上的方法應該使用 HttpPost。
表單的預設方法是 GET,我們不希望使用 GET 操作來編輯員工。
在 label 標記中,我們使用了 asp-for 標籤助手,它表示這是模型的 Name 屬性的標籤。此標籤助手可以設定 Html.For 屬性以具有正確的值並設定此標籤的內部文字,以便它實際顯示我們想要的內容,例如員工姓名。
讓我們轉到 HomeController 類並新增 **Edit** 操作,該操作返回一個檢視,該檢視為使用者提供一個表單來編輯員工,然後我們需要第二個 Edit 操作來響應 HttpPost,如下所示。
[HttpGet]
public IActionResult Edit(int id) {
var context = new FirstAppDemoDbContext();
SQLEmployeeData sqlData = new SQLEmployeeData(context);
var model = sqlData.Get(id);
if (model == null) {
return RedirectToAction("Index");
}
return View(model);
}
首先,我們需要一個將響應 GET 請求的 edit 操作。它將採用員工 ID。此處的程式碼將類似於我們 Details 操作中的程式碼。我們將首先提取使用者想要編輯的員工的資料。我們還需要確保員工確實存在。如果不存在,我們將把使用者重定向回 Index 檢視。但是,當員工存在時,我們將呈現 Edit 檢視。
我們還需要響應表單將傳送的 HttpPost。
讓我們在 HomeController.cs 檔案中新增一個新類,如下面的程式所示。
public class EmployeeEditViewModel {
[Required, MaxLength(80)]
public string Name { get; set; }
}
在將響應 HttpPost 的 Edit 操作中,將採用 EmployeeEditViewModel,而不是員工本身,因為我們只想捕獲 Edit.cshtml 檔案中表單中的專案。
以下是 Edit 操作的實現。
[HttpPost]
public IActionResult Edit(int id, EmployeeEditViewModel input) {
var context = new FirstAppDemoDbContext();
SQLEmployeeData sqlData = new SQLEmployeeData(context);
var employee = sqlData.Get(id);
if (employee != null && ModelState.IsValid) {
employee.Name = input.Name;
context.SaveChanges();
return RedirectToAction("Details", new { id = employee.Id });
}
return View(employee);
}
根據我們的路由規則,編輯表單應始終從 URL 中包含 ID 的 URL 傳遞,例如 **/home/edit/1**。
表單將始終釋出回同一個 URL,/home/edit/1。
MVC 框架將能夠從 URL 中提取該 ID 並將其作為引數傳遞。
我們始終需要檢查 ModelState 是否有效,並確保此員工在資料庫中並且在執行資料庫更新操作之前不為空。
如果這些都不成立,我們將返回一個檢視並允許使用者重試。儘管在具有併發使用者的實際應用程式中,如果員工為空,則可能是因為員工詳細資訊被其他人刪除了。
如果該員工不存在,則告訴使用者該員工不存在。
否則,檢查 ModelState。如果 ModelState 無效,則返回一個檢視。這允許修復編輯並使 ModelState 有效。
將名稱從 Input 檢視模型複製到從資料庫檢索的員工,並儲存更改。SaveChagnes() 方法將把所有這些更改重新整理到資料庫。
以下是 HomeController 的完整實現。
using Microsoft.AspNet.Mvc;
using FirstAppDemo.ViewModels;
using FirstAppDemo.Services;
using FirstAppDemo.Entities;
using FirstAppDemo.Models;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel.DataAnnotations;
namespace FirstAppDemo.Controllers {
public class HomeController : Controller {
public ViewResult Index() {
var model = new HomePageViewModel();
using (var context = new FirstAppDemoDbContext()) {
SQLEmployeeData sqlData = new SQLEmployeeData(context);
model.Employees = sqlData.GetAll();
}
return View(model);
}
public IActionResult Details(int id) {
var context = new FirstAppDemoDbContext();
SQLEmployeeData sqlData = new SQLEmployeeData(context);
var model = sqlData.Get(id)
if (model == null) {
return RedirectToAction("Index");
}
return View(model);
}
[HttpGet]
public IActionResult Edit(int id) {
var context = new FirstAppDemoDbContext();
SQLEmployeeData sqlData = new SQLEmployeeData(context);
var model = sqlData.Get(id);
if (model == null) {
return RedirectToAction("Index");
}
return View(model);
}
[HttpPost]
public IActionResult Edit(int id, EmployeeEditViewModel input) {
var context = new FirstAppDemoDbContext();
SQLEmployeeData sqlData = new SQLEmployeeData(context);
var employee = sqlData.Get(id);
if (employee != null && ModelState.IsValid) {
employee.Name = input.Name;
context.SaveChanges();
return RedirectToAction("Details", new { id = employee.Id });
}
return View(employee);
}
}
public class SQLEmployeeData {
private FirstAppDemoDbContext _context { get; set; }
public SQLEmployeeData(FirstAppDemoDbContext context) {
_context = context;
}
public void Add(Employee emp) {
_context.Add(emp);
_context.SaveChanges();
}
public Employee Get(int ID) {
return _context.Employees.FirstOrDefault(e => e.Id == ID);
}
public IEnumerable<Employee> GetAll() {
return _context.Employees.ToList<Employee>();
}
}
public class HomePageViewModel {
public IEnumerable<Employee> Employees { get; set; }
}
public class EmployeeEditViewModel {
[Required, MaxLength(80)]
public string Name { get; set; }
}
}
讓我們編譯程式並執行應用程式。
我們現在有一個 Edit 連結可用;讓我們透過點選 Edit 連結來編輯 Josh 的詳細資訊。
讓我們將名稱更改為 Josh Groban。
點選儲存按鈕。
您可以看到名稱已更改為 Josh Groban,如上面的螢幕截圖所示。現在讓我們點選主頁連結。
在主頁上,您現在將看到更新後的名稱。
ASP.NET Core - 身份概述
在本章中,我們將簡要討論 ASP.NET Core Identity 框架。ASP.NET Core Identity 框架用於實現表單身份驗證。有許多選項可用於識別您的使用者,包括 Windows 身份驗證和所有第三方身份提供商,例如 Google、Microsoft、Facebook 和 GitHub 等。
Identity 框架是我們將新增到 project.js 檔案中應用程式中的另一個依賴項。
此框架允許我們新增使用者可以使用本地密碼註冊和登入的功能。
該框架還支援雙因素身份驗證、第三方身份提供商和其他功能。
我們將重點關注使用者可以註冊、登入和登出的場景。
為此,我們需要建立一個 User 實體,此類將繼承自 Identity 框架中的基類,並且基類為我們提供了標準的使用者屬性,例如使用者名稱和電子郵件地址。
我們可以在此類中包含任意數量的其他屬性來儲存有關我們使用者的資訊。
我們需要獲取此 User 類並將其插入到 Identity 框架提供的 UserStore 類中。
UserStore 是我們的程式碼將用於建立使用者和驗證使用者密碼的類。
最終,UserStore 將與資料庫進行通訊。Identity 框架支援 Entity Framework 和所有可以與 Entity Framework 一起使用的資料庫。
但是您可以實現自己的 UserStore 來與任何資料來源一起使用。
為了與 Entity Framework 正確協作,我們的 User 類也將插入到 IdentityDb 類中。
這是一個使用 Entity Framework DBContext 執行實際資料庫工作的類。
我們需要透過使現有的 DataContext 類繼承自 IdentityDb 而不是 Entity Framework 的 DBContext 來將此 IdentityDb 包含到我們的應用程式中。
正是 IdentityDb 和 UserStore 協同工作來儲存使用者資訊和驗證使用者密碼(資料庫中的雜湊密碼)。
我們需要了解 ASP.NET Core Identity 框架的兩個部分
SignInManager
這是 Identity 框架的兩個部分之一 -
顧名思義,**SignInManager** 可以在我們驗證密碼後登入使用者。
我們還可以使用此管理器登出使用者。
對於表單身份驗證,登入和登出是透過管理 cookie 來完成的。
當我們告訴 SignInManager 登入使用者時,管理器會向用戶的瀏覽器發出一個 cookie,並且瀏覽器將在每個後續請求中傳送此 cookie。它有助於我們識別該使用者。
Identity 中介軟體
這是框架的第二個部分 -
讀取 SignInManager 傳送的 Cookie 並識別使用者,這發生在框架的最後部分,即 Identity 中介軟體。
我們需要將此中介軟體配置到我們的應用程式管道中以處理 SignInManager 設定的 Cookie。我們還將在接下來的幾章中看到此中介軟體的一些其他功能。
ASP.NET Core - 授權屬性
在本章中,我們將討論 Authorize 屬性。到目前為止,在我們的應用程式中,我們允許匿名使用者執行任何操作。他們可以編輯員工詳細資訊和檢視詳細資訊,但我們沒有建立新員工的功能。讓我們首先新增建立功能,然後我們將使用 Authorize 屬性限制使用者訪問。
我們需要首先在 **Views → Home** 資料夾內建立一個新的 MVC 檢視頁面,並將其命名為 Create.cshtml,然後新增以下程式碼。
@model Employee
@{
ViewBag.Title = "Create";
}
<h1>Create</h1>
@using (Html.BeginForm()) {
<div>
@Html.LabelFor(m => m.Name)
@Html.EditorFor(m => m.Name)
@Html.ValidationMessageFor(m => m.Name)
</div>
<div>
<input type = "submit" value = "Save" />
</div>
}
現在,我們將為 POST 和 GET 在 HomeController 中新增 **操作方法**,如下面的程式所示。
[HttpGet]
public ViewResult Create() {
return View();
}
[HttpPost]
public IActionResult Create(EmployeeEditViewModel model) {
if (ModelState.IsValid) {
var employee = new Employee();
employee.Name = model.Name;
var context = new FirstAppDemoDbContext();
SQLEmployeeData sqlData = new SQLEmployeeData(context);
sqlData.Add(employee);
return RedirectToAction("Details", new { id = employee.Id });
}
return View();
}
讓我們在 Index.cshtml 檔案中新增一個指向 **Create 檢視** 的連結,如下面的程式所示。
@model HomePageViewModel
@{
ViewBag.Title = "Home";
}
<h1>Welcome!</h1>
<table>
@foreach (var employee in Model.Employees) {
<tr>
<td>@employee.Name
<td>
<a asp-controller = "Home" asp-action = "Details"
asp-routeid = "@employee.Id">Details</a>
<a asp-controller = "Home" asp-action = "Edit"
asp-routeid = "@employee.Id">Edit</a>
</td>
</tr>
}
</table>
<div>
<a asp-action = "Create">Create</a>
</div>
執行應用程式;您將看到以下頁面。
在主頁上,您將看到“建立”連結。當您單擊“建立”連結時,它將帶您到“建立”檢視。
在“姓名”欄位中輸入姓名,然後單擊“儲存”按鈕。
您現在將看到新新增的員工的 **詳細資訊檢視**。讓我們單擊“主頁”連結。
在此應用程式中,每個使用者都可以建立、編輯員工,並且每個人都可以檢視詳細資訊檢視。我們希望更改此行為,以便將來,匿名使用者只能檢視主頁上的員工列表,但其他所有操作都需要使用者識別自己並登入。我們可以使用 **Authorize 屬性** 來實現這一點。
您可以將 Authorize 屬性放置在控制器上或控制器內的單個操作上。
[Authorize]
public class HomeController : Controller {
//....
}
當我們將 Authorize 屬性放置在控制器本身時,授權屬性將應用於其中的所有操作。
除非使用者透過授權檢查,否則 MVC 框架將不允許請求到達受此屬性保護的操作。
預設情況下,如果您不使用任何其他引數,Authorize 屬性將執行的唯一檢查是檢查以確保使用者已登入,以便我們知道他們的身份。
但是您可以使用引數來指定您喜歡的任何花哨的自定義授權策略。
還有一個 **AllowAnonymous** 屬性。當您想在控制器上使用 Authorize 屬性來保護其中的所有操作,但又有一個或兩個操作您希望取消保護並允許匿名使用者訪問該特定操作時,此屬性很有用。
[AllowAnonymous]
public ViewResult Index() {
var model = new HomePageViewModel();
using (var context = new FirstAppDemoDbContext()) {
SQLEmployeeData sqlData = new SQLEmployeeData(context);
model.Employees = sqlData.GetAll();
}
return View(model);
}
讓我們在我們的應用程式中嘗試這些屬性。在執行的應用程式中,匿名使用者可以編輯員工。
我們希望更改此設定,並強制使用者在編輯員工之前登入並識別自己。現在讓我們進入 HomeController。我們將在此處限制對一兩個操作的訪問。我們始終可以將 Authorize 屬性放置在我們想要保護的那些特定操作上。我們也可以將 Authorize 屬性放置在控制器本身,此 Authorize 屬性位於 Microsoft.AspNet.Authorization 名稱空間中。
現在,我們將使用 Authorize 屬性並強制使用者識別自己才能進入此控制器,但主頁除外,如下面的程式所示。
[Authorize]
public class HomeController : Controller {
[AllowAnonymous]
public ViewResult Index() {
var model = new HomePageViewModel();
using (var context = new FirstAppDemoDbContext()) {
SQLEmployeeData sqlData = new SQLEmployeeData(context);
model.Employees = sqlData.GetAll();
}
return View(model);
}
public IActionResult Details(int id) {
var context = new FirstAppDemoDbContext();
SQLEmployeeData sqlData = new SQLEmployeeData(context);
var model = sqlData.Get(id);
if (model == null) {
return RedirectToAction("Index");
}
return View(model);
}
[HttpGet]
public IActionResult Edit(int id) {
var context = new FirstAppDemoDbContext();
SQLEmployeeData sqlData = new SQLEmployeeData(context);
var model = sqlData.Get(id);
if (model == null) {
return RedirectToAction("Index");
}
return View(model);
}
[HttpPost]
public IActionResult Edit(int id, EmployeeEditViewModel input) {
var context = new FirstAppDemoDbContext();
SQLEmployeeData sqlData = new SQLEmployeeData(context);
var employee = sqlData.Get(id);
if (employee != null && ModelState.IsValid) {
employee.Name = input.Name;
context.SaveChanges();
return RedirectToAction("Details", new { id = employee.Id });
}
return View(employee);
}
[HttpGet]
public ViewResult Create() {
return View();
}
[HttpPost]
public IActionResult Create(EmployeeEditViewModel model) {
if (ModelState.IsValid) {
var employee = new Employee();
employee.Name = model.Name;
var context = new FirstAppDemoDbContext();
SQLEmployeeData sqlData = new SQLEmployeeData(context);
sqlData.Add(employee);
return RedirectToAction("Details", new { id = employee.Id });
}
return View();
}
}
顯示員工列表的主頁或 **Index.cshtml** 檔案具有 **AllowAnonymous 屬性**。現在讓我們執行您的應用程式。
按 F12 鍵,這將開啟 **開發者工具**。現在,轉到 **網路** 選項卡。
在開發者工具中,我們想觀察一些內容,以便我們可以瞭解事情是如何運作的。當您單擊“編輯”連結時,您將看到一個空白頁面。
如果您檢視開發者工具,您會看到伺服器返回的 HTTP 狀態程式碼是 **401 狀態程式碼**。
401 狀態程式碼告訴瀏覽器該請求未被允許透過,因為它缺少有效的身份驗證憑據。這告訴我們 Authorize 屬性正在工作。
同樣,當您單擊主頁上的“建立”連結時,您將看到與以下螢幕截圖相同的錯誤。
這裡,不好的地方在於使用者被留在一個空白頁面上,除非他們打開了開發者工具,否則他們可能不知道這是一個身份驗證問題。
這就是 Identity 框架可以介入並提供幫助的地方。
Identity 框架可以檢測到應用程式的某個部分何時想要返回 401 狀態程式碼,因為使用者不允許到達那裡,並且 Identity 框架可以將其轉換為登入頁面,並允許使用者解決此問題。
一旦我們安裝並配置了 Identity 框架,我們將瞭解其工作原理。
但現在,我們可以看到 **Authorize 屬性** 正在工作。
ASP.NET Core - Identity 配置
在本章中,我們將安裝和配置 Identity 框架,這隻需要少量的工作。如果您轉到 Visual Studio 並建立一個新的 ASP.NET Core 應用程式,並且您選擇帶有身份驗證設定為單個使用者帳戶的完整 Web 應用程式模板,則該新專案將包含為您設定的所有 Identity 框架位。
我們從一個空專案開始。我們現在將從頭開始設定 Identity 框架,這是一種瞭解完整應用程式模板中所有部分的好方法,因為如果您沒有詳細地遍歷所有程式碼,它可能會令人困惑。
首先,我們需要安裝依賴項,即 **Microsoft.AspNet.Identity**。我們將繼續安裝 **Microsoft.AspNet.Identity.EntityFramework**,然後實現與 Entity Framework 協同工作的 Identity 框架。
如果我們依賴 Identity.EntityFramework,則該包包含 Identity 包。
如果您構建自己的資料儲存,則可以使用 Identity 包。
安裝完依賴項後,我們可以建立一個客戶 User 類,其中包含我們想要儲存的有關使用者的所有資訊。
對於此應用程式,我們將從 Identity 框架提供的類繼承,該類將為我們提供所有基本要素,例如 Username 屬性和儲存雜湊密碼的位置。
我們還需要修改我們的 **FirstAppDemoDbContext** 類以從 Identity 框架的 **IdentityDb** 類繼承。
IdentityDb 為我們提供了使用 Entity Framework 儲存使用者資訊所需的一切。一旦我們有了 User 類和 **DBContext**,我們就需要使用 Startup 類的 **ConfigureServices** 方法將 Identity 服務配置到應用程式中。
就像我們需要新增服務來支援 MVC 框架一樣,Identity 框架也需要嚮應用程式新增服務才能工作。
這些服務包括 **UserStore** 服務和 **SignInManager** 等服務。
我們將把這些服務注入到我們的控制器中,以便在適當的時間建立使用者和發出 Cookie。
最後,在啟動的 Configure 方法期間,我們需要新增 Identity 中介軟體。
此中介軟體不僅有助於將 Cookie 轉換為使用者身份,而且還可以確保使用者不會看到帶有 401 響應的空白頁面。
現在讓我們按照以下步驟操作。
**步驟 1** - 我們需要繼續新增對 Identity 框架的依賴項。讓我們將 Microsoft.AspNet.Identity.EntityFramework 依賴項新增到 project.json 檔案中。這將包含我們需要的其他所有必要的 Identity 包。
{
"version": "1.0.0-*",
"compilationOptions": {
"emitEntryPoint": true
},
"dependencies": {
"Microsoft.AspNet.Mvc": "6.0.0-rc1-final",
"Microsoft.AspNet.Diagnostics": "1.0.0-rc1-final",
"Microsoft.AspNet.IISPlatformHandler": "1.0.0-rc1-final",
"Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final",
"Microsoft.AspNet.StaticFiles": "1.0.0-rc1-final",
"EntityFramework.MicrosoftSqlServer": "7.0.0-rc1-final",
"EntityFramework.Commands": "7.0.0-rc1-final",
"Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-rc1-final",
"Microsoft.AspNet.Identity.EntityFramework": "3.0.0-rc1-final"
},
"commands": {
"web": "Microsoft.AspNet.Server.Kestrel",
"ef": "EntityFramework.Commands"
},
"frameworks": {
"dnx451": { },
"dnxcore50": { }
},
"exclude": [
"wwwroot",
"node_modules"
],
"publishExclude": [
"**.user",
"**.vspscc"
]
}
**步驟 2** - 儲存此檔案。Visual Studio 會還原包,現在我們可以新增我們的 User 類。讓我們透過右鍵單擊 Models 資料夾並選擇新增 → 類來新增 User 類。
將此類命名為 User 並單擊“新增”按鈕,如上圖所示。在此類中,您可以新增屬性以儲存您想要儲存的有關使用者的任何資訊。
**步驟 3** - 讓我們從 Identity 框架提供的類派生 User 類。它是 IdentityUser 類,位於 Identity.EntityFramework 名稱空間中。
using Microsoft.AspNet.Identity.EntityFramework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace FirstAppDemo.Models {
public class User : IdentityUser {
}
}
**步驟 4**- 現在讓我們轉到 IdentityUser,將游標放在該符號上,然後按 F12 以檢視 Visual Studio 的元資料檢視。
#region Assembly Microsoft.AspNet.Identity.EntityFramework, Version = 3.0.0.0,
namespace Microsoft.AspNet.Identity.EntityFramework {
public class IdentityUser : IdentityUser<string> {
public IdentityUser();
public IdentityUser(string userName);
}
}
**步驟 5** - 您可以看到 IdentityUser 是從字串的 IdentityUser 派生的。您可以透過從 IdentityUser 派生並指定我們的泛型型別引數來更改主鍵的型別。您還可以使用主鍵儲存內容,該主鍵理想情況下是一個整數值。
**步驟 6** - 現在讓我們將游標放在字串的 IdentityUser 上,然後再次按 F12 以轉到元資料檢視。
您現在可以看到預設情況下與使用者相關的所有資訊。資訊包括以下內容 -
我們不會在此應用程式中使用的欄位,但可供使用。
Identity 框架可以跟蹤特定使用者的失敗登入嘗試次數,並在一段時間內鎖定該帳戶。
儲存 PasswordHash、PhoneNumber 的欄位。我們將使用的兩個重要欄位是 PasswordHash 和 UserName。
我們還將隱式使用使用者的 PrimaryKey 和 ID 屬性。如果您需要查詢特定使用者,也可以使用該屬性。
**步驟 7** - 現在,我們需要確保 User 包含在我們的 DBContext 中。因此,讓我們開啟應用程式中存在的 **FirstAppDemoDBContext**,而不是直接從 DBContext 派生,DBContext 是內建的 Entity Framework 基類,我們現在需要從 IdentityDbContext 派生。
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.Data.Entity;
namespace FirstAppDemo.Models {
public class FirstAppDemoDbContext : IdentityDbContext<User> {
public DbSet<Employee> Employees { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
optionsBuilder.UseSqlServer("Data Source = (localdb)\\MSSQLLocalDB;
Initial Catalog = FirstAppDemo;Integrated Security = True;
Connect Timeout = 30;Encrypt = False;TrustServerCertificate = True;
ApplicationIntent = ReadWrite;MultiSubnetFailover = False");
}
}
}
**步驟 8** - IdentityDbContext 類也位於 Microsoft.AspNet.Identity.EntityFramework 名稱空間中,我們可以指定它應該儲存的使用者型別。這樣,我們新增到 User 類的任何其他欄位都會進入資料庫。
IdentityDbContext 除了用於儲存使用者資訊外,還引入了額外的 DbSet,用於儲存使用者角色和使用者宣告資訊。
現在,我們的 User 類已準備就緒。FirstAppDemoDbContext 類已配置為與 Identity 框架配合使用。
現在,我們可以進入 Configure 和 ConfigureServices 來設定 Identity 框架。
步驟 9 − 現在讓我們從 ConfigureServices 開始。除了 MVC 服務和 Entity Framework 服務之外,我們還需要新增 Identity 服務。這將新增 Identity 框架依賴的所有服務,以使其正常工作。
public void ConfigureServices(IServiceCollection services) {
services.AddMvc();
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<FirstAppDemoDbContext>
(option => option.UseSqlServer(Configuration["database:connection"]));
services.AddIdentity<User, IdentityRole>()
.AddEntityFrameworkStores<FirstAppDemoDbContext>();
}
AddIdentity 方法接受兩個泛型型別引數——使用者實體型別和角色實體型別。
這兩個泛型型別引數是我們使用者的型別——我們剛剛建立的 User 類和我們想要使用的 Role 類。現在,我們將使用內建的 IdentityRole。此類位於 EntityFramework 名稱空間中。
當我們使用 Entity Framework 與 Identity 時,還需要呼叫第二個方法——AddEntityFrameworkStores。
AddEntityFrameworkStores 方法將配置諸如 UserStore 之類的服務,該服務用於建立使用者並驗證其密碼。
步驟 10 − 以下兩行是我們配置應用程式服務所需的所有內容。
services.AddIdentity<User, IdentityRole>() .AddEntityFrameworkStores<FirstAppDemoDbContext>();
步驟 11 − 我們還需要新增中介軟體。插入中介軟體的位置很重要,因為如果我們過晚地插入中介軟體,它將永遠沒有機會處理請求。
如果我們在 MVC 控制器內部需要授權檢查,則需要在 MVC 框架之前插入 Identity 中介軟體,以確保 cookie 和 401 錯誤能夠成功處理。
public void Configure(IApplicationBuilder app) {
app.UseIISPlatformHandler();
app.UseDeveloperExceptionPage();
app.UseRuntimeInfoPage();
app.UseFileServer();
app.UseIdentity();
app.UseMvc(ConfigureRoute);
app.Run(async (context) => {
var msg = Configuration["message"];
await context.Response.WriteAsync(msg);
});
}
步驟 12 − 我們插入中介軟體的位置就是新增 Identity 中介軟體的位置。以下是 Startup.cs 檔案的完整實現。
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using FirstAppDemo.Services;
using Microsoft.AspNet.Routing;
using System;
using FirstAppDemo.Entities;
using Microsoft.Data.Entity;
using FirstAppDemo.Models;
using Microsoft.AspNet.Identity.EntityFramework;
namespace FirstAppDemo {
public class Startup {
public Startup() {
var builder = new ConfigurationBuilder()
.AddJsonFile("AppSettings.json");
Configuration = builder.Build();
}
public IConfiguration Configuration { get; set; }
// This method gets called by the runtime.
// Use this method to add services to the container.
// For more information on how to configure your application,
// visit http://go.microsoft.com/fwlink/?LinkID = 398940
public void ConfigureServices(IServiceCollection services) {
services.AddMvc();
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<FirstAppDemoDbContext>(option =>
option.UseSqlServer(Configuration["database:connection"]));
services.AddIdentity<User, IdentityRole>()
.AddEntityFrameworkStores<FirstAppDemoDbContext>();
}
// This method gets called by the runtime.
// Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app) {
app.UseIISPlatformHandler();
app.UseDeveloperExceptionPage();
app.UseRuntimeInfoPage();
app.UseFileServer();
app.UseIdentity();
app.UseMvc(ConfigureRoute);
app.Run(async (context) => {
var msg = Configuration["message"];
await context.Response.WriteAsync(msg);
});
}
private void ConfigureRoute(IRouteBuilder routeBuilder) {
//Home/Index
routeBuilder.MapRoute("Default", "{controller=Home}/{action=Index}/{id?}");
}
// Entry point for the application.
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}
}
步驟 13 − 現在讓我們繼續構建應用程式。在下一章中,我們需要新增另一個 Entity Framework 遷移,以確保我們在 SQL Server 資料庫中擁有 Identity 架構。
ASP.NET Core - 身份遷移
在本章中,我們將討論 Identity 遷移。在 ASP.NET Core MVC 中,身份驗證和身份功能在 Startup.cs 檔案中配置。
public void ConfigureServices(IServiceCollection services) {
services.AddMvc();
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<FirstAppDemoDbContext>option.
UseSqlServer(Configuration["database:connection"]));
services.AddIdentity<User, IdentityRole>()
.AddEntityFrameworkStores<FirstAppDemoDbContext>();
}
每當您對其中一個實體類進行更改或對派生自 DBContext 的類進行更改時,您可能都需要建立一個新的遷移指令碼以應用於資料庫並將架構與程式碼中的內容同步。
在我們的應用程式中就是這樣,因為我們現在將 FirstAppDemoDbContext 類派生自 IdentityDbContext 類,它包含自己的 DbSet,並且還將建立一個架構來儲存其管理的所有實體的資訊。
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.Data.Entity;
namespace FirstAppDemo.Models {
public class FirstAppDemoDbContext : IdentityDbContext<User> {
public DbSet<Employee> Employees { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
optionsBuilder.UseSqlServer("Data Source = (localdb)\\MSSQLLocalDB;
Initial Catalog = FirstAppDemo;Integrated Security = True;
Connect Timeout = 30;Encrypt = False;
TrustServerCertificate = True;ApplicationIntent = ReadWrite;
MultiSubnetFailover = False");
}
}
}
現在,讓我們開啟命令提示符並確保我們位於專案的 project.json 檔案所在的目錄中。
我們還可以透過鍵入 dnx ef 來獲取 Entity Framework 命令。
我們的 project.json 檔案有一個部分將此“ef”關鍵字對映到 EntityFramework.Commands。
"commands": {
"web": "Microsoft.AspNet.Server.Kestrel",
"ef": "EntityFramework.Commands"
}
我們可以從此處新增遷移。我們還需要為遷移提供一個名稱。讓我們使用 v2 表示版本 2 並按 Enter 鍵。
遷移完成後,您將在 migrations 資料夾中有一個 v2 檔案。
現在,我們希望透過執行 “dnx ef database update” 命令將該遷移應用於我們的資料庫。
Entity Framework 將看到需要應用的遷移,並將執行該遷移。
如果您進入 SQL Server 物件資源管理器,您將看到我們之前建立的 Employee 表。您還將看到一些其他表,這些表用於儲存使用者、宣告、角色以及一些將使用者對映到特定角色的對映表。
所有這些表都與 Identity 框架提供的實體相關。
讓我們快速瀏覽一下 users 表。
您現在可以看到 AspNetUsers 表中的列包括儲存我們在繼承的 Identity User 上看到的那些屬性的所有列,以及它的欄位,如 UserName 和 PasswordHash。因此,您一直在使用一些內建的 Identity 服務,因為它們還包含建立使用者和驗證使用者密碼的功能。
ASP.NET Core - 使用者註冊
在本章中,我們將討論使用者註冊。我們現在擁有一個可用的資料庫,現在是時候開始嚮應用程式新增一些功能了。我們還配置了我們的應用程式,並且擁有一個可用的資料庫架構。現在讓我們轉到應用程式的主頁。
按 F12 開啟開發者工具,然後單擊“編輯”連結。以前,當我們單擊“編輯”連結時,MVC 框架檢測到 Authorize 屬性的存在並返回 401 狀態程式碼,因為使用者未登入。
您現在將看到我們在螢幕上收到來自配置檔案的訊息。
現在讓我們轉到開發者工具。
您將看到瀏覽器請求了編輯頁面,MVC 框架確定使用者無權檢視此資源。
因此,在 MVC 框架內部的某個地方生成了 401 狀態程式碼。
我們現在已經到位了 Identity 中介軟體。Identity 中介軟體檢視將傳送給使用者的 401 狀態程式碼,並將其替換為 302 狀態程式碼,這是一個重定向狀態程式碼。
Identity 框架知道使用者必須先嚐試登入才能訪問此資源。
Identity 框架將我們重定向到此 URL,如我們在位址列中看到的——/Account/Login。
這是一個可配置的端點,位於 Identity 框架中,在您註冊這些服務和中介軟體時位於 Startup 中。您可以設定不同的選項,其中一個選項是更改登入 URL。
預設情況下,URL 將為 /Account/Login。目前,我們還沒有帳戶控制器,因此最終我們要做的是建立一個帳戶控制器並允許使用者登入。
但在使用者甚至登入之前,他們需要在網站上註冊並儲存其使用者名稱和密碼。
登入和註冊功能都可以是帳戶控制器的部分。
現在讓我們繼續在 Controllers 資料夾中新增一個新類,並將其命名為 AccountController。我們將從 MVC 框架的基類 Controller 類派生此類。
using Microsoft.AspNet.Mvc;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace FirstAppDemo.Controllers {
public class AccountController : Controller {
}
}
現在,我們需要設定一個功能,以便使用者可以註冊此網站。
它將非常類似於編輯表單。
當用戶想要註冊時,我們首先會顯示一個表單,允許他們填寫所需的資訊。然後,他們可以將此表單上傳到網站。
然後將此資訊儲存在資料庫中。
現在讓我們建立當我們轉到 /account/register 時將返回檢視的操作。
public class AccountController : Controller {
[HttpGet]
public ViewResult Register() {
return View();
}
}
我們不需要查詢任何內容,使用者將提供我們所需的所有資訊。在我們構建該檢視的 ViewModel 之前,我們需要確定檢視將顯示哪些資訊。我們還需要確定我們需要從使用者那裡接收哪些資訊?
讓我們透過在 AccountController.cs 檔案中新增一個新類並將其命名為 RegisterViewModel 來為此場景建立一個檢視模型。
讓我們建立一些屬性來儲存使用者名稱、密碼以及使用者確認密碼(兩次輸入並確保兩個密碼匹配),如下面的程式所示。
public class RegisterViewModel {
[Required, MaxLength(256)]
public string Username { get; set; }
[Required, DataType(DataType.Password)]
public string Password { get; set; }
[DataType(DataType.Password), Compare(nameof(Password))]
public string ConfirmPassword { get; set; }
}
在上面的類中,您可以看到一些可以幫助我們驗證此模型的註釋。此處的使用者名稱是必需的,如果您檢視資料庫架構,則儲存使用者名稱的列長度為 256 個字元。
我們還將在此處應用 MaxLength 屬性。
密碼將是必需的,當我們為該密碼呈現輸入時,我們希望輸入型別為 Type Password,以便字元不會顯示在螢幕上。
確認密碼也將是 DataType Password,然後還有一個額外的 Compare 屬性。我們將使用我們可以指定的另一個屬性(即 Password 欄位)來比較 ConfirmPassword 欄位。
現在讓我們建立所需的檢視。我們需要向 views 新增一個新資料夾並將其命名為 Account,以便與 AccountController 相關的所有檢視都將新增到此資料夾中。
現在,右鍵單擊 Account 資料夾並選擇新增→新建項。
在中間窗格中,選擇 MVC 檢視頁面並將其命名為 Register.cshtml,然後單擊“新增”按鈕。
從 Register.cshtml 檔案中刪除所有現有程式碼並新增以下程式碼。
@model RegisterViewModel
@{
ViewBag.Title = "Register";
}
<h1>Register</h1>
<form method = "post" asp-controller = "Account" asp-action = "Register">
<div asp-validation-summary = "ValidationSummary.ModelOnly"></div>
<div>
<label asp-for = "Username"></label>
<input asp-for = "Username" />
<span asp-validation-for = "Username"></span>
</div>
<div>
<label asp-for = "Password"></label>
<input asp-for = "Password" />
<span asp-validation-for = "Password"></span>
</div>
<div>
<label asp-for = "ConfirmPassword"></label>
<input asp-for = "ConfirmPassword" />
<span asp-validation-for = "ConfirmPassword"></span>
</div>
<div>
<input type = "submit" value = "Register" />
</div>
</form>
您現在可以看到我們已將模型指定為我們剛剛建立的 RegisterViewModel。
我們還將使用 ViewBag 設定此頁面的標題,並且希望標題為 Register。
我們還需要建立一個包含使用者名稱、密碼和確認密碼欄位的表單。
我們還包括一個將顯示驗證摘要的 div。當我們使用 ASP 驗證摘要時,我們需要指定哪些錯誤將顯示在摘要中。
我們可以讓所有錯誤都顯示在摘要區域中,或者我們可以說 ValidationSummary.ModelOnly,並且在摘要中僅顯示來自模型驗證的錯誤將是與模型關聯的驗證錯誤,而不是該模型的特定屬性。
換句話說,如果使用者未填寫其使用者名稱,但使用者名稱是必需的,則該特定屬性將存在驗證錯誤。
但您還可以生成與特定屬性無關的模型錯誤,它們將顯示在此 ValidationSummary 中。
在 <form> 標記內,我們有針對 ViewModel 中所有不同欄位的標籤和輸入。
我們需要使用者名稱標籤、使用者名稱輸入以及使用者名稱驗證訊息。
我們需要使用者輸入的其他兩個屬性相同,並且將有一個標籤和輸入以及一個用於密碼的 span 以及一個標籤和一個輸入以及一個用於確認密碼的 span。
我們不需要為 Password 和 ConfirmPassword 指定輸入型別,因為 asp for 標記助手將確保為我們將其輸入型別設定為密碼。
最後,我們需要有一個顯示 Register 的按鈕。當用戶單擊此按鈕時,我們將把表單提交回控制器。
在 AccountController 中,我們還需要實現一個 HttpPost Register 操作方法。讓我們返回到 AccountController 並新增以下 Register 操作,如下所示:
[HttpPost]
public IActionResult Register (RegisterViewModel model) {
}
此操作方法將返回 IActionResult。這將接收 RegisterViewModel。現在,我們需要與 Identity 框架互動以確保使用者有效,告訴 Identity 框架建立該使用者,然後由於他們剛剛建立了帳戶,因此繼續登入他們。我們將在下一章中介紹如何實現所有這些步驟。
ASP.NET Core - 建立使用者
在本章中,我們將討論如何建立使用者。要繼續執行此操作,我們需要與 Identity 框架互動以確保使用者有效,然後建立該使用者,然後繼續登入他們。
Identity 框架有兩個核心服務,一個是UserManager,另一個是SignInManager。
我們需要將這兩個服務注入到我們的控制器中。這樣,當我們需要建立使用者或登入使用者時,就可以呼叫相應的 API。
讓我們為 SignInManager 和 UserManager 新增私有變數,然後在 AccountController 中新增一個建構函式,該建構函式將接收兩個引數:型別為 User 的 UserManager 和型別為 User 的 SignInManager。
private SignInManager<User> _signManager;
private UserManager<User> _userManager;
public AccountController(UserManager<User> userManager, SignInManager<User> signManager){
_userManager = userManager;
_signManager = signManager;
}
我們將繼續使用 AccountController 的 POST 操作方法,並且在 post 操作中我們應該始終進行的第一個檢查之一是檢查我們的 ModelState 是否有效。
如果 ModelState 有效,那麼我們知道使用者給了我們使用者名稱和密碼並確認了密碼;如果不是,我們需要讓他們提供正確的資訊。
以下是 Register 操作的實現。
[HttpPost]
public async Task<IActionResult> Register(RegisterViewModel model) {
if (ModelState.IsValid) {
var user = new User { UserName = model.Username };
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded) {
await _signManager.SignInAsync(user, false);
return RedirectToAction("Index", "Home");
} else {
foreach (var error in result.Errors) {
ModelState.AddModelError("", error.Description);
}
}
}
return View();
}
如果我們的ModelState有效,我們需要與 Identity 框架通訊。我們還需要建立一個 User 實體的新例項,並將我們的輸入model.Username複製到 User 實體的UserName屬性中。
但是,我們不會複製密碼,因為在 User 實體中沒有地方儲存純文字密碼。相反,我們將密碼直接傳遞給 Identity 框架,它將對密碼進行雜湊處理。
所以我們有一個 userManager。建立一個非同步方法,我們需要將使用者名稱傳遞給它,以便我們可以儲存該使用者的密碼。
此非同步方法返回一個結果,告訴我們例項是成功還是失敗,如果失敗,它會提供一些可能失敗的原因。
如果結果成功,我們可以登入剛剛建立帳戶的使用者,然後要求 SignInManager 登入此使用者。現在,將使用者重定向回主頁,您現在將被認證。
如果結果不成功,那麼我們應該嘗試告訴使用者原因,並且從 UserManager 返回的結果包含一個錯誤集合,我們可以遍歷這些錯誤並將這些錯誤新增到 ModelState 中。這些錯誤將在檢視中用於驗證標籤助手(如驗證標籤助手),以在頁面上顯示資訊。
在 ModelState.AddModelError 中,我們可以提供一個鍵來將錯誤與特定欄位關聯。我們還將使用空字串並新增提供的錯誤描述。
讓我們儲存所有檔案並執行應用程式,然後轉到/account/register。
讓我們輸入一個使用者名稱和一個非常簡單的 5 字元密碼。
現在,點選註冊按鈕。
預設情況下,Identity 框架嘗試對密碼執行一些規則。
密碼必須至少包含 6 個字元,一個字元必須是小寫,一個必須是大寫,並且必須包含一個非數字字元。
這些錯誤出現在這裡的原因是,我們在頁面上有一個驗證摘要,它會獲取從userManager.CreateAsync結果返回的錯誤。
現在我們對密碼規則有了更多的瞭解,讓我們嘗試建立一個足夠複雜的密碼並點選註冊。
您現在將看到主頁。這意味著操作成功了。現在讓我們轉到 SQL Server 物件資源管理器。
右鍵單擊dbo.AspNetUsers表並選擇檢視資料。
您現在可以看到使用者已成功建立,並且您還可以在 Users 表中看到一條新記錄。您還可以看到一個雜湊密碼值以及使用者名稱,這是我們使用mark.upston註冊的使用者名稱。
ASP.NET Core - 登入和登出
在本章中,我們將討論登入和登出功能。與登入相比,登出的實現相當簡單。讓我們繼續處理 Layout 檢視,因為我們希望構建一個具有某些連結的 UI。這將允許已登入的使用者登出並顯示使用者名稱。
<!DOCTYPE html>
<html>
<head>
<meta name = "viewport" content = "width = device-width" />
<title>@ViewBag.Title</title>
</head>
<body>
<div>
@DateTime.Now
</div>
<div>
@RenderBody()
</div>
</body>
</html>
對於匿名使用者,我們將顯示一個登入連結。
構建此 UI 所需的所有資訊都可從 Razor 檢視上下文獲取。
首先,讓我們在佈局檢視中新增名稱空間System.Security.Claims。
@using System.Security.Claims
<!DOCTYPE html>
<html>
<head>
<meta name = "viewport" content = "width = device-width" />
<title>@ViewBag.Title</title>
</head>
<body>
<div>
@if (User.IsSignedIn()) {
<div>@User.GetUserName()</div>
<form method = "post" asp-controller = "Account" aspcontroller = "Logout">
<input type = "submit" value = "Logout"/>
</form>
} else {
<a asp-controller = "Account" asp-action = "Login">Login</a>
<a asp-controller = "Account" asp-action = "Register">Register</a>
}
</div>
<div>
@DateTime.Now
</div>
<div>
@RenderBody()
</div>
</body>
</html>
在每個 Razor 檢視內部都有一個 User 屬性,我們希望構建一個 UI 來顯示已登入使用者的姓名。這裡還有一個擴充套件方法IsSignedIn。
我們可以呼叫此方法,如果它返回 true,則可以在此處放置一些標記來顯示使用者名稱,顯示登出按鈕。
現在,如果使用者已登入,我們可以使用輔助方法GetUserName顯示使用者的使用者名稱。
我們必須在表單內構建一個登出按鈕,該表單將釋出到 Web 伺服器。必須這樣做,因為如果您允許簡單的 GET 請求讓使用者退出,則會建立某些不良情況。
我們將強制此操作為 post,當用戶提交此表單時,我們需要做的就是在 AccountController 中實現的登出操作上點選,並登出使用者。
如果使用者未登入並且我們有一個匿名使用者,那麼我們需要顯示一個連結,該連結將轉到 AccountController,具體來說是 Login 操作,並且它可以顯示文字 Login。
我們還需要新增一個連結,以便新使用者註冊並直接轉到註冊頁面。
現在讓我們轉到 AccountController 並首先實現登出操作,如下面的程式所示。
[HttpPost]
public async Task<IActionResult> Logout() {
await _signManager.SignOutAsync();
return RedirectToAction("Index", "Home");
}
此操作僅響應 HttpPost。這是一個非同步操作。我們將不得不呼叫 Identity 框架上的另一個非同步方法。
我們可以返回 IActionResult 的任務,並且操作名為 Logout。
我們需要做的就是等待SignInManager 的 SignOutAsync方法。
使用者上下文現在已更改;我們現在有一個匿名使用者。檢視將重定向到主頁,我們將返回到員工列表。
現在讓我們繼續構建登入功能。這裡,我們需要一對操作,一個響應 HttpGet 請求並顯示我們可以用來登入的表單,另一個響應 HttpPost 請求。
首先,我們需要一個新的 ViewModel 來提取登入資料,因為登入與註冊非常不同。所以,讓我們新增一個新類並將其命名為LoginViewModel。
public class LoginViewModel {
public string Username { get; set; }
[DataType(DataType.Password)]
public string Password { get; set; }
[Display(Name ="Remember Me")]
public bool RememberMe { get; set; }
public string ReturnUrl { get; set; }
}
當用戶登入時,他們必須提供一些資訊,例如使用者名稱、密碼。
第三個資訊必須是登入 UI。它們帶有一個小的複選框,上面寫著——“您是否希望記住我”。這是在會話 cookie 和更持久的 cookie 之間進行選擇。
為了允許此功能,我們添加了一個布林屬性RememberMe,並使用了 Display 註解。現在,當我們構建標籤時,文字Remember Me 將帶空格顯示。
我們實際上希望作為此 ViewModel 一部分的最後一個資訊是擁有一個屬性來儲存 ReturnUrl。
現在讓我們新增將響應 Get 請求的 Login 操作,如下面的程式所示。
[HttpGet]
public IActionResult Login(string returnUrl = "") {
var model = new LoginViewModel { ReturnUrl = returnUrl };
return View(model);
}
我們將returnUrl作為查詢字串中的引數。
returnUrl可能並不總是存在。讓我們使用空字串作為預設值。
我們現在將透過在Views → Account資料夾中新增一個新的 MVC 檢視頁面來建立一個新檢視。
在中間窗格中,選擇 MVC 檢視頁面並將其命名為 Login.cshtml,然後單擊新增按鈕。讓我們在 Login.cshtml 檔案中新增以下程式碼。
@model LoginViewModel
@{
ViewBag.Title = "Login";
}
<h2>Login</h2>
<form method = "post" asp-controller = "Account" asp-action = "Login"
asp-route-returnurl = "@Model.ReturnUrl">
<div asp-validation-summary = "ValidationSummary.ModelOnly"></div>
<div>
<label asp-for = "Username"></label>
<input asp-for = "Username" />
<span asp-validation-for = "Username"></span>
</div>
<div>
<label asp-for = "Password"></label>
<input asp-for = "Password" />
<span asp-validation-for = "Password"></span>
</div>
<div>
<label asp-for = "RememberMe"></label>
<input asp-for = "RememberMe" />
<span asp-validation-for = "RememberMe"></span>
</div>
<input type = "submit" value = "Login" />
</form>
在此登入檢視中,我們將頁面的標題設定為 Login,然後我們有一個表單,該表單將釋出到AccountLogin操作。
我們需要使用標籤助手asp-route-returnurl,以確保 ReturnUrl 存在於表單釋出回的 URL 中。
我們需要將該 ReturnUrl 傳送回伺服器,以便如果使用者成功登入,我們可以將其傳送到他們試圖訪問的位置。
您在 asp-route- 後新增的任何內容,id 或 returnurl,無論您在那裡有什麼,都將以某種方式進入請求,要麼進入 URL 路徑,要麼作為查詢字串引數。
我們有ValidationSummary和使用者名稱、密碼和 RememberMe 的輸入,然後我們有一個提交按鈕。
AccountController,並實現 Post 操作。此操作響應 HttpPost。這將是一個非同步方法,因為我們需要呼叫 Identity 框架並返回 IActionResult 的任務。
[HttpPost]
public async Task<IActionResult> Login(LoginViewModel model) {
if (ModelState.IsValid) {
var result = await _signManager.PasswordSignInAsync(model.Username,
model.Password, model.RememberMe,false);
if (result.Succeeded) {
if (!string.IsNullOrEmpty(model.ReturnUrl) && Url.IsLocalUrl(model.ReturnUrl)) {
return Redirect(model.ReturnUrl);
} else {
return RedirectToAction("Index", "Home");
}
}
}
ModelState.AddModelError("","Invalid login attempt");
return View(model);
}
我們將其稱為 Login,現在我們期望接收 LoginViewModel。
我們需要檢查 ModelState 是否有效。如果有效,則透過呼叫 SignInManager 上的 API 來登入使用者。
PasswordSignInAsync方法將返回一個結果,如果結果成功,我們就知道使用者已成功登入。
我們還有一個 return URL。如果它是一個有效的本地 URL,我們將重定向到 return URL。
如果使用者剛剛登入並且沒有任何特定位置要訪問,我們將重定向使用者到 HomeController 的 Index 操作。
我們可能處於使用者提供無效密碼或無效使用者名稱的情況。我們還需要新增一個模型錯誤,提示是否存在無效的登入嘗試。這有助於使用者瞭解是否出現錯誤。
現在讓我們儲存所有內容並執行應用程式。
我們現在有了登入和註冊連結。讓我們點選登入連結。
讓我們使用我們在上一章中建立的使用者登入,方法是指定使用者名稱和密碼並選中記住我複選框。
當您點選登入按鈕時,瀏覽器會詢問您是否要儲存 localhost 的密碼。讓我們點選是按鈕。
現在,讓我們透過點選登出按鈕登出。
作為匿名使用者,讓我們嘗試編輯員工詳細資訊。
您現在可以看到我們已被重定向到登入檢視。
讓我們使用您的使用者名稱和密碼登入,並選中記住我複選框。
現在,點選登入按鈕。
您現在可以看到我們被定向到我們想要編輯的 URL。這是因為我們適當地處理了 return URL。