【转】asp.net Core 系列【一】——创建Web应用
ASP.NET Core 中的 Razor 頁面介紹
Razor 頁面是 ASP.NET Core MVC 的一個新功能,它可以使基于頁面的編碼方式更簡單高效。
若要查找使用模型視圖控制器方法的教程,請參閱?ASP.NET Core MVC 入門。
?
ASP.NET Core 2.0 必備組件
安裝?.NET Core?2.0.0 或更高版本。
如果在使用 Visual Studio,請使用以下工作負載安裝?Visual Studio?2017 版本 15.3 或更高版本:
- ASP.NET 和 Web 開發
- .NET Core 跨平臺開發
?
創建 Razor 頁面項目
- Visual Studio ?
- Visual Studio for Mac ?
- Visual Studio Code ?
- .NET Core CLI
請參閱?Razor 頁面入門,獲取關于如何使用 Visual Studio 創建 Razor 頁面項目的詳細說明。
Razor 頁面
Startup.cs 中已啟用 Razor 頁面:
public class Startup {public void ConfigureServices(IServiceCollection services){// Includes support for Razor Pages and controllers. services.AddMvc();}public void Configure(IApplicationBuilder app){app.UseMvc();} }?
請考慮一個基本頁面:
@page<h1>Hello, world!</h1> <h2>The time on the server is @DateTime.Now</h2>?
上述代碼看上去類似于一個 Razor 視圖文件。 不同之處在于?@page?指令。?@page?使文件轉換為一個 MVC 操作 ,這意味著它將直接處理請求,而無需通過控制器處理。?@page?必須是頁面上的第一個 Razor 指令。?@page?將影響其他 Razor 構造的行為。
將在以下兩個文件中顯示使用?PageModel?類的類似頁面。 Pages/Index2.cshtml 文件:
@page @using RazorPages @model IndexModel2<h2>Separate page model</h2> <p>@Model.Message </p>?
Pages/Index2.cshtml.cs“代碼隱藏”文件:
using Microsoft.AspNetCore.Mvc.RazorPages; using System;namespace RazorPages {public class IndexModel2 : PageModel{public string Message { get; private set; } = "PageModel in C#";public void OnGet(){Message += $" Server time is { DateTime.Now }";}} }?
按照慣例,PageModel?類文件的名稱與追加 .cs 的 Razor 頁面文件名稱相同。 例如,前面的 Razor 頁面的名稱為 Pages/Index2.cshtml。 包含?PageModel?類的文件的名稱為 Pages/Index2.cshtml.cs。
頁面的 URL 路徑的關聯由頁面在文件系統中的位置決定。 下表顯示了 Razor 頁面路徑及匹配的 URL:
| /Pages/Index.cshtml | /?或?/Index |
| /Pages/Contact.cshtml | /Contact |
| /Pages/Store/Contact.cshtml | /Store/Contact |
| /Pages/Store/Index.cshtml | /Store?或?/Store/Index |
注意:
- 默認情況下,運行時在“頁面”文件夾中查找 Razor 頁面文件。
- URL 未包含頁面時,Index?為默認頁面。
編寫基本窗體
Razor 頁面功能旨在簡化 Web 瀏覽器常用的模式。?模型綁定、標記幫助程序和 HTML 幫助程序均只可用于 Razor 頁面類中定義的屬性。 請參考為?Contact?模型實現基本的“聯系我們”窗體的頁面:
在本文檔中的示例中,DbContext?在?Startup.cs?文件中進行初始化。
C#復制 using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using RazorPagesContacts.Data; namespace RazorPagesContacts { public class Startup { public IHostingEnvironment HostingEnvironment { get; } public void ConfigureServices(IServiceCollection services) { services.AddDbContext<AppDbContext>(options => options.UseInMemoryDatabase("name")); services.AddMvc(); } public void Configure(IApplicationBuilder app) { app.UseMvc(); } } }數據模型:
C#復制 using System.ComponentModel.DataAnnotations;namespace RazorPagesContacts.Data {public class Customer { public int Id { get; set; } [數據庫上下文:
C#復制 using Microsoft.EntityFrameworkCore;namespace RazorPagesContacts.Data {public class AppDbContext : DbContext { public AppDbContext(DbContextOptions options) : base(options) { } public DbSet<Customer> Customers { get; set; } } }Pages/Create.cshtml 視圖文件:
cshtml復制 @page @model RazorPagesContacts.Pages.CreateModel @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers<html> <body><p>Enter your name.</p><div asp-validation-summary="All"></div><form method="POST"> <div>Name: <input asp-for="Customer.Name" /></div> <input type="submit" /> </form> </body> </html>Pages/Create.cshtml.cs 代碼隱藏視圖文件:
C#復制 using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using RazorPagesContacts.Data;namespace RazorPagesContacts.Pages { public class CreateModel : PageModel { private readonly AppDbContext _db; public CreateModel(AppDbContext db) { _db = db; } [按照慣例,PageModel?類稱為?<PageName>Model并且它與頁面位于同一個命名空間中。
使用?PageModel?代碼隱藏文件支持單元測試,但是需要你編寫顯式構造函數和類。 未使用?PageModel?代碼隱藏文件的頁面支持運行時編譯,這在開發過程中可以作為一種優勢。
頁面包含?OnPostAsync?處理程序方法,它在?POST?請求上運行(當用戶發布窗體時)。 可以為任何 HTTP 謂詞添加處理程序方法。 最常見的處理程序是:
- OnGet,用于初始化頁面所需的狀態。?OnGet?示例。
- OnPost,用于處理窗體提交。
Async?命名后綴為可選,但是按照慣例通常會將它用于異步函數。 前面示例中的?OnPostAsync?代碼看上去與通常在控制器中編寫的內容相似。 前面的代碼通常用于 Razor 頁面。 多數 MVC 基元(例如模型綁定、驗證和操作結果)都是共享的。
之前的?OnPostAsync?方法:
C#復制 public async Task<IActionResult> OnPostAsync() { if (!ModelState.IsValid) { return Page(); } _db.Customers.Add(Customer); await _db.SaveChangesAsync(); return RedirectToPage("/Index"); }OnPostAsync?的基本流:
檢查驗證錯誤。
- 如果沒有錯誤,則保存數據并重定向。
- 如果有錯誤,則再次顯示頁面并附帶驗證消息。 客戶端驗證與傳統的 ASP.NET Core MVC 應用程序相同。 很多情況下,都會在客戶端上檢測到驗證錯誤,并且從不將它們提交到服務器。
成功輸入數據后,OnPostAsync?處理程序方法調用?RedirectToPage?幫助程序方法來返回?RedirectToPageResult?的實例。?RedirectToPage?是新的操作結果,類似于?RedirectToAction?或?RedirectToRoute,但是已針對頁面進行自定義。 在前面的示例中,它將重定向到根索引頁 (/Index)。?頁面 URL 生成部分中詳細介紹了?RedirectToPage。
提交的窗體存在(已傳遞到服務器的)驗證錯誤時,OnPostAsync?處理程序方法調用?Page?幫助程序方法。?Page?返回?PageResult?的實例。 返回?Page?的過程與控制器中的操作返回?View?的過程相似。?PageResult?是處理程序方法的默認?返回類型。 返回?void?的處理程序方法將顯示頁面。
Customer?屬性使用?[BindProperty]?特性來選擇加入模型綁定。
C#復制 public class CreateModel : PageModel {private readonly AppDbContext _db; public CreateModel(AppDbContext db) { _db = db; } [默認情況下,Razor 頁面只綁定帶有非 GET 謂詞的屬性。 綁定屬性可以減少需要編寫的代碼量。 綁定通過使用相同的屬性顯示窗體字段 (<input asp-for="Customer.Name" />) 來減少代碼,并接受輸入。
主頁 (Index.cshtml):
cshtml復制 @page @model RazorPagesContacts.Pages.IndexModel @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers<h1>Contacts</h1> <form method="post"> <table class="table"> <thead> <tr> <th>ID</th> <th>Name</th> </tr> </thead> <tbody> @foreach (var contact in Model.Customers) { <tr> <td>@contact.Id</td> <td>@contact.Name</td> <td> <a asp-page="./Edit" asp-route-id="@contact.Id">edit</a> <button type="submit" asp-page-handler="delete" asp-route-id="@contact.Id">delete</button> </td> </tr> } </tbody> </table> <a asp-page="./Create">Create</a> </form>Index.cshtml.cs 隱藏文件:
C#復制 using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using RazorPagesContacts.Data; using System.Collections.Generic; using Microsoft.EntityFrameworkCore; namespace RazorPagesContacts.Pages { public class IndexModel : PageModel { private readonly AppDbContext _db; public IndexModel(AppDbContext db) { _db = db; } public IList<Customer> Customers { get; private set; } public async Task OnGetAsync() { Customers = await _db.Customers.AsNoTracking().ToListAsync(); } public async Task<IActionResult> OnPostDeleteAsync(int id) { var contact = await _db.Customers.FindAsync(id); if (contact != null) { _db.Customers.Remove(contact); await _db.SaveChangesAsync(); } return RedirectToPage(); } } }Index.cshtml 文件包含以下標記來創建每個聯系人項的編輯鏈接:
cshtml復制 <a asp-page="./Edit" asp-route-id="@contact.Id">edit</a>定位點標記幫助程序?使用?asp-route-{value}?屬性生成“編輯”頁面的鏈接。 此鏈接包含路由數據及聯系人 ID。 例如?http://localhost:5000/Edit/1。
Pages/Edit.cshtml 文件:
cshtml復制 @page "{id:int}" @model RazorPagesContacts.Pages.EditModel @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers@{ViewData["Title"] = "Edit Customer"; }<h1>Edit Customer - @Model.Customer.Id</h1> <form method="post"> <div asp-validation-summary="All"></div> <input asp-for="Customer.Id" type="hidden" /> <div> <label asp-for="Customer.Name"></label> <div> <input asp-for="Customer.Name" /> <span asp-validation-for="Customer.Name" ></span> </div> </div> <div> <button type="submit">Save</button> </div> </form>第一行包含?@page "{id:int}"?指令。 路由約束?"{id:int}"?告訴頁面接受包含?int?路由數據的頁面請求。 如果頁面請求未包含可轉換為?int的路由數據,則運行時返回 HTTP 404(未找到)錯誤。
Pages/Edit.cshtml.cs 文件:
C#復制 using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.EntityFrameworkCore; using RazorPagesContacts.Data; namespace RazorPagesContacts.Pages { public class EditModel : PageModel { private readonly AppDbContext _db; public EditModel(AppDbContext db) { _db = db; } [Index.cshtml 文件還包含用于為每個客戶聯系人創建刪除按鈕的標記:
cshtml復制 <button type="submit" asp-page-handler="delete" asp-route-id="@contact.Id">delete</button>刪除按鈕采用 HTML 呈現,其?formaction?包括參數:
- asp-route-id?屬性指定的客戶聯系人 ID。
- asp-page-handler?屬性指定的?handler。
下面是呈現的刪除按鈕的示例,其中客戶聯系人 ID 為?1:
html復制 <button type="submit" formaction="/?id=1&handler=delete">delete</button>選中按鈕時,向服務器發送窗體?POST?請求。 按照慣例,根據方案?OnPost[handler]Async?基于?handler?參數的值來選擇處理程序方法的名稱。
因為本示例中?handler?是?delete,因此?OnPostDeleteAsync?處理程序方法用于處理?POST?請求。 如果?asp-page-handler?設置為不同值(如?remove),則選擇名稱為?OnPostRemoveAsync?的頁面處理程序方法。
C#復制 public async Task<IActionResult> OnPostDeleteAsync(int id) { var contact = await _db.Customers.FindAsync(id); if (contact != null) { _db.Customers.Remove(contact); await _db.SaveChangesAsync(); } return RedirectToPage(); }OnPostDeleteAsync?方法:
- 接受來自查詢字符串的?id。
- 使用?FindAsync?查詢客戶聯系人的數據庫。
- 如果找到客戶聯系人,則從客戶聯系人列表將其刪除。 數據庫將更新。
- 調用?RedirectToPage,重定向到根索引頁 (/Index)。
XSRF/CSRF 和 Razor 頁面
無需為防偽驗證編寫任何代碼。 Razor 頁面自動將防偽標記生成過程和驗證過程包含在內。
將布局、分區、模板和標記幫助程序用于 Razor 頁面
頁面可使用 Razor 視圖引擎的所有功能。 布局、分區、模板、標記幫助程序、_ViewStart.cshtml 和 _ViewImports.cshtml 的工作方式與它們在傳統的 Razor 視圖中的工作方式相同。
我們來使用其中的一些功能來整理此頁面。
向 Pages/_Layout.cshtml 添加布局頁面:
cshtml復制布局:
- 控制每個頁面的布局(頁面選擇退出布局時除外)。
- 導入 HTML 結構,例如 JavaScript 和樣式表。
請參閱布局頁面了解詳細信息。
在 Pages/_ViewStart.cshtml 中設置?Layout?屬性:
cshtml復制注意:布局位于“頁面”文件夾中。 頁面按層次結構從當前頁面的文件夾開始查找其他視圖(布局、模板、分區)。 可以從“頁面”文件夾下的任意 Razor 頁面使用“頁面”文件夾中的布局。
建議不要將布局文件放在“視圖/共享”文件夾中。 視圖/共享 是一種 MVC 視圖模式。 Razor 頁面旨在依賴文件夾層次結構,而非路徑約定。
Razor 頁面中的視圖搜索包含“頁面”文件夾。 用于 MVC 控制器和傳統 Razor 視圖的布局、模板和分區可直接工作。
添加 Pages/_ViewImports.cshtml 文件:
cshtml復制 @namespace RazorPagesContacts.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers本教程的后續部分中將介紹?@namespace。?@addTagHelper?指令將內置標記幫助程序引入“頁面”文件夾中的所有頁面。
頁面上顯式使用?@namespace?指令后:
cshtml復制 @page @namespace RazorPagesIntro.Pages.Customers@model NameSpaceModel<h2>Name space</h2> <p>@Model.Message </p>此指令將為頁面設置命名空間。?@model?指令無需包含命名空間。
_ViewImports.cshtml 中包含?@namespace?指令后,指定的命名空間將為在導入?@namespace?指令的頁面中生成的命名空間提供前綴。 生成的命名空間的剩余部分(后綴部分)是包含 _ViewImports.cshtml 的文件夾與包含頁面的文件夾之間以點分隔的相對路徑。
例如,代碼隱藏文件 Pages/Customers/Edit.cshtml.cs 顯式設置命名空間:
C#復制 namespace RazorPagesContacts.Pages {public class EditModel : PageModel { private readonly AppDbContext _db; public EditModel(AppDbContext db) { _db = db; } // Code removed for brevity.Pages/_ViewImports.cshtml 文件設置以下命名空間:
cshtml復制 @namespace RazorPagesContacts.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers為 Pages/Customers/Edit.cshtml Razor 頁面生成的命名空間與代碼隱藏文件相同. 已對?@namespace?指令進行設計,因此添加到項目的 C# 類和頁面生成的代碼可直接工作,而無需添加代碼隱藏文件的?@using?指令。
注意:@namespace?也可用于傳統的 Razor 視圖。
原始的 Pages/Create.cshtml 視圖文件:
cshtml復制 @page @model RazorPagesContacts.Pages.CreateModel @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers<html> <body><p>Enter your name.</p><div asp-validation-summary="All"></div> <form method="POST"> <div>Name: <input asp-for="Customer.Name" /></div> <input type="submit" /> </form> </body> </html>更新后的 Pages/Create.cshtml 視圖文件:
cshtml復制 @page @model CreateModel<html> <body> <p> Enter your name. </p> <div asp-validation-summary="All"></div> <form method="POST"> <div>Name: <input asp-for="Customer.Name" /></div> <input type="submit" /> </form> </body> </html>Razor 頁面初學者項目包含 Pages/_ValidationScriptsPartial.cshtml,它與客戶端驗證聯合。
頁面的 URL 生成
之前顯示的?Create?頁面使用?RedirectToPage:
C#復制 public async Task<IActionResult> OnPostAsync() { if (!ModelState.IsValid) { return Page(); } _db.Customers.Add(Customer); await _db.SaveChangesAsync(); return RedirectToPage("/Index"); }應用具有以下文件/文件夾結構:
-
/Pages
- Index.cshtml
-
/Customer
- Create.cshtml
- Edit.cshtml
- Index.cshtml
成功后,Pages/Customers/Create.cshtml 和 Pages/Customers/Edit.cshtml 頁面將重定向到 Pages/Index.cshtml。 字符串?/Index?是用于訪問上一頁的 URI 的組成部分。 可以使用字符串?/Index?生成 Pages/Index.cshtml 頁面的 URI。 例如:
- Url.Page("/Index", ...)
- <a asp-page="/Index">My Index Page</a>
- RedirectToPage("/Index")
頁面名稱是從根“/Pages”文件夾到頁面的路徑(包含前導?/,例如?/Index)。 相較于僅對 URL 硬編碼,前面的 URL 生成示例的功能更加強大。 URL 生成使用路由,并且可以根據目標路徑定義路由的方式生成參數并對參數編碼。
頁面的 URL 生成支持相對名稱。 下表顯示了 Pages/Customers/Create.cshtml 中不同的?RedirectToPage?參數選擇的索引頁:
| RedirectToPage("/Index") | Pages/Index |
| RedirectToPage("./Index"); | Pages/Customers/Index |
| RedirectToPage("../Index") | Pages/Index |
| RedirectToPage("Index") | Pages/Customers/Index |
RedirectToPage("Index")、RedirectToPage("./Index")?和?RedirectToPage("../Index")?是相對名稱。 結合?RedirectToPage?參數與當前頁的路徑來計算目標頁面的名稱。
構建結構復雜的站點時,相對名稱鏈接很有用。 如果使用相對名稱鏈接文件夾中的頁面,則可以重命名該文件夾。 所有鏈接仍然有效(因為這些鏈接未包含此文件夾名稱)。
TempData
ASP.NET 在控制器上公開了?TempData?屬性。 此屬性可存儲數據,直至數據被讀取。?Keep?和?Peek?方法可用于檢查數據,而不執行刪除。 多個請求需要數據時,TempData?有助于進行重定向。
[TempData]?是 ASP.NET Core 2.0 中的新屬性,在控制器和頁面上受支持。
下面的代碼使用?TempData?設置?Message?的值:
C#復制 public class CreateDotModel : PageModel {private readonly AppDbContext _db; public CreateDotModel(AppDbContext db) { _db = db; } [Pages/Customers/Index.cshtml 文件中的以下標記使用?TempData?顯示?Message?的值。
cshtml復制 <h3>Msg: @Model.Message</h3>Pages/Customers/Index.cshtml.cs 代碼隱藏文件將?[TempData]?屬性應用到?Message?屬性。
C#復制 [請參閱?TempData?了解詳細信息。
針對一個頁面的多個處理程序
以下頁面使用?asp-page-handler?標記幫助程序為兩個頁面處理程序生成標記:
cshtml復制 @page @model CreateFATHModel<html> <body><p> Enter your name. </p> <div asp-validation-summary="All"></div> <form method="POST"> <div>Name: <input asp-for="Customer.Name" /></div> <input type="submit" asp-page-handler="JoinList" value="Join" /> <input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" /> </form> </body> </html>前面示例中的窗體包含兩個提交按鈕,每個提交按鈕均使用?FormActionTagHelper?提交到不同的 URL。?asp-page-handler?是?asp-page?的配套屬性。?asp-page-handler?生成提交到頁面定義的各個處理程序方法的 URL。 未指定?asp-page,因為示例已鏈接到當前頁面。
代碼隱藏文件:
C#復制 using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using RazorPagesContacts.Data;namespace RazorPagesContacts.Pages.Customers { public class CreateFATHModel : PageModel { private readonly AppDbContext _db; public CreateFATHModel(AppDbContext db) { _db = db; } [前面的代碼使用已命名處理程序方法。 已命名處理程序方法通過采用名稱中?On<HTTP Verb>?之后及?Async?之前的文本(如果有)創建。 在前面的示例中,頁面方法是 OnPostJoinListAsync 和 OnPostJoinListUCAsync。 刪除 OnPost 和 Async 后,處理程序名稱為?JoinList?和?JoinListUC。
cshtml復制 <input type="submit" asp-page-handler="JoinList" value="Join" /> <input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" />使用前面的代碼時,提交到?OnPostJoinListAsync?的 URL 路徑為?http://localhost:5000/Customers/CreateFATH?handler=JoinList。 提交到?OnPostJoinListUCAsync?的 URL 路徑為?http://localhost:5000/Customers/CreateFATH?handler=JoinListUC。
自定義路由
如果你不喜歡 URL 中的查詢字符串??handler=JoinList,可以更改路由,將處理程序名稱放在 URL 的路徑部分。 可以通過在?@page?指令后面添加使用雙引號括起來的路由模板來自定義路由。
cshtml復制 @page "{handler?}" @model CreateRouteModel<html> <body> <p> Enter your name. </p> <div asp-validation-summary="All"></div> <form method="POST"> <div>Name: <input asp-for="Customer.Name" /></div> <input type="submit" asp-page-handler="JoinList" value="Join" /> <input type="submit" asp-page-handler="JoinListUC" value="JOIN UC" /> </form> </body> </html>前面的路由將處理程序放在了 URL 路徑中,而不是查詢字符串中。?handler?前面的???表示路由參數為可選。
可以使用?@page?將其他段和參數添加到頁面的路由中。 其中的任何內容均會被追加到頁面的默認路由中。 不支持使用絕對路徑或虛擬路徑更改頁面的路由(例如?"~/Some/Other/Path")。
配置和設置
若要配置高級選項,請在 MVC 生成器上使用?AddRazorPagesOptions?擴展方法:
C#復制 public void ConfigureServices(IServiceCollection services) { services.AddMvc() .AddRazorPagesOptions(options => { options.RootDirectory = "/MyPages"; options.Conventions.AuthorizeFolder("/MyPages/Admin"); }); }目前,可以使用?RazorPagesOptions?設置頁面的根目錄,或者為頁面添加應用程序模型約定。 我們希望將來可以通過這種方式實現更多擴展功能。
轉載于:https://www.cnblogs.com/dayang12525/p/7693208.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的【转】asp.net Core 系列【一】——创建Web应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: zufeoj 分数线划定
- 下一篇: 设计模式之——Builder建造模式