第四章:ASP.NET Core Razor Pages


文档摘要

第四章:ASP.NET Core Razor Pages 第四章:ASP.NET Core Razor Pages 欢迎来到 ASP.NET Core Razor Pages 的世界!在本章中,我们将深入探索 Razor Pages,这是构建基于页面的 ASP.NET Core Web 应用程序的一种更简单、更高效的方式。Razor Pages 提供了一种以页面为中心的方法来构建 Web UI,使得代码更易于组织和理解,尤其适合构建以数据为中心的应用程序。 4.1 Razor Pages 简介 在传统的 ASP.NET MVC (Model-View-Controller) 架构中,用户界面逻辑分散在控制器 (Controller) 和视图 (View) 之间。

# 第四章:ASP.NET Core Razor Pages ## 第四章:ASP.NET Core Razor Pages 欢迎来到 ASP.NET Core Razor Pages 的世界!在本章中,我们将深入探索 Razor Pages,这是构建基于页面的 ASP.NET Core Web 应用程序的一种更简单、更高效的方式。Razor Pages 提供了一种以页面为中心的方法来构建 Web UI,使得代码更易于组织和理解,尤其适合构建以数据为中心的应用程序。 ### 4.1 Razor Pages 简介 在传统的 ASP.NET MVC (Model-View-Controller) 架构中,用户界面逻辑分散在控制器 (Controller) 和视图 (View) 之间。虽然 MVC 模式在大型、复杂的应用程序中表现出色,但对于许多场景,特别是构建简单的 Web 应用程序或单个页面的应用程序时,这种分离可能会显得过于繁琐。 Razor Pages 应运而生,它简化了 ASP.NET Core 应用程序的开发。Razor Pages 将单个页面的逻辑和视图组织在一起,减少了文件数量和概念上的复杂性。每个 Razor Page 都包含: * **Razor 页面文件 (.cshtml):** 负责定义页面的用户界面,使用 Razor 语法嵌入 C# 代码。 * **页面模型类 (.cshtml.cs):** 可选的 C# 类,称为 PageModel,用于处理页面的业务逻辑、数据处理和与视图之间的数据交互。 这种结构将视图和模型紧密结合,使得页面更加自包含,提高了开发效率和代码可维护性。 **Razor Pages 的优势:** * **更简单易学:** 对于初学者来说,Razor Pages 的结构比 MVC 更容易理解和上手。 * **更高效的开发:** 减少了文件数量和概念上的复杂性,加速了开发过程。 * **更清晰的代码组织:** 将页面相关的逻辑和视图集中在一起,提高了代码的可读性和可维护性。 * **更适合页面为中心的应用程序:** 对于许多以页面为中心的 Web 应用程序,Razor Pages 是比 MVC 更自然和高效的选择。 **Razor Pages 适用场景:** * 小型到中型 Web 应用程序 * 以数据为中心的应用程序 * 快速原型开发 * 需要简化开发流程的场景 **Razor Pages 与 MVC 的关系:** Razor Pages 构建于 ASP.NET Core MVC 之上,共享许多相同的核心功能,例如路由、模型绑定、验证、授权等。 Razor Pages 可以被视为 MVC 的一个子集,专注于简化页面开发。 你甚至可以在同一个 ASP.NET Core 应用程序中同时使用 Razor Pages 和 MVC 控制器。 ### 4.2 Razor Pages 的基本结构 一个典型的 Razor Page 包括两个主要文件: 1. **`.cshtml` 文件 (Razor 页面文件):** 这是页面的视图部分,使用 Razor 语法 (HTML 与 C# 代码的结合) 来定义页面的结构和内容。 2. **`.cshtml.cs` 文件 (页面模型类):** 这是一个 C# 类,继承自 `PageModel` 类。它负责处理页面的业务逻辑、数据处理以及与视图之间的数据传递。 让我们通过一个简单的示例来理解 Razor Pages 的基本结构。 **示例: 简单的 "Hello, World!" Razor Page** **1. 创建 Razor Page 文件 (Pages/HelloWorld.cshtml):** ```cshtml @page @model RazorPagesDemo.Pages.HelloWorldModel @{ ViewData["Title"] = "Hello World Page"; }

Hello, @Model.Name!

Welcome to Razor Pages!

``` * **`@page` 指令:** 这是 Razor Page 的关键指令,它将 `.cshtml` 文件标记为 Razor Page,使其可以通过 URL 直接访问。 * **`@model RazorPagesDemo.Pages.HelloWorldModel` 指令:** 指定与此 Razor Page 关联的页面模型类。 * **`@{ ... }` 代码块:** 用于编写 C# 代码,例如设置 `ViewData` 或执行其他逻辑。 * **`@Model.Name`:** 访问页面模型类 `HelloWorldModel` 中的 `Name` 属性,并在视图中显示其值。 **2. 创建页面模型类 (Pages/HelloWorld.cshtml.cs):** ```csharp using Microsoft.AspNetCore.Mvc.RazorPages; namespace RazorPagesDemo.Pages { public class HelloWorldModel : PageModel { public string Name { get; set; } = "World"; // 默认名称 public void OnGet() { // 在页面加载时执行的逻辑 (GET 请求) // 可以从数据库或其他来源获取数据,并设置 Model 属性 } } } ``` * **`HelloWorldModel` 类:** 继承自 `PageModel` 类,成为 Razor Page 的页面模型。 * **`Name` 属性:** 一个简单的字符串属性,用于存储名称数据。 * **`OnGet()` 方法:** 一个**处理程序 (Handler)** 方法,用于处理 HTTP GET 请求。当用户通过浏览器访问 `/HelloWorld` 页面时,`OnGet()` 方法会被执行。 **访问页面:** 启动 ASP.NET Core 应用程序后,你可以通过浏览器访问 `/HelloWorld` URL 来查看这个 Razor Page。页面将显示 "Hello, World! Welcome to Razor Pages!"。 **mermaid graph TD 图示 Razor Page 结构:** ```mermaid graph TD subgraph Razor Page A[.cshtml File
(View)] --> B[.cshtml.cs File
(PageModel)] end style A fill:#f9f,stroke:#333,stroke-width:2px style B fill:#ccf,stroke:#333,stroke-width:2px ``` 这个图示简单地展示了 Razor Page 的两个核心组成部分:`.cshtml` 文件 (视图) 和 `.cshtml.cs` 文件 (页面模型),它们协同工作来呈现页面和处理逻辑。 ### 4.3 页面模型 (PageModel) 页面模型类是 Razor Pages 的核心,它负责处理页面的业务逻辑、数据管理以及与视图的数据交互。 页面模型类必须继承自 `Microsoft.AspNetCore.Mvc.RazorPages.PageModel` 类。 **页面模型的主要职责:** * **数据管理:** 定义页面需要显示和处理的数据属性 (Model 属性)。 * **处理程序方法 (Handlers):** 定义处理 HTTP 请求 (例如 GET, POST) 的方法,例如 `OnGet()`, `OnPost()`, `OnGetAsync()`, `OnPostAsync()` 等。 * **业务逻辑:** 在处理程序方法中编写业务逻辑代码,例如从数据库获取数据、验证用户输入、执行计算等。 * **视图模型 (ViewModel):** 页面模型类本质上充当了视图模型,它将视图所需的数据传递给 `.cshtml` 文件。 **处理程序方法 (Handlers):** 处理程序方法是页面模型中用于响应特定 HTTP 请求的方法。 Razor Pages 约定基于 HTTP 方法 (GET, POST, PUT, DELETE 等) 和处理程序名称来自动路由请求到相应的处理程序方法。 * **`OnGet()` 和 `OnGetAsync()`:** 处理 HTTP GET 请求。通常用于页面初始化、数据加载和显示。 * **`OnPost()` 和 `OnPostAsync()`:** 处理 HTTP POST 请求。通常用于处理表单提交、数据创建或更新。 * **`OnPut()` 和 `OnPutAsync()`, `OnDelete()` 和 `OnDeleteAsync()`:** 处理 HTTP PUT 和 DELETE 请求。 适用于 RESTful API 或更复杂的页面交互。 **处理程序方法命名约定:** 处理程序方法名称必须以 `On` 开头,后跟 HTTP 方法名称 (Get, Post, Put, Delete 等)。 可以选择性地在方法名称后添加后缀 `Async` 表示异步操作。 **示例: 带有 GET 和 POST 处理程序的 Razor Page** **1. Razor Page 文件 (Pages/FormDemo.cshtml):** ```cshtml @page @model RazorPagesDemo.Pages.FormDemoModel @{ ViewData["Title"] = "Form Demo Page"; }

Form Demo

Name:
Submit @if (!string.IsNullOrEmpty(Model.Message)) {
@Model.Message
} ``` * **``:** 表单提交方式为 POST。 * **`asp-for="Name"` Tag Helper:** 将输入框绑定到页面模型 `FormDemoModel` 的 `Name` 属性,并启用模型绑定和验证。 * **`asp-validation-for="Name"` Tag Helper:** 用于显示 `Name` 属性的验证错误消息。 * **`@if (!string.IsNullOrEmpty(Model.Message)) { ... }`:** 条件性地显示成功消息。 **2. 页面模型类 (Pages/FormDemo.cshtml.cs):** ```csharp using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using System.ComponentModel.DataAnnotations; namespace RazorPagesDemo.Pages { public class FormDemoModel : PageModel { [BindProperty] // 启用模型绑定 [Required(ErrorMessage = "Name is required.")] // 数据验证规则 public string Name { get; set; } public string Message { get; set; } public void OnGet() { // 初始化页面 (GET 请求) Message = ""; // 清空消息 } public IActionResult OnPost() // 处理 POST 请求 { if (!ModelState.IsValid) // 检查模型验证是否通过 { return Page(); // 如果验证失败,重新显示页面并显示错误消息 } Message = $"Hello, {Name}! Form submitted successfully."; // 设置成功消息 return Page(); // 重新显示页面,这次显示成功消息 } } } ``` * **`[BindProperty]` 属性:** 必须添加到要进行模型绑定的属性上,例如 `Name` 属性。这告诉 Razor Pages 框架将 HTTP 请求中的数据绑定到 `Name` 属性。 * **`[Required]` 属性:** 数据验证属性,指定 `Name` 属性是必需的。 * **`ModelState.IsValid`:** 检查模型验证是否通过。如果验证失败,`ModelState.IsValid` 将为 `false`,并且验证错误消息将显示在视图中。 * **`return Page();`:** 返回 `PageResult` 对象,用于重新呈现当前 Razor Page。 **mermaid graph TD 图示 Form 处理流程:** ```mermaid graph TD A[Browser] --> B[HTTP GET Request to /FormDemo] B --> C[FormDemo PageModel - OnGet()] C --> D[Render FormDemo.cshtml] D --> A A --> E[User Input Data in Form] E --> F[HTTP POST Request to /FormDemo] F --> G[FormDemo PageModel - OnPost()] G --> H{ModelState.IsValid?} H -- Yes --> I[Process Data
(e.g., update database, send email)] I --> J[Set Message Property] J --> K[Render FormDemo.cshtml with Message] K --> A H -- No --> L[Render FormDemo.cshtml with Validation Errors] L --> A style H fill:#f9f,stroke:#333,stroke-width:2px ``` 这个图示展示了表单处理的流程: 1. **GET 请求:** 浏览器发送 GET 请求获取页面,`OnGet()` 处理程序初始化页面并渲染表单。 2. **POST 请求 (表单提交):** 用户在表单中输入数据并提交,浏览器发送 POST 请求。`OnPost()` 处理程序接收数据,进行模型绑定和验证。 3. **验证:** 检查 `ModelState.IsValid`。 * **验证成功:** 处理数据 (示例中只是设置消息),然后重新渲染页面显示成功消息。 * **验证失败:** 重新渲染页面,显示验证错误消息。 ### 4.4 Razor 语法基础 Razor 语法是用于在 `.cshtml` 文件中嵌入 C# 代码的标记语法。它允许你在 HTML 中动态生成内容、执行逻辑和访问页面模型的数据。 **常用的 Razor 语法元素:** * **`@` 符号:** Razor 语法的核心符号,用于指示 C# 代码的开始。 * **隐式表达式 (`@expression`):** 用于在 HTML 中直接输出 C# 表达式的值。例如:`

Hello, @Model.Name!

` * **代码块 (`@{ ... }`):** 用于编写多行 C# 代码。例如: ```cshtml @{ var message = "Welcome to Razor Pages!"; ViewData["Message"] = message; }

@ViewData["Message"]

``` * **HTML 编码:** Razor 默认会对输出的字符串进行 HTML 编码,以防止 XSS 攻击。如果要输出原始 HTML,可以使用 `@Html.Raw(expression)`. * **控制结构 (例如 `@if`, `@else`, `@for`, `@foreach`, `@while`):** 用于在 Razor 视图中编写 C# 控制流逻辑。例如: ```cshtml @if (Model.Items.Count > 0) {
    @foreach (var item in Model.Items) {
  • @item.Name
  • }
} else {

No items found.

} ``` * **注释 (`@* ... *@`):** 用于在 Razor 文件中添加 Razor 注释,这些注释不会在最终 HTML 输出中显示。 **示例: Razor 语法应用** ```cshtml @page @model RazorPagesDemo.Pages.RazorSyntaxDemoModel @{ ViewData["Title"] = "Razor Syntax Demo"; var currentTime = DateTime.Now; }

Razor Syntax Demo

Current Time: @currentTime

@if (currentTime.Hour < 12) {

Good morning!

} else {

Good afternoon!

}
    @foreach (var item in Model.Items) {
  • @item
  • }
@* This is a Razor comment, it will not be rendered in HTML *@ ``` **页面模型类 (Pages/RazorSyntaxDemo.cshtml.cs):** ```csharp using Microsoft.AspNetCore.Mvc.RazorPages; using System.Collections.Generic; namespace RazorPagesDemo.Pages { public class RazorSyntaxDemoModel : PageModel { public List Items { get; set; } = new List { "Item 1", "Item 2", "Item 3" }; public void OnGet() { } } } ``` 这个示例展示了 Razor 语法的一些基本用法,包括: * 输出变量值 (`@currentTime`). * 使用 `@if` 条件语句. * 使用 `@foreach` 循环. * 使用 Razor 注释. ### 4.5 路由 (Routing) Razor Pages 的路由是基于文件路径的约定路由。 默认情况下,Razor Pages 框架会将 `Pages` 文件夹下的 `.cshtml` 文件映射到相应的 URL 路径。 **默认路由约定:** * `Pages/Index.cshtml` 映射到根 URL `/` 或 `/Index`. * `Pages/About.cshtml` 映射到 URL `/About`. * `Pages/Products/Details.cshtml` 映射到 URL `/Products/Details`. **`@page` 指令和路由:** `@page` 指令是 Razor Page 的关键,它将 `.cshtml` 文件标记为可路由的页面。 `@page` 指令还可以用于自定义路由。 **自定义路由:** 你可以在 `@page` 指令后指定路由模板来覆盖默认路由约定。 * **显式路由模板:** ```cshtml @page "/my-custom-path" ``` 这将把 Razor Page 映射到 URL `/my-custom-path`,而不是默认的文件路径路由。 * **路由参数:** ```cshtml @page "{id:int}" ``` 这将定义一个名为 `id` 的路由参数,并限制其类型为整数 (`int`)。 你可以在页面模型中使用属性绑定来接收路由参数的值。 **示例: 自定义路由和路由参数** **1. Razor Page 文件 (Pages/Products/Details.cshtml):** ```cshtml @page "{id:int}" @model RazorPagesDemo.Pages.Products.DetailsModel @{ ViewData["Title"] = "Product Details"; }

Product Details

Product ID: @Model.ProductId

Product Name: @Model.ProductName

``` * **`@page "{id:int}"`:** 定义路由模板,包含一个名为 `id` 的整数类型路由参数. **2. 页面模型类 (Pages/Products/Details.cshtml.cs):** ```csharp using Microsoft.AspNetCore.Mvc.RazorPages; namespace RazorPagesDemo.Pages.Products { public class DetailsModel : PageModel { public int ProductId { get; set; } public string ProductName { get; set; } public void OnGet(int id) // 接收路由参数 id { ProductId = id; // 假设从数据库中根据 ProductId 获取产品名称 ProductName = $"Product {id}"; // 示例数据 } } } ``` * **`OnGet(int id)`:** `OnGet` 处理程序方法接收名为 `id` 的参数,该参数与路由模板中的 `{id:int}` 路由参数名称匹配。 Razor Pages 框架会自动将 URL 中的路由参数值绑定到 `OnGet` 方法的参数。 **访问页面:** 你可以通过 URL `/Products/Details/123` (假设 ID 为 123) 来访问这个页面。 页面将显示 "Product ID: 123" 和 "Product Name: Product 123"。 **mermaid graph TD 图示 Razor Pages 路由:** ```mermaid graph TD A[Browser Request
(e.g., /Products/Details/123)] --> B[Razor Pages Routing Middleware] B --> C{Match Razor Page?} C -- Yes --> D[Find Matching .cshtml File
(e.g., Pages/Products/Details.cshtml)] D --> E[Create PageModel Instance
(DetailsModel)] E --> F[Bind Route Parameters to Handler Parameters
(id = 123)] F --> G[Execute Handler Method
(OnGet(123))] G --> H[Render .cshtml View] H --> I[HTTP Response to Browser] C -- No --> J[MVC Controller Routing (if any)] style C fill:#f9f,stroke:#333,stroke-width:2px ``` 这个图示展示了 Razor Pages 路由的基本流程: 1. **浏览器请求:** 浏览器发送请求到 ASP.NET Core 应用程序。 2. **Razor Pages 路由中间件:** 路由中间件检查请求 URL 是否匹配任何 Razor Pages 的路由约定或自定义路由模板。 3. **匹配 Razor Page:** * **匹配成功:** 找到匹配的 Razor Page 文件,创建 PageModel 实例,将路由参数绑定到处理程序方法参数,执行处理程序方法,渲染视图,并返回 HTTP 响应。 * **匹配失败:** 如果找不到匹配的 Razor Page,则路由过程可能继续到 MVC 控制器路由 (如果应用程序中还配置了 MVC 控制器路由)。 ### 4.6 布局 (Layouts) 和 部分视图 (Partial Views) 为了提高代码重用性和维护性,Razor Pages 提供了布局 (Layouts) 和部分视图 (Partial Views) 的功能。 **布局 (Layouts):** 布局页面提供了一个共享的 HTML 结构,用于多个 Razor Pages。 布局页面通常包含页面的通用元素,例如: * HTML 文档结构 (``, ``, ``, ``) * 导航栏 * 页脚 * 样式表和 JavaScript 文件的引用 **默认布局:** 默认情况下,ASP.NET Core 项目通常会创建一个默认布局文件 `_Layout.cshtml`,位于 `Pages/Shared` 文件夹下。 Razor Pages 默认会使用这个布局文件。 **指定布局:** 你可以在 Razor Page 的 `.cshtml` 文件中使用 `Layout` 属性来指定要使用的布局文件。 ```cshtml @page @model ... @{ Layout = "_Layout"; // 使用默认布局 // 或 Layout = "/Pages/Shared/_MyCustomLayout.cshtml"; // 使用自定义布局 } ``` 如果 `Layout` 属性设置为 `null`,则 Razor Page 将不使用任何布局。 **布局页面的 `@RenderBody()` 方法:** 布局页面必须包含 `@RenderBody()` 方法。 `@RenderBody()` 方法是一个占位符,用于渲染 Razor Page 的内容。 **示例: 使用布局页面的 Razor Page** **1. 默认布局文件 (Pages/Shared/_Layout.cshtml):** ```cshtml @ViewData["Title"] - RazorPagesDemo
@RenderBody() @* 渲染 Razor Page 内容的占位符 *@
© 2024 - RazorPagesDemo - Privacy
@await RenderSectionAsync("Scripts", required: false) @* 可选的 Section 用于渲染特定页面的脚本 *@ ``` * **`@RenderBody()`:** 布局页面的核心,用于渲染 Razor Page 的内容。 * **`@await RenderSectionAsync("Scripts", required: false)`:** 一个可选的 Section,用于在布局页面的底部渲染特定 Razor Page 的脚本。 **2. Razor Page 文件 (Pages/Privacy.cshtml):** ```cshtml @page @model RazorPagesDemo.Pages.PrivacyModel @{ ViewData["Title"] = "Privacy Policy"; }

@ViewData["Title"]

Use this page to detail your site's privacy policy.

``` * **`Layout = "_Layout";` (默认):** 由于没有显式指定 `Layout` 属性,Razor Pages 默认使用 `_Layout.cshtml` 布局文件。 * **`

@ViewData["Title"]

` 和 `

...`:** 这些是 Razor Page 的内容,它们将被渲染到 `_Layout.cshtml` 布局文件的 `@RenderBody()` 占位符处。 **部分视图 (Partial Views):** 部分视图是可重用的 Razor 标记文件 (`.cshtml` 文件),用于将大型 Razor Page 视图分解为更小的、更易于管理的部分。 部分视图通常用于渲染: * 可重用的 UI 组件 (例如表单、列表、卡片) * 复杂页面的子组件 **创建部分视图:** 部分视图通常放在 `Pages/Shared/Components` 文件夹下 (约定,不是强制的)。 部分视图的文件名通常以下划线 `_` 开头,例如 `_LoginPartial.cshtml`. **渲染部分视图:** 可以使用 `Partial` 或 `PartialAsync` Tag Helper 在 Razor Page 或布局页面中渲染部分视图。 ```cshtml @await Html.PartialAsync("_LoginPartial", Model.LoginViewModel) ``` * **`name` 属性:** 指定部分视图的文件名 (不包括扩展名)。 * **`model` 属性 (可选):** 将模型数据传递给部分视图。 **示例: 使用部分视图的 Razor Page** **1. 部分视图文件 (Pages/Shared/Components/_ProductCard.cshtml):** ```cshtml @model RazorPagesDemo.Models.Product

@Model.Name
@Model.Name

Price: $@Model.Price

View Details
``` * **`@model RazorPagesDemo.Models.Product`:** 指定部分视图的模型类型为 `Product` 类。 * **渲染产品卡片 UI:** 使用 Bootstrap Card 组件渲染产品信息。 **2. Razor Page 文件 (Pages/ProductList.cshtml):** ```cshtml @page @model RazorPagesDemo.Pages.ProductListModel @{ ViewData["Title"] = "Product List"; }

Product List

@foreach (var product in Model.Products) {
@* 渲染部分视图,传递产品模型 *@
}
``` * **``:** 在循环中渲染 `_ProductCard.cshtml` 部分视图,并将当前 `product` 模型传递给部分视图。 **页面模型类 (Pages/ProductList.cshtml.cs):** ```csharp using Microsoft.AspNetCore.Mvc.RazorPages; using System.Collections.Generic; using RazorPagesDemo.Models; namespace RazorPagesDemo.Pages { public class ProductListModel : PageModel { public List Products { get; set; } = new List { new Product { Id = 1, Name = "Product 1", Price = 19.99m, ImageUrl = "https://via.placeholder.com/150" }, new Product { Id = 2, Name = "Product 2", Price = 29.99m, ImageUrl = "https://via.placeholder.com/150" }, new Product { Id = 3, Name = "Product 3", Price = 39.99m, ImageUrl = "https://via.placeholder.com/150" } }; public void OnGet() { } } } ``` * **`Products` 属性:** 包含产品列表数据。 这个示例展示了如何使用部分视图 `_ProductCard.cshtml` 在 `ProductList.cshtml` Razor Page 中渲染产品列表。 通过使用部分视图,可以将产品卡片的 UI 逻辑封装在单独的文件中,并在多个 Razor Pages 中重用。 ### 4.7 总结 本章深入探讨了 ASP.NET Core Razor Pages 的核心概念和实践。我们学习了 Razor Pages 的基本结构、页面模型、处理程序方法、Razor 语法、路由、布局和部分视图。 Razor Pages 提供了一种更简单、更高效的方式来构建基于页面的 ASP.NET Core Web 应用程序。 它特别适合构建以数据为中心的应用程序和需要快速开发迭代的场景。 通过将页面逻辑和视图紧密结合,Razor Pages 提高了代码的可读性、可维护性和开发效率。 在后续章节中,我们将继续深入探索 Razor Pages 的更多高级特性,例如模型绑定、验证、Tag Helpers、依赖注入等,以便你能够构建更强大、更复杂的 Razor Pages 应用程序。 希望本章的内容能够帮助你入门 Razor Pages 开发,并为你构建精彩的 Web 应用程序奠定坚实的基础!

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U