第 3 部分,ASP.NET Core 中的 Scaffold Razor 頁面
注意
這不是這篇文章的最新版本。 如需目前的版本,請參閱 本文的 .NET 9 版本。
警告
不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支持原則。 如需目前的版本,請參閱 本文的 .NET 9 版本。
本教學課程會檢查在先前教學課程中 Scaffolding 所建立的 Razor 頁面。
Create、Delete、Details 和 Edit 頁面
檢查 Pages/Movies/Index.cshtml.cs
頁面模型:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Data;
using RazorPagesMovie.Models;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace RazorPagesMovie.Pages.Movies
{
public class IndexModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
public IList<Movie> Movie { get;set; } = default!;
public async Task OnGetAsync()
{
Movie = await _context.Movie.ToListAsync();
}
}
}
Razor 頁面衍生自 PageModel。 依照慣例,PageModel
衍生類別會命名為 PageNameModel
。 例如,[索引] 頁面名為 IndexModel
。
建構函式會使用相依性插入 ,將 RazorPagesMovieContext
新增至頁面:
public class IndexModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
如需使用 Entity Framework 進行非同步程式設計的詳細資訊,請參閱非同步程式碼。
當針對頁面提出 GET
要求時,OnGetAsync
方法會將電影清單傳回 Razor 頁面。 在 Razor 頁面上,呼叫 OnGetAsync
或 OnGet
以初始化頁面的狀態。 在此情況下,OnGetAsync
會取得電影清單並加以顯示。
當 OnGet
傳回 void
或 OnGetAsync
傳回 Task
時,並未使用任何 return 陳述式。 例如,檢查 Privacy 頁面:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace RazorPagesMovie.Pages
{
public class PrivacyModel : PageModel
{
private readonly ILogger<PrivacyModel> _logger;
public PrivacyModel(ILogger<PrivacyModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
}
}
當傳回型別是 IActionResult 或 Task<IActionResult>
時,必須提供傳回陳述式。 例如,Pages/Movies/Create.cshtml.cs OnPostAsync
方法:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
檢查 Pages/Movies/Index.cshtml
Razor 頁面:
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-page="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Title)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Price)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Movie) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-page="./Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-page="./Details" asp-route-id="@item.Id">Details</a> |
<a asp-page="./Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Razor 可以從 HTML 轉換成 C# 或 Razor 特定標記。 當 @
符號後面接著 Razor 保留關鍵字時,它會轉換成 Razor 特定標記,否則就會轉換成 C#。
@page 指示詞
@page
Razor 指示詞可讓檔案成為 MVC 動作,這表示它可以處理要求。 @page
必須是頁面上的第一個 Razor 指示詞。 @page
和 @model
是轉換成 Razor 特定標記的範例。 如需詳細資訊,請參閱 Razor 語法。
@model 指示詞
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@model
指示詞會指定傳遞至 Razor 頁面的模型類型。 在上述範例中,@model
行可讓 PageModel
衍生的類別供 Razor 頁面使用。 此模型用於頁面上的 @Html.DisplayNameFor
和 @Html.DisplayFor
HTML 協助程式。
檢查下列 HTML 協助程式中使用的 Lambda 運算式:
@Html.DisplayNameFor(model => model.Movie[0].Title)
DisplayNameFor HTML 協助程式會檢查 Lambda 運算式中參考的 Title
屬性來判斷顯示名稱。 Lambda 運算式是進行檢查而不是評估。 這表示當 model
、model.Movie
或 model.Movie[0]
是 null
或空白時,不會有任何存取違規。 在評估 Lambda 運算式時 (例如,使用 @Html.DisplayFor(modelItem => item.Title)
),會評估模型的屬性值。
版面配置頁
選取功能表連結 RazorPagesMovie、Home 和 Privacy。 每個頁面會顯示相同的功能表配置。 功能表版面配置要在 Pages/Shared/_Layout.cshtml
檔案中實作。
開啟並檢查 Pages/Shared/_Layout.cshtml
檔案。
版面配置範本可讓 HTML 容器版面配置:
- 指定在一個位置。
- 套用於網站中的多個頁面。
找到 @RenderBody()
這行。 RenderBody
是一個預留位置,可供顯示所有頁面特定檢視 (「包裝」在版面配置頁面中)。 例如,選取 Privacy 連結,則 Pages/Privacy.cshtml
檢視就會呈現在 RenderBody
方法內。
ViewData 和 Layout
請考慮 Pages/Movies/Index.cshtml
檔案中的下列標記:
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@{
ViewData["Title"] = "Index";
}
上述強調顯示的標記是 Razor 轉換成 C# 的範例。 {
和 }
字元中含括 C# 程式碼的區塊。
PageModel
基底類別包含 ViewData
字典屬性,可用來新增資料並傳遞到檢視。 物件會使用機碼/值模式新增至 ViewData
字典。 在上述範例中,Title
屬性會新增至 ViewData
字典。
Title
屬性會用於 Pages/Shared/_Layout.cshtml
檔案中。 下列標記會顯示 _Layout.cshtml
檔案的前幾行。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - RazorPagesMovie</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/RazorPagesMovie.styles.css" asp-append-version="true" />
更新配置
變更
Pages/Shared/_Layout.cshtml
檔案中的<title>
項目,以顯示 Movie 而不是 RazorPagesMovie。<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>@ViewData["Title"] - Movie</title>
在
Pages/Shared/_Layout.cshtml
檔案中尋找下列錨點項目。<a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
以下列標記來取代上述元素:
<a class="navbar-brand" asp-page="/Movies/Index">RpMovie</a>
上述的錨點項目是標記協助程式。 在此情況下,它是錨點標記協助程式。
asp-page="/Movies/Index"
標記協助程式的屬性和值會建立/Movies/Index
Razor 頁面的連結。asp-area
屬性值為空白,因此不會在連結中使用該區域。 如需詳細資訊,請參閱區域。選取 RpMovie 連結來儲存變更並測試應用程式。 如有任何問題,請參閱 GitHub 中的 _Layout.cshtml 檔案。
測試 Home、RpMovie、建立、編輯,以及刪除連結。 每一頁都會設定標題,您可以在瀏覽器索引標籤中看到該標題。當您將某個頁面加為書籤時,會使用標題來表示書籤。
注意
您可能無法在 Price
欄位中輸入小數逗號。 若要對使用逗號 (",") 作為小數點的非英文地區設定和非英文日期欄位支援 jQuery 驗證,您必須採取將應用程式全球化的步驟。 請參閱此 GitHub 問題 4076 \(英文\),以取得加入十進位逗號的指示。
Layout
屬性是在 Pages/_ViewStart.cshtml
檔案中設定:
@{
Layout = "_Layout";
}
上述的標記會針對 Pages 資料夾下的所有 Razor 檔案.將配置檔設定為 Pages/Shared/_Layout.cshtml
。 如需詳細資訊,請參閱 Layout。
Create 頁面模型
檢查 Pages/Movies/Create.cshtml.cs
頁面模型:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using RazorPagesMovie.Data;
using RazorPagesMovie.Models;
namespace RazorPagesMovie.Pages.Movies
{
public class CreateModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public CreateModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
public IActionResult OnGet()
{
return Page();
}
[BindProperty]
public Movie Movie { get; set; } = default!;
// To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
}
OnGet
方法會初始化頁面所需的任何狀態。 建立頁面沒有任何要初始化的狀態,所以傳回 Page
。 稍後在此教學課程中,會顯示 OnGet
初始化狀態的範例。 Page
方法會建立 PageResult
物件,用以呈現 Create.cshtml
頁面。
Movie
屬性 (property) 使用 [BindProperty] 屬性 (attribute) 來加入模型繫結。 當 Create 表單發佈表單值時,ASP.NET Core 執行階段會將發佈的值繫結至 Movie
模型。
當頁面發佈表單資料時,即會執行 OnPostAsync
方法:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
如果沒有任何模型錯誤,將會重新顯示表單,以及任何發佈的表單資料。 大部分的模型錯誤可以在發佈表單之前,於用戶端上攔截到。 模型錯誤的範例為針對日期欄位發佈無法轉換為日期的值。 稍後的教學課程中將討論用戶端驗證和模型驗證。
如果沒有模型錯誤:
- 資料會儲存。
- 瀏覽器會重新導向至 [索引] 頁面。
建立 Razor 頁面
檢查 Pages/Movies/Create.cshtml
Razor 頁面檔案:
@page
@model RazorPagesMovie.Pages.Movies.CreateModel
@{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.ReleaseDate" class="control-label"></label>
<input asp-for="Movie.ReleaseDate" class="form-control" />
<span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.Genre" class="control-label"></label>
<input asp-for="Movie.Genre" class="form-control" />
<span asp-validation-for="Movie.Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.Price" class="control-label"></label>
<input asp-for="Movie.Price" class="form-control" />
<span asp-validation-for="Movie.Price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Visual Studio 會以用於標籤協助程式的特殊粗體字型顯示下列標籤:
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
<form method="post">
項目是表單標記協助程式。 表單標記協助程式會自動包含 antiforgery 語彙基元。
Scaffolding 引擎會在模型中建立每個欄位的 Razor 標記 (除了識別碼),如下所示:
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>
驗證標記協助程式 (<div asp-validation-summary
和 <span asp-validation-for
) 會顯示驗證錯誤。 驗證將於本文稍後詳細討論到。
標籤標記協助程式 (<label asp-for="Movie.Title" class="control-label"></label>
) 會產生 Title
屬性 (property) 的標籤標題和 [for]
屬性 (attribute)。
輸入標記協助程式 (<input asp-for="Movie.Title" class="form-control">
) 會使用DataAnnotations 屬性,並產生在用戶端上進行 jQuery 驗證所需的 HTML 屬性。
如需標籤協助程式 (例如 <form method="post">
) 的詳細資訊,請參閱 ASP.NET Core 中的標籤協助程式。
下一步
Create、Delete、Details 和 Edit 頁面
檢查 Pages/Movies/Index.cshtml.cs
頁面模型:
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Models;
namespace RazorPagesMovie.Pages.Movies;
public class IndexModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
public IList<Movie> Movie { get;set; } = default!;
public async Task OnGetAsync()
{
if (_context.Movie != null)
{
Movie = await _context.Movie.ToListAsync();
}
}
}
Razor 頁面衍生自 PageModel。 依照慣例,PageModel
衍生類別會命名為 PageNameModel
。 例如,[索引] 頁面名為 IndexModel
。
建構函式會使用相依性插入 ,將 RazorPagesMovieContext
新增至頁面:
public class IndexModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
如需使用 Entity Framework 進行非同步程式設計的詳細資訊,請參閱非同步程式碼。
當針對頁面提出 GET
要求時,OnGetAsync
方法會將電影清單傳回 Razor 頁面。 在 Razor 頁面上,呼叫 OnGetAsync
或 OnGet
以初始化頁面的狀態。 在此情況下,OnGetAsync
會取得電影清單並加以顯示。
當 OnGet
傳回 void
或 OnGetAsync
傳回 Task
時,並未使用任何 return 陳述式。 例如,檢查 Privacy 頁面:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace RazorPagesMovie.Pages
{
public class PrivacyModel : PageModel
{
private readonly ILogger<PrivacyModel> _logger;
public PrivacyModel(ILogger<PrivacyModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
}
}
當傳回型別是 IActionResult 或 Task<IActionResult>
時,必須提供傳回陳述式。 例如,Pages/Movies/Create.cshtml.cs OnPostAsync
方法:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
檢查 Pages/Movies/Index.cshtml
Razor 頁面:
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-page="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Title)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Price)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Movie) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-page="./Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-page="./Details" asp-route-id="@item.Id">Details</a> |
<a asp-page="./Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Razor 可以從 HTML 轉換成 C# 或 Razor 特定標記。 當 @
符號後面接著 Razor 保留關鍵字時,它會轉換成 Razor 特定標記,否則就會轉換成 C#。
@page 指示詞
@page
Razor 指示詞可讓檔案成為 MVC 動作,這表示它可以處理要求。 @page
必須是頁面上的第一個 Razor 指示詞。 @page
和 @model
是轉換成 Razor 特定標記的範例。 如需詳細資訊,請參閱 Razor 語法。
@model 指示詞
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@model
指示詞會指定傳遞至 Razor 頁面的模型類型。 在上述範例中,@model
行可讓 PageModel
衍生的類別供 Razor 頁面使用。 此模型用於頁面上的 @Html.DisplayNameFor
和 @Html.DisplayFor
HTML 協助程式。
檢查下列 HTML 協助程式中使用的 Lambda 運算式:
@Html.DisplayNameFor(model => model.Movie[0].Title)
DisplayNameFor HTML 協助程式會檢查 Lambda 運算式中參考的 Title
屬性來判斷顯示名稱。 Lambda 運算式是進行檢查而不是評估。 這表示當 model
、model.Movie
或 model.Movie[0]
是 null
或空白時,不會有任何存取違規。 在評估 Lambda 運算式時 (例如,使用 @Html.DisplayFor(modelItem => item.Title)
),會評估模型的屬性值。
版面配置頁
選取功能表連結 RazorPagesMovie、Home 和 Privacy。 每個頁面會顯示相同的功能表配置。 功能表版面配置要在 Pages/Shared/_Layout.cshtml
檔案中實作。
開啟並檢查 Pages/Shared/_Layout.cshtml
檔案。
版面配置範本可讓 HTML 容器版面配置:
- 指定在一個位置。
- 套用於網站中的多個頁面。
找到 @RenderBody()
這行。 RenderBody
是一個預留位置,可供顯示所有頁面特定檢視 (「包裝」在版面配置頁面中)。 例如,選取 Privacy 連結,則 Pages/Privacy.cshtml
檢視就會呈現在 RenderBody
方法內。
ViewData 和 Layout
請考慮 Pages/Movies/Index.cshtml
檔案中的下列標記:
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@{
ViewData["Title"] = "Index";
}
上述強調顯示的標記是 Razor 轉換成 C# 的範例。 {
和 }
字元中含括 C# 程式碼的區塊。
PageModel
基底類別包含 ViewData
字典屬性,可用來新增資料並傳遞到檢視。 物件會使用機碼/值模式新增至 ViewData
字典。 在上述範例中,Title
屬性會新增至 ViewData
字典。
Title
屬性會用於 Pages/Shared/_Layout.cshtml
檔案中。 下列標記會顯示 _Layout.cshtml
檔案的前幾行。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - RazorPagesMovie</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/RazorPagesMovie.styles.css" asp-append-version="true" />
更新配置
變更
Pages/Shared/_Layout.cshtml
檔案中的<title>
項目,以顯示 Movie 而不是 RazorPagesMovie。<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>@ViewData["Title"] - Movie</title>
在
Pages/Shared/_Layout.cshtml
檔案中尋找下列錨點項目。<a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
以下列標記來取代上述元素:
<a class="navbar-brand" asp-page="/Movies/Index">RpMovie</a>
上述的錨點項目是標記協助程式。 在此情況下,它是錨點標記協助程式。
asp-page="/Movies/Index"
標記協助程式的屬性和值會建立/Movies/Index
Razor 頁面的連結。asp-area
屬性值為空白,因此不會在連結中使用該區域。 如需詳細資訊,請參閱區域。選取 RpMovie 連結來儲存變更並測試應用程式。 如有任何問題,請參閱 GitHub 中的 _Layout.cshtml 檔案。
測試 Home、RpMovie、建立、編輯,以及刪除連結。 每一頁都會設定標題,您可以在瀏覽器索引標籤中看到該標題。當您將某個頁面加為書籤時,會使用標題來表示書籤。
注意
您可能無法在 Price
欄位中輸入小數逗號。 若要對使用逗號 (",") 作為小數點的非英文地區設定和非英文日期欄位支援 jQuery 驗證,您必須採取將應用程式全球化的步驟。 請參閱此 GitHub 問題 4076 \(英文\),以取得加入十進位逗號的指示。
Layout
屬性是在 Pages/_ViewStart.cshtml
檔案中設定:
@{
Layout = "_Layout";
}
上述的標記會針對 Pages 資料夾下的所有 Razor 檔案.將配置檔設定為 Pages/Shared/_Layout.cshtml
。 如需詳細資訊,請參閱 Layout。
Create 頁面模型
檢查 Pages/Movies/Create.cshtml.cs
頁面模型:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesMovie.Models;
namespace RazorPagesMovie.Pages.Movies
{
public class CreateModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public CreateModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
public IActionResult OnGet()
{
return Page();
}
[BindProperty]
public Movie Movie { get; set; } = default!;
// To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid || _context.Movie == null || Movie == null)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
}
OnGet
方法會初始化頁面所需的任何狀態。 建立頁面沒有任何要初始化的狀態,所以傳回 Page
。 稍後在此教學課程中,會顯示 OnGet
初始化狀態的範例。 Page
方法會建立 PageResult
物件,用以呈現 Create.cshtml
頁面。
Movie
屬性 (property) 使用 [BindProperty] 屬性 (attribute) 來加入模型繫結。 當 Create 表單發佈表單值時,ASP.NET Core 執行階段會將發佈的值繫結至 Movie
模型。
當頁面發佈表單資料時,即會執行 OnPostAsync
方法:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
如果沒有任何模型錯誤,將會重新顯示表單,以及任何發佈的表單資料。 大部分的模型錯誤可以在發佈表單之前,於用戶端上攔截到。 模型錯誤的範例為針對日期欄位發佈無法轉換為日期的值。 稍後的教學課程中將討論用戶端驗證和模型驗證。
如果沒有模型錯誤:
- 資料會儲存。
- 瀏覽器會重新導向至 [索引] 頁面。
建立 Razor 頁面
檢查 Pages/Movies/Create.cshtml
Razor 頁面檔案:
@page
@model RazorPagesMovie.Pages.Movies.CreateModel
@{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.ReleaseDate" class="control-label"></label>
<input asp-for="Movie.ReleaseDate" class="form-control" />
<span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.Genre" class="control-label"></label>
<input asp-for="Movie.Genre" class="form-control" />
<span asp-validation-for="Movie.Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.Price" class="control-label"></label>
<input asp-for="Movie.Price" class="form-control" />
<span asp-validation-for="Movie.Price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Visual Studio 會以用於標籤協助程式的特殊粗體字型顯示下列標籤:
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
<form method="post">
項目是表單標記協助程式。 表單標記協助程式會自動包含 antiforgery 語彙基元。
Scaffolding 引擎會在模型中建立每個欄位的 Razor 標記 (除了識別碼),如下所示:
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>
驗證標記協助程式 (<div asp-validation-summary
和 <span asp-validation-for
) 會顯示驗證錯誤。 驗證將於本文稍後詳細討論到。
標籤標記協助程式 (<label asp-for="Movie.Title" class="control-label"></label>
) 會產生 Title
屬性 (property) 的標籤標題和 [for]
屬性 (attribute)。
輸入標記協助程式 (<input asp-for="Movie.Title" class="form-control">
) 會使用DataAnnotations 屬性,並產生在用戶端上進行 jQuery 驗證所需的 HTML 屬性。
如需標籤協助程式 (例如 <form method="post">
) 的詳細資訊,請參閱 ASP.NET Core 中的標籤協助程式。
下一步
Create、Delete、Details 和 Edit 頁面
檢查 Pages/Movies/Index.cshtml.cs
頁面模型:
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Models;
namespace RazorPagesMovie.Pages.Movies;
public class IndexModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
public IList<Movie> Movie { get;set; } = default!;
public async Task OnGetAsync()
{
if (_context.Movie != null)
{
Movie = await _context.Movie.ToListAsync();
}
}
}
Razor 頁面衍生自 PageModel。 依照慣例,PageModel
衍生類別會命名為 PageNameModel
。 例如,[索引] 頁面名為 IndexModel
。
建構函式會使用相依性插入 ,將 RazorPagesMovieContext
新增至頁面:
public class IndexModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
如需使用 Entity Framework 進行非同步程式設計的詳細資訊,請參閱非同步程式碼。
當針對頁面提出 GET
要求時,OnGetAsync
方法會將電影清單傳回 Razor 頁面。 在 Razor 頁面上,呼叫 OnGetAsync
或 OnGet
以初始化頁面的狀態。 在此情況下,OnGetAsync
會取得電影清單並加以顯示。
當 OnGet
傳回 void
或 OnGetAsync
傳回 Task
時,並未使用任何 return 陳述式。 例如,檢查 Privacy 頁面:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace RazorPagesMovie.Pages
{
public class PrivacyModel : PageModel
{
private readonly ILogger<PrivacyModel> _logger;
public PrivacyModel(ILogger<PrivacyModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
}
}
當傳回型別是 IActionResult 或 Task<IActionResult>
時,必須提供傳回陳述式。 例如,Pages/Movies/Create.cshtml.cs OnPostAsync
方法:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
檢查 Pages/Movies/Index.cshtml
Razor 頁面:
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-page="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Title)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Price)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Movie) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-page="./Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-page="./Details" asp-route-id="@item.Id">Details</a> |
<a asp-page="./Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Razor 可以從 HTML 轉換成 C# 或 Razor 特定標記。 當 @
符號後面接著 Razor 保留關鍵字時,它會轉換成 Razor 特定標記,否則就會轉換成 C#。
@page 指示詞
@page
Razor 指示詞可讓檔案成為 MVC 動作,這表示它可以處理要求。 @page
必須是頁面上的第一個 Razor 指示詞。 @page
和 @model
是轉換成 Razor 特定標記的範例。 如需詳細資訊,請參閱 Razor 語法。
@model 指示詞
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@model
指示詞會指定傳遞至 Razor 頁面的模型類型。 在上述範例中,@model
行可讓 PageModel
衍生的類別供 Razor 頁面使用。 此模型用於頁面上的 @Html.DisplayNameFor
和 @Html.DisplayFor
HTML 協助程式。
檢查下列 HTML 協助程式中使用的 Lambda 運算式:
@Html.DisplayNameFor(model => model.Movie[0].Title)
DisplayNameFor HTML 協助程式會檢查 Lambda 運算式中參考的 Title
屬性來判斷顯示名稱。 Lambda 運算式是進行檢查而不是評估。 這表示當 model
、model.Movie
或 model.Movie[0]
是 null
或空白時,不會有任何存取違規。 在評估 Lambda 運算式時 (例如,使用 @Html.DisplayFor(modelItem => item.Title)
),會評估模型的屬性值。
版面配置頁
選取功能表連結 RazorPagesMovie、Home 和 Privacy。 每個頁面會顯示相同的功能表配置。 功能表版面配置要在 Pages/Shared/_Layout.cshtml
檔案中實作。
開啟並檢查 Pages/Shared/_Layout.cshtml
檔案。
版面配置範本可讓 HTML 容器版面配置:
- 指定在一個位置。
- 套用於網站中的多個頁面。
找到 @RenderBody()
這行。 RenderBody
是一個預留位置,可供顯示所有頁面特定檢視 (「包裝」在版面配置頁面中)。 例如,選取 Privacy 連結,則 Pages/Privacy.cshtml
檢視就會呈現在 RenderBody
方法內。
ViewData 和 Layout
請考慮 Pages/Movies/Index.cshtml
檔案中的下列標記:
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@{
ViewData["Title"] = "Index";
}
上述強調顯示的標記是 Razor 轉換成 C# 的範例。 {
和 }
字元中含括 C# 程式碼的區塊。
PageModel
基底類別包含 ViewData
字典屬性,可用來新增資料並傳遞到檢視。 物件會使用機碼/值模式新增至 ViewData
字典。 在上述範例中,Title
屬性會新增至 ViewData
字典。
Title
屬性會用於 Pages/Shared/_Layout.cshtml
檔案中。 下列標記會顯示 _Layout.cshtml
檔案的前幾行。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - RazorPagesMovie</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/RazorPagesMovie.styles.css" asp-append-version="true" />
行 @*Markup removed for brevity.*@
是 Razor 註解。 不同於 HTML 註解 <!-- -->
,Razor 註解不會傳送到用戶端。 如需詳細資訊,請參閱 MDN Web 文件:開始使用 HTML。
更新配置
變更
Pages/Shared/_Layout.cshtml
檔案中的<title>
項目,以顯示 Movie 而不是 RazorPagesMovie。<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>@ViewData["Title"] - Movie</title>
在
Pages/Shared/_Layout.cshtml
檔案中尋找下列錨點項目。<a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
以下列標記來取代上述元素:
<a class="navbar-brand" asp-page="/Movies/Index">RpMovie</a>
上述的錨點項目是標記協助程式。 在此情況下,它是錨點標記協助程式。
asp-page="/Movies/Index"
標記協助程式的屬性和值會建立/Movies/Index
Razor 頁面的連結。asp-area
屬性值為空白,因此不會在連結中使用該區域。 如需詳細資訊,請參閱區域。選取 RpMovie 連結來儲存變更並測試應用程式。 如有任何問題,請參閱 GitHub 中的 _Layout.cshtml 檔案。
測試 Home、RpMovie、建立、編輯,以及刪除連結。 每一頁都會設定標題,您可以在瀏覽器索引標籤中看到該標題。當您將某個頁面加為書籤時,會使用標題來表示書籤。
注意
您可能無法在 Price
欄位中輸入小數逗號。 若要對使用逗號 (",") 作為小數點的非英文地區設定和非英文日期欄位支援 jQuery 驗證,您必須採取將應用程式全球化的步驟。 請參閱此 GitHub 問題 4076 \(英文\),以取得加入十進位逗號的指示。
Layout
屬性是在 Pages/_ViewStart.cshtml
檔案中設定:
@{
Layout = "_Layout";
}
上述的標記會針對 Pages 資料夾下的所有 Razor 檔案.將配置檔設定為 Pages/Shared/_Layout.cshtml
。 如需詳細資訊,請參閱 Layout。
Create 頁面模型
檢查 Pages/Movies/Create.cshtml.cs
頁面模型:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesMovie.Models;
namespace RazorPagesMovie.Pages.Movies
{
public class CreateModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public CreateModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
public IActionResult OnGet()
{
return Page();
}
[BindProperty]
public Movie Movie { get; set; } = default!;
// To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid || _context.Movie == null || Movie == null)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
}
OnGet
方法會初始化頁面所需的任何狀態。 建立頁面沒有任何要初始化的狀態,所以傳回 Page
。 稍後在此教學課程中,會顯示 OnGet
初始化狀態的範例。 Page
方法會建立 PageResult
物件,用以呈現 Create.cshtml
頁面。
Movie
屬性 (property) 使用 [BindProperty] 屬性 (attribute) 來加入模型繫結。 當 Create 表單發佈表單值時,ASP.NET Core 執行階段會將發佈的值繫結至 Movie
模型。
當頁面發佈表單資料時,即會執行 OnPostAsync
方法:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
如果沒有任何模型錯誤,將會重新顯示表單,以及任何發佈的表單資料。 大部分的模型錯誤可以在發佈表單之前,於用戶端上攔截到。 模型錯誤的範例為針對日期欄位發佈無法轉換為日期的值。 稍後的教學課程中將討論用戶端驗證和模型驗證。
如果沒有模型錯誤:
- 資料會儲存。
- 瀏覽器會重新導向至 [索引] 頁面。
建立 Razor 頁面
檢查 Pages/Movies/Create.cshtml
Razor 頁面檔案:
@page
@model RazorPagesMovie.Pages.Movies.CreateModel
@{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.ReleaseDate" class="control-label"></label>
<input asp-for="Movie.ReleaseDate" class="form-control" />
<span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.Genre" class="control-label"></label>
<input asp-for="Movie.Genre" class="form-control" />
<span asp-validation-for="Movie.Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.Price" class="control-label"></label>
<input asp-for="Movie.Price" class="form-control" />
<span asp-validation-for="Movie.Price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Visual Studio 會以用於標籤協助程式的特殊粗體字型顯示下列標籤:
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
<form method="post">
項目是表單標記協助程式。 表單標記協助程式會自動包含 antiforgery 語彙基元。
Scaffolding 引擎會在模型中建立每個欄位的 Razor 標記 (除了識別碼),如下所示:
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>
驗證標記協助程式 (<div asp-validation-summary
和 <span asp-validation-for
) 會顯示驗證錯誤。 驗證將於本文稍後詳細討論到。
標籤標記協助程式 (<label asp-for="Movie.Title" class="control-label"></label>
) 會產生 Title
屬性 (property) 的標籤標題和 [for]
屬性 (attribute)。
輸入標記協助程式 (<input asp-for="Movie.Title" class="form-control">
) 會使用DataAnnotations 屬性,並產生在用戶端上進行 jQuery 驗證所需的 HTML 屬性。
如需標籤協助程式 (例如 <form method="post">
) 的詳細資訊,請參閱 ASP.NET Core 中的標籤協助程式。
下一步
Create、Delete、Details 和 Edit 頁面
檢查 Pages/Movies/Index.cshtml.cs
頁面模型:
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Models;
namespace RazorPagesMovie.Pages.Movies
{
public class IndexModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
public IList<Movie> Movie { get;set; } = default!;
public async Task OnGetAsync()
{
if (_context.Movie != null)
{
Movie = await _context.Movie.ToListAsync();
}
}
}
}
Razor 頁面衍生自 PageModel。 依照慣例,PageModel
衍生類別會命名為 PageNameModel
。 例如,[索引] 頁面名為 IndexModel
。
建構函式會使用相依性插入 ,將 RazorPagesMovieContext
新增至頁面:
public class IndexModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
如需使用 Entity Framework 進行非同步程式設計的詳細資訊,請參閱非同步程式碼。
當針對頁面提出要求時,OnGetAsync
方法會將電影清單傳回 Razor 頁面。 在 Razor 頁面上,呼叫 OnGetAsync
或 OnGet
以初始化頁面的狀態。 在此情況下,OnGetAsync
會取得電影清單並加以顯示。
當 OnGet
傳回 void
或 OnGetAsync
傳回 Task
時,並未使用任何 return 陳述式。 例如,檢查 Privacy 頁面:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace RazorPagesMovie.Pages
{
public class PrivacyModel : PageModel
{
private readonly ILogger<PrivacyModel> _logger;
public PrivacyModel(ILogger<PrivacyModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
}
}
當傳回型別是 IActionResult 或 Task<IActionResult>
時,必須提供傳回陳述式。 例如,Pages/Movies/Create.cshtml.cs
OnPostAsync
方法:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid || _context.Movie == null || Movie == null)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
檢查 Pages/Movies/Index.cshtml
Razor 頁面:
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-page="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Title)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Price)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Movie) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-page="./Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-page="./Details" asp-route-id="@item.ID">Details</a> |
<a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Razor 可以從 HTML 轉換成 C# 或 Razor 特定標記。 當 @
符號後面接著 Razor 保留關鍵字時,它會轉換成 Razor 特定標記,否則就會轉換成 C#。
@page 指示詞
@page
Razor 指示詞可讓檔案成為 MVC 動作,這表示它可以處理要求。 @page
必須是頁面上的第一個 Razor 指示詞。 @page
和 @model
是轉換成 Razor 特定標記的範例。 如需詳細資訊,請參閱 Razor 語法。
@model 指示詞
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@model
指示詞會指定傳遞至 Razor 頁面的模型類型。 在上述範例中,@model
行可讓 PageModel
衍生的類別供 Razor 頁面使用。 此模型用於頁面上的 @Html.DisplayNameFor
和 @Html.DisplayFor
HTML 協助程式。
檢查下列 HTML 協助程式中使用的 Lambda 運算式:
@Html.DisplayNameFor(model => model.Movie[0].Title)
DisplayNameFor HTML 協助程式會檢查 Lambda 運算式中參考的 Title
屬性來判斷顯示名稱。 Lambda 運算式是進行檢查而不是評估。 這表示當 model
、model.Movie
或 model.Movie[0]
是 null
或空白時,不會有任何存取違規。 在評估 Lambda 運算式時 (例如,使用 @Html.DisplayFor(modelItem => item.Title)
),會評估模型的屬性值。
版面配置頁
選取功能表連結 RazorPagesMovie、Home 和 Privacy。 每個頁面會顯示相同的功能表配置。 功能表版面配置要在 Pages/Shared/_Layout.cshtml
檔案中實作。
開啟並檢查 Pages/Shared/_Layout.cshtml
檔案。
版面配置範本可讓 HTML 容器版面配置:
- 指定在一個位置。
- 套用於網站中的多個頁面。
找到 @RenderBody()
這行。 RenderBody
是一個預留位置,可供顯示所有頁面特定檢視 (「包裝」在版面配置頁面中)。 例如,選取 Privacy 連結,則 Pages/Privacy.cshtml
檢視就會呈現在 RenderBody
方法內。
ViewData 和 Layout
請考慮 Pages/Movies/Index.cshtml
檔案中的下列標記:
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@{
ViewData["Title"] = "Index";
}
上述強調顯示的標記是 Razor 轉換成 C# 的範例。 {
和 }
字元中含括 C# 程式碼的區塊。
PageModel
基底類別包含 ViewData
字典屬性,可用來新增資料並傳遞到檢視。 物件會使用機碼/值模式新增至 ViewData
字典。 在上述範例中,Title
屬性會新增至 ViewData
字典。
Title
屬性會用於 Pages/Shared/_Layout.cshtml
檔案中。 下列標記會顯示 _Layout.cshtml
檔案的前幾行。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - RazorPagesMovie</title>
@*Markup removed for brevity.*@
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
行 @*Markup removed for brevity.*@
是 Razor 註解。 不同於 HTML 註解 <!-- -->
,Razor 註解不會傳送到用戶端。 如需詳細資訊,請參閱 MDN Web 文件:開始使用 HTML。
更新配置
變更
Pages/Shared/_Layout.cshtml
檔案中的<title>
項目,以顯示 Movie 而不是 RazorPagesMovie。<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>@ViewData["Title"] - Movie</title>
在
Pages/Shared/_Layout.cshtml
檔案中尋找下列錨點項目。<a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
以下列標記來取代上述元素:
<a class="navbar-brand" asp-page="/Movies/Index">RpMovie</a>
上述的錨點項目是標記協助程式。 在此情況下,它是錨點標記協助程式。
asp-page="/Movies/Index"
標記協助程式的屬性和值會建立/Movies/Index
Razor 頁面的連結。asp-area
屬性值為空白,因此不會在連結中使用該區域。 如需詳細資訊,請參閱區域。選取 RpMovie 連結來儲存變更並測試應用程式。 如有任何問題,請參閱 GitHub 中的 _Layout.cshtml 檔案。
測試 Home、RpMovie、建立、編輯,以及刪除連結。 每一頁都會設定標題,您可以在瀏覽器索引標籤中看到該標題。當您將某個頁面加為書籤時,會使用標題來表示書籤。
注意
您可能無法在 Price
欄位中輸入小數逗號。 若要對使用逗號 (",") 作為小數點的非英文地區設定和非英文日期欄位支援 jQuery 驗證,您必須採取將應用程式全球化的步驟。 請參閱此 GitHub 問題 4076 \(英文\),以取得加入十進位逗號的指示。
Layout
屬性是在 Pages/_ViewStart.cshtml
檔案中設定:
@{
Layout = "_Layout";
}
上述的標記會針對 Pages 資料夾下的所有 Razor 檔案.將配置檔設定為 Pages/Shared/_Layout.cshtml
。 如需詳細資訊,請參閱 Layout。
Create 頁面模型
檢查 Pages/Movies/Create.cshtml.cs
頁面模型:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesMovie.Models;
namespace RazorPagesMovie.Pages.Movies
{
public class CreateModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public CreateModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
public IActionResult OnGet()
{
return Page();
}
[BindProperty]
public Movie Movie { get; set; } = default!;
// To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid || _context.Movie == null || Movie == null)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
}
OnGet
方法會初始化頁面所需的任何狀態。 建立頁面沒有任何要初始化的狀態,所以傳回 Page
。 稍後在此教學課程中,會顯示 OnGet
初始化狀態的範例。 Page
方法會建立 PageResult
物件,用以呈現 Create.cshtml
頁面。
Movie
屬性 (property) 使用 [BindProperty] 屬性 (attribute) 來加入模型繫結。 當 Create 表單發佈表單值時,ASP.NET Core 執行階段會將發佈的值繫結至 Movie
模型。
當頁面發佈表單資料時,即會執行 OnPostAsync
方法:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid || _context.Movie == null || Movie == null)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
如果沒有任何模型錯誤,將會重新顯示表單,以及任何發佈的表單資料。 大部分的模型錯誤可以在發佈表單之前,於用戶端上攔截到。 模型錯誤的範例為針對日期欄位發佈無法轉換為日期的值。 稍後的教學課程中將討論用戶端驗證和模型驗證。
如果沒有模型錯誤:
- 資料會儲存。
- 瀏覽器會重新導向至 [索引] 頁面。
建立 Razor 頁面
檢查 Pages/Movies/Create.cshtml
Razor 頁面檔案:
@page
@model RazorPagesMovie.Pages.Movies.CreateModel
@{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.ReleaseDate" class="control-label"></label>
<input asp-for="Movie.ReleaseDate" class="form-control" />
<span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.Genre" class="control-label"></label>
<input asp-for="Movie.Genre" class="form-control" />
<span asp-validation-for="Movie.Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.Price" class="control-label"></label>
<input asp-for="Movie.Price" class="form-control" />
<span asp-validation-for="Movie.Price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Visual Studio 會以用於標籤協助程式的特殊粗體字型顯示下列標籤:
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
<form method="post">
項目是表單標記協助程式。 表單標記協助程式會自動包含 antiforgery 語彙基元。
Scaffolding 引擎會在模型中建立每個欄位的 Razor 標記 (除了識別碼),如下所示:
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>
驗證標記協助程式 (<div asp-validation-summary
和 <span asp-validation-for
) 會顯示驗證錯誤。 驗證將於本文稍後詳細討論到。
標籤標記協助程式 (<label asp-for="Movie.Title" class="control-label"></label>
) 會產生 Title
屬性 (property) 的標籤標題和 [for]
屬性 (attribute)。
輸入標記協助程式 (<input asp-for="Movie.Title" class="form-control">
) 會使用DataAnnotations 屬性,並產生在用戶端上進行 jQuery 驗證所需的 HTML 屬性。
如需標籤協助程式 (例如 <form method="post">
) 的詳細資訊,請參閱 ASP.NET Core 中的標籤協助程式。
下一步
Create、Delete、Details 和 Edit 頁面
檢查 Pages/Movies/Index.cshtml.cs
頁面模型:
// Unused usings removed.
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPagesMovie.Models;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace RazorPagesMovie.Pages.Movies
{
public class IndexModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
public IList<Movie> Movie { get;set; }
public async Task OnGetAsync()
{
Movie = await _context.Movie.ToListAsync();
}
}
}
Razor 頁面衍生自 PageModel
。 依照慣例,PageModel
衍生類別會命名為 <PageName>Model
。 建構函式會使用相依性插入 ,將 RazorPagesMovieContext
新增至頁面:
public class IndexModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public IndexModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
如需使用 Entity Framework 進行非同步程式設計的詳細資訊,請參閱非同步程式碼。
當針對頁面提出要求時,OnGetAsync
方法會將電影清單傳回 Razor 頁面。 在 Razor 頁面上,呼叫 OnGetAsync
或 OnGet
以初始化頁面的狀態。 在此情況下,OnGetAsync
會取得電影清單並加以顯示。
當 OnGet
傳回 void
或 OnGetAsync
傳回 Task
時,並未使用任何 return 陳述式。 例如,Privacy 頁面:
public class PrivacyModel : PageModel
{
private readonly ILogger<PrivacyModel> _logger;
public PrivacyModel(ILogger<PrivacyModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
}
當傳回型別是 IActionResult
或 Task<IActionResult>
時,必須提供傳回陳述式。 例如,Pages/Movies/Create.cshtml.cs
OnPostAsync
方法:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
檢查 Pages/Movies/Index.cshtml
Razor 頁面:
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<p>
<a asp-page="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Title)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].ReleaseDate)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Genre)
</th>
<th>
@Html.DisplayNameFor(model => model.Movie[0].Price)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Movie) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Title)
</td>
<td>
@Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
@Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<a asp-page="./Edit" asp-route-id="@item.ID">Edit</a> |
<a asp-page="./Details" asp-route-id="@item.ID">Details</a> |
<a asp-page="./Delete" asp-route-id="@item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Razor 可以從 HTML 轉換成 C# 或 Razor 特定標記。 當 @
符號後面接著 Razor 保留關鍵字時,它會轉換成 Razor 特定標記,否則就會轉換成 C#。
@page 指示詞
@page
Razor 指示詞可讓檔案成為 MVC 動作,這表示它可以處理要求。 @page
必須是頁面上的第一個 Razor 指示詞。 @page
和 @model
是轉換成 Razor 特定標記的範例。 如需詳細資訊,請參閱 Razor 語法。
@model 指示詞
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@model
指示詞會指定傳遞至 Razor 頁面的模型類型。 在上述範例中,@model
行可讓 PageModel
衍生的類別供 Razor 頁面使用。 此模型用於頁面上的 @Html.DisplayNameFor
和 @Html.DisplayFor
HTML 協助程式。
檢查下列 HTML 協助程式中使用的 Lambda 運算式:
@Html.DisplayNameFor(model => model.Movie[0].Title)
DisplayNameFor HTML 協助程式會檢查 Lambda 運算式中參考的 Title
屬性來判斷顯示名稱。 Lambda 運算式是進行檢查而不是評估。 這表示當 model
、model.Movie
或 model.Movie[0]
是 null
或空白時,不會有任何存取違規。 在評估 Lambda 運算式時 (例如,使用 @Html.DisplayFor(modelItem => item.Title)
),會評估模型的屬性值。
版面配置頁
選取功能表連結 RazorPagesMovie、Home 和 Privacy。 每個頁面會顯示相同的功能表配置。 功能表版面配置要在 Pages/Shared/_Layout.cshtml
檔案中實作。
開啟並檢查 Pages/Shared/_Layout.cshtml
檔案。
版面配置範本可讓 HTML 容器版面配置:
- 指定在一個位置。
- 套用於網站中的多個頁面。
找到 @RenderBody()
這行。 RenderBody
是一個預留位置,可供顯示所有頁面特定檢視 (「包裝」在版面配置頁面中)。 例如,選取 Privacy 連結,則 Pages/Privacy.cshtml
檢視就會呈現在 RenderBody
方法內。
ViewData 和 Layout
請考慮 Pages/Movies/Index.cshtml
檔案中的下列標記:
@page
@model RazorPagesMovie.Pages.Movies.IndexModel
@{
ViewData["Title"] = "Index";
}
上述強調顯示的標記是 Razor 轉換成 C# 的範例。 {
和 }
字元中含括 C# 程式碼的區塊。
PageModel
基底類別包含 ViewData
字典屬性,可用來新增資料並傳遞到檢視。 物件會使用機碼/值模式新增至 ViewData
字典。 在上述範例中,Title
屬性會新增至 ViewData
字典。
Title
屬性會用於 Pages/Shared/_Layout.cshtml
檔案中。 下列標記會顯示 _Layout.cshtml
檔案的前幾行。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - RazorPagesMovie</title>
@*Markup removed for brevity.*@
行 @*Markup removed for brevity.*@
是 Razor 註解。 不同於 HTML 註解 <!-- -->
,Razor 註解不會傳送到用戶端。 如需詳細資訊,請參閱 MDN Web 文件:開始使用 HTML。
更新配置
變更
Pages/Shared/_Layout.cshtml
檔案中的<title>
項目,以顯示 Movie 而不是 RazorPagesMovie。<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>@ViewData["Title"] - Movie</title>
在
Pages/Shared/_Layout.cshtml
檔案中尋找下列錨點項目。<a class="navbar-brand" asp-area="" asp-page="/Index">RazorPagesMovie</a>
以下列標記來取代上述元素:
<a class="navbar-brand" asp-page="/Movies/Index">RpMovie</a>
上述的錨點項目是標記協助程式。 在此情況下,它是錨點標記協助程式。
asp-page="/Movies/Index"
標記協助程式的屬性和值會建立/Movies/Index
Razor 頁面的連結。asp-area
屬性值為空白,因此不會在連結中使用該區域。 如需詳細資訊,請參閱區域。選取 RpMovie 連結來儲存變更並測試應用程式。 如有任何問題,請參閱 GitHub 中的 _Layout.cshtml 檔案。
測試 Home、RpMovie、建立、編輯,以及刪除連結。 每一頁都會設定標題,您可以在瀏覽器索引標籤中看到該標題。當您將某個頁面加為書籤時,會使用標題來表示書籤。
注意
您可能無法在 Price
欄位中輸入小數逗號。 若要對使用逗號 (",") 作為小數點的非英文地區設定和非英文日期欄位支援 jQuery 驗證,您必須採取將應用程式全球化的步驟。 請參閱此 GitHub 問題 4076 \(英文\),以取得加入十進位逗號的指示。
Layout
屬性是在 Pages/_ViewStart.cshtml
檔案中設定:
@{
Layout = "_Layout";
}
上述的標記會針對 Pages 資料夾下的所有 Razor 檔案.將配置檔設定為 Pages/Shared/_Layout.cshtml
。 如需詳細資訊,請參閱 Layout。
Create 頁面模型
檢查 Pages/Movies/Create.cshtml.cs
頁面模型:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesMovie.Models;
using System;
using System.Threading.Tasks;
namespace RazorPagesMovie.Pages.Movies
{
public class CreateModel : PageModel
{
private readonly RazorPagesMovie.Data.RazorPagesMovieContext _context;
public CreateModel(RazorPagesMovie.Data.RazorPagesMovieContext context)
{
_context = context;
}
public IActionResult OnGet()
{
return Page();
}
[BindProperty]
public Movie Movie { get; set; }
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
}
OnGet
方法會初始化頁面所需的任何狀態。 建立頁面沒有任何要初始化的狀態,所以傳回 Page
。 稍後在此教學課程中,會顯示 OnGet
初始化狀態的範例。 Page
方法會建立 PageResult
物件,用以呈現 Create.cshtml
頁面。
Movie
屬性 (property) 使用 [BindProperty] 屬性 (attribute) 來加入模型繫結。 當 Create 表單發佈表單值時,ASP.NET Core 執行階段會將發佈的值繫結至 Movie
模型。
當頁面發佈表單資料時,即會執行 OnPostAsync
方法:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Movie.Add(Movie);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
如果沒有任何模型錯誤,將會重新顯示表單,以及任何發佈的表單資料。 大部分的模型錯誤可以在發佈表單之前,於用戶端上攔截到。 模型錯誤的範例為針對日期欄位發佈無法轉換為日期的值。 稍後的教學課程中將討論用戶端驗證和模型驗證。
如果沒有模型錯誤:
- 資料會儲存。
- 瀏覽器會重新導向至 [索引] 頁面。
建立 Razor 頁面
檢查 Pages/Movies/Create.cshtml
Razor 頁面檔案:
@page
@model RazorPagesMovie.Pages.Movies.CreateModel
@{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Movie</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.ReleaseDate" class="control-label"></label>
<input asp-for="Movie.ReleaseDate" class="form-control" />
<span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.Genre" class="control-label"></label>
<input asp-for="Movie.Genre" class="form-control" />
<span asp-validation-for="Movie.Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Movie.Price" class="control-label"></label>
<input asp-for="Movie.Price" class="form-control" />
<span asp-validation-for="Movie.Price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Visual Studio 會以用於標籤協助程式的特殊粗體字型顯示下列標籤:
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
<form method="post">
項目是表單標記協助程式。 表單標記協助程式會自動包含 antiforgery 語彙基元。
Scaffolding 引擎會在模型中建立每個欄位的 Razor 標記 (除了識別碼),如下所示:
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Movie.Title" class="control-label"></label>
<input asp-for="Movie.Title" class="form-control" />
<span asp-validation-for="Movie.Title" class="text-danger"></span>
</div>
驗證標記協助程式 (<div asp-validation-summary
和 <span asp-validation-for
) 會顯示驗證錯誤。 驗證將於本文稍後詳細討論到。
標籤標記協助程式 (<label asp-for="Movie.Title" class="control-label"></label>
) 會產生 Title
屬性 (property) 的標籤標題和 [for]
屬性 (attribute)。
輸入標記協助程式 (<input asp-for="Movie.Title" class="form-control">
) 會使用DataAnnotations 屬性,並產生在用戶端上進行 jQuery 驗證所需的 HTML 屬性。
如需標籤協助程式 (例如 <form method="post">
) 的詳細資訊,請參閱 ASP.NET Core 中的標籤協助程式。