3.7 表单处理 (Form Handling)


文档摘要

3.7 表单处理 (Form Handling) 第三章:ASP.NET Core MVC 父章节领域 - 3.7 表单处理 (Form Handling) 3.7.1 表单基础与 HTML 结构 在Web开发中,表单本质上是 HTML 的 元素及其内部各种输入控件(如 、 、 等)的集合。 元素定义了表单的边界,并指定了表单数据提交的目标 URL ( 属性) 和提交方法 ( 属性)。 HTML 元素的核心属性: : 指定处理表单提交的服务器端 URL。当用户提交表单时,浏览器会将表单数据发送到此 URL。在 ASP.NET Core MVC 中,通常会指向一个 Controller 的 Action 方法。 : 定义表单数据提交的 HTTP 方法。

## 3.7 表单处理 (Form Handling) ## 第三章:ASP.NET Core MVC 父章节领域 - 3.7 表单处理 (Form Handling) ### 3.7.1 表单基础与 HTML 结构 在Web开发中,表单本质上是 HTML 的 `` 元素及其内部各种输入控件(如 ``、``、`<select>` 等)的集合。`<form>` 元素定义了表单的边界,并指定了表单数据提交的目标 URL ( `action` 属性) 和提交方法 ( `method` 属性)。 **HTML `<form>` 元素的核心属性:** * **`action`**: 指定处理表单提交的服务器端 URL。当用户提交表单时,浏览器会将表单数据发送到此 URL。在 ASP.NET Core MVC 中,通常会指向一个 Controller 的 Action 方法。 * **`method`**: 定义表单数据提交的 HTTP 方法。常用的方法有两种: * **`GET`**: 表单数据会附加在 URL 的查询字符串中,以 `?name1=value1&name2=value2` 的形式发送。GET 请求通常用于获取数据,不应用于修改服务器端数据。 * **`POST`**: 表单数据会包含在 HTTP 请求的主体 (Body) 中发送。POST 请求通常用于提交数据到服务器进行创建、更新等操作。 * **`enctype`**: 指定表单数据的编码方式。常用的值有: * **`application/x-www-form-urlencoded` (默认值)**: 将表单数据编码为 URL 格式。适用于大多数文本数据。 * **`multipart/form-data`**: 用于上传文件时,需要使用此编码方式。 * **`text/plain`**: 将表单数据作为纯文本发送,不常用。 **HTML 表单输入控件:** `<form>` 元素内部可以包含各种输入控件,用于收集用户输入的数据。常见的输入控件包括: * **`<input type="text">`**: 单行文本输入框。 * **`<input type="password">`**: 密码输入框,输入内容会被隐藏。 * **`<input type="radio">`**: 单选按钮,一组单选按钮中只能选择一个。 * **`<input type="checkbox">`**: 复选框,可以选择多个。 * **`<input type="submit">`**: 提交按钮,点击后提交表单。 * **`<input type="button">`**: 普通按钮,通常用于客户端脚本触发事件。 * **`<textarea>`**: 多行文本输入框。 * **`<select>`**: 下拉列表选择框。 **简单的 HTML 表单示例:** ```html <form action="/Home/SubmitForm" method="post"> <div> <label for="name">姓名:</label> <input type="text" id="name" name="name" /> </div> <div> <label for="email">邮箱:</label> <input type="email" id="email" name="email" /> </div> <div> <label for="message">留言:</label> <textarea id="message" name="message">
提交
``` 在这个示例中,我们创建了一个简单的表单,包含姓名、邮箱和留言三个字段。`action` 属性设置为 `/Home/SubmitForm`,表示表单数据将提交到 `HomeController` 的 `SubmitForm` Action 方法。`method` 属性设置为 `post`,表示使用 POST 方法提交数据。每个输入控件都使用 `name` 属性进行命名,这个 `name` 属性在服务器端接收表单数据时非常重要。 ### 3.7.2 表单提交方法:GET 与 POST 的选择 在表单处理中,选择合适的 HTTP 方法 (GET 或 POST) 至关重要,它直接影响着表单数据的传输方式、安全性以及语义化。 **GET 方法:** * **数据传输方式:** 表单数据附加在 URL 的查询字符串中。例如:`/Home/Search?keyword=ASP.NET&category=Programming` * **特点:** * **数据可见:** 数据直接暴露在 URL 中,不适合传输敏感数据。 * **URL 长度限制:** 浏览器和服务器对 URL 长度有限制,不适合传输大量数据。 * **语义:** GET 请求通常用于获取资源,应该是幂等的 (多次请求结果相同),不应引起服务器端状态的改变。 * **缓存:** GET 请求可以被浏览器和代理服务器缓存。 * **书签:** 用户可以保存包含查询字符串的 URL 作为书签。 **POST 方法:** * **数据传输方式:** 表单数据包含在 HTTP 请求的主体 (Body) 中。 * **特点:** * **数据隐藏:** 数据在请求体中,相对 GET 方法更安全,但仍需 HTTPS 加密传输敏感数据。 * **数据量较大:** POST 请求没有 URL 长度限制,可以传输大量数据,例如文件上传。 * **语义:** POST 请求通常用于创建或更新资源,可能引起服务器端状态的改变。 * **不缓存:** POST 请求默认不会被缓存。 * **不书签:** POST 请求不适合作为书签。 **选择 GET 还是 POST 的原则:** * **使用 GET 方法:** * 当表单操作是**查询数据**,并且不涉及服务器端数据的修改时。 * 当数据量较小,且不包含敏感信息时。 * 当希望用户能够通过 URL 分享或书签当前状态时。 * **使用 POST 方法:** * 当表单操作是**创建、更新或删除数据**,或涉及服务器端状态的改变时。 * 当需要传输**大量数据**,例如文件上传。 * 当需要传输**敏感信息**,例如用户密码 (即使使用 HTTPS,也应优先使用 POST)。 **Graph TD 图示 GET 与 POST 的区别:** ```mermaid graph TD A[浏览器] -->|GET 请求| B(服务器); B -->|URL 查询字符串获取数据| C[Controller Action]; C -->|响应| A; D[浏览器] -->|POST 请求| E(服务器); E -->|请求体获取数据| F[Controller Action]; F -->|响应| D; style A fill:#f9f,stroke:#333,stroke-width:2px style D fill:#f9f,stroke:#333,stroke-width:2px style B fill:#ccf,stroke:#333,stroke-width:2px style E fill:#ccf,stroke:#333,stroke-width:2px style C fill:#fff,stroke:#333,stroke-width:2px style F fill:#fff,stroke:#333,stroke-width:2px ``` ### 3.7.3 ASP.NET Core MVC 中的模型绑定 (Model Binding) ASP.NET Core MVC 的模型绑定 (Model Binding) 机制是处理表单数据的核心。它负责将 HTTP 请求中的数据 (例如表单数据、查询字符串、路由数据等) 自动映射到 Controller Action 方法的参数或模型对象上。这极大地简化了数据处理过程,开发者无需手动解析请求数据。 **模型绑定的工作流程:** 1. **请求到达服务器:** 浏览器发送 HTTP 请求到 ASP.NET Core MVC 应用程序。 2. **路由匹配:** 路由系统根据请求 URL 找到匹配的 Controller 和 Action 方法。 3. **模型绑定器 (Model Binder) 激活:** ASP.NET Core MVC 框架根据 Action 方法的参数类型,选择合适的模型绑定器。 4. **数据源解析:** 模型绑定器从请求的各个数据源 (例如表单数据、查询字符串、路由数据、请求头等) 中查找与参数名称或模型属性名称匹配的数据。 5. **类型转换和赋值:** 模型绑定器将找到的数据进行类型转换 (例如将字符串转换为整数、日期等),并将转换后的值赋值给 Action 方法的参数或模型对象的属性。 6. **Action 方法执行:** 模型绑定完成后,Action 方法接收到绑定好的参数或模型对象,开始执行业务逻辑。 **模型绑定的数据来源:** 模型绑定器可以从以下数据源中获取数据: * **表单数据 (Form Data):** 当表单使用 POST 方法提交时,表单数据会包含在请求体中。模型绑定器会解析表单数据,并根据输入控件的 `name` 属性进行绑定。 * **查询字符串 (Query String):** 当表单使用 GET 方法提交或手动在 URL 中添加查询字符串时,模型绑定器会解析查询字符串中的参数。 * **路由数据 (Route Data):** 路由数据是从 URL 路由模板中提取的参数值。例如,在路由模板 `/products/{id}` 中,`{id}` 就是路由数据。 * **请求头 (Request Headers):** 模型绑定器可以从 HTTP 请求头中获取数据。 * **请求体 (Request Body):** 除了表单数据,请求体还可以包含 JSON、XML 等格式的数据。模型绑定器可以根据请求头的 `Content-Type` 来解析不同格式的请求体数据。 **模型绑定到 Action 方法参数:** 最常见的模型绑定方式是将表单数据绑定到 Action 方法的参数。参数的名称需要与表单输入控件的 `name` 属性匹配。 **示例代码:** **Model (Models/UserInputModel.cs):** ```csharp namespace WebApp.Models { public class UserInputModel { public string Name { get; set; } public string Email { get; set; } public string Message { get; set; } } } ``` **Controller (Controllers/HomeController.cs):** ```csharp using Microsoft.AspNetCore.Mvc; using WebApp.Models; namespace WebApp.Controllers { public class HomeController : Controller { [HttpGet("/")] public IActionResult Index() { return View(); // 假设 Index.cshtml 包含表单 } [HttpPost("/Home/SubmitForm")] public IActionResult SubmitForm(UserInputModel model) // 模型绑定到 UserInputModel { if (ModelState.IsValid) { // 处理表单数据,例如保存到数据库、发送邮件等 // 这里仅简单返回一个成功视图 return View("Success", model); // 假设 Success.cshtml 显示提交成功信息 } else { // 模型验证失败,返回到表单视图并显示错误信息 return View("Index", model); } } } } ``` **View (Views/Home/Index.cshtml):** ```cshtml @model WebApp.Models.UserInputModel
姓名:
邮箱:
留言:
提交
``` 在这个示例中,`SubmitForm` Action 方法接收 `UserInputModel` 类型的参数 `model`。当表单提交时,ASP.NET Core MVC 的模型绑定器会自动将表单数据绑定到 `UserInputModel` 对象的 `Name`、`Email` 和 `Message` 属性上。在 Action 方法中,我们可以直接使用 `model` 对象来访问表单数据。 **Graph TD 图示模型绑定流程:** ```mermaid graph TD A[HTTP 请求] --> B(路由匹配); B --> C{Action 方法参数类型?}; C -- 是 --> D[选择模型绑定器]; C -- 否 --> E[直接绑定 (简单类型)]; D --> F[解析数据源 (Form, Query, Route...)]; F --> G[类型转换]; G --> H[赋值给模型/参数]; H --> I[Action 方法执行]; E --> H; style A fill:#f9f,stroke:#333,stroke-width:2px style B fill:#ccf,stroke:#333,stroke-width:2px style C fill:#ddd,stroke:#333,stroke-width:2px style D fill:#ccf,stroke:#333,stroke-width:2px style E fill:#ccf,stroke:#333,stroke-width:2px style F fill:#fff,stroke:#333,stroke-width:2px style G fill:#fff,stroke:#333,stroke-width:2px style H fill:#fff,stroke:#333,stroke-width:2px style I fill:#ccf,stroke:#333,stroke-width:2px ``` ### 3.7.4 控制器动作处理表单数据 Controller Action 方法是处理表单提交的核心逻辑所在。在 Action 方法中,我们可以接收模型绑定后的数据,进行数据验证、业务处理、数据持久化等操作,并最终返回视图或重定向。 **Action 方法的职责:** * **接收模型数据:** 通过模型绑定接收表单数据。 * **数据验证:** 验证模型数据的有效性,例如必填字段、数据格式、业务规则等。 * **业务逻辑处理:** 根据表单数据执行相应的业务逻辑,例如用户注册、订单处理、数据更新等。 * **数据持久化:** 将处理后的数据保存到数据库或其他持久化存储介质。 * **返回响应:** 根据处理结果返回合适的响应,例如视图、重定向、JSON 数据等。 **Action 方法的处理流程:** 1. **接收模型数据:** Action 方法通过参数接收模型绑定器传递的模型数据。 2. **模型验证:** 检查 `ModelState.IsValid` 属性,判断模型数据是否通过验证。 * 如果 `ModelState.IsValid` 为 `true`,表示模型数据验证通过,可以继续执行业务逻辑。 * 如果 `ModelState.IsValid` 为 `false`,表示模型数据验证失败,需要将错误信息返回给用户。 3. **业务逻辑处理:** 根据业务需求,执行相应的业务逻辑操作。 4. **数据持久化:** 如果需要持久化数据,将模型数据保存到数据库。 5. **返回响应:** * **成功场景:** 通常返回一个成功视图,或重定向到其他页面,或返回 JSON 数据表示操作成功。 * **失败场景 (验证失败):** 通常返回到表单视图,并将 `ModelState` 中的错误信息传递给视图进行显示,提示用户修改输入。 **示例代码 (继续使用 3.7.3 的示例):** 在 `HomeController` 的 `SubmitForm` Action 方法中,我们已经展示了基本的处理流程: ```csharp [HttpPost("/Home/SubmitForm")] public IActionResult SubmitForm(UserInputModel model) { if (ModelState.IsValid) { // 模型验证通过,执行业务逻辑 // 例如: // 1. 保存数据到数据库 // 2. 发送邮件通知 // 3. ... // 这里简单模拟保存成功 // ... return View("Success", model); // 返回成功视图 } else { // 模型验证失败,返回到表单视图并显示错误信息 return View("Index", model); // 返回表单视图,并传递 model 和 ModelState } } ``` 在 `Index.cshtml` 视图中,我们使用了 Tag Helpers (`asp-validation-summary` 和 `asp-validation-for`) 来显示验证错误信息。当 `ModelState.IsValid` 为 `false` 时,这些 Tag Helpers 会自动从 `ModelState` 中获取错误信息并显示在视图中。 ### 3.7.5 模型验证 (Model Validation) 模型验证是确保表单数据有效性和数据完整性的关键步骤。ASP.NET Core MVC 提供了强大的模型验证机制,可以方便地定义验证规则,并在服务器端和客户端进行验证。 **模型验证的类型:** * **服务器端验证 (Server-side Validation):** 在服务器端 Controller Action 方法中进行验证。这是**必须**的,因为客户端验证可以被绕过。 * **客户端验证 (Client-side Validation):** 在浏览器端使用 JavaScript 进行验证,提供实时的用户反馈,提升用户体验。客户端验证不能替代服务器端验证,只能作为辅助手段。 **数据注解 (Data Annotations) 验证:** ASP.NET Core MVC 使用数据注解 (Data Annotations) 来定义模型属性的验证规则。数据注解是一组特性 (Attributes),可以添加到模型类的属性上,用于指定验证规则。 **常用的数据注解验证特性:** * **`[Required]`**: 指定属性为必填项。 * **`[StringLength(maxLength, MinimumLength = minLength)]`**: 指定字符串属性的最大长度和最小长度。 * **`[MaxLength(maxLength)]`**: 指定字符串或数组属性的最大长度。 * **`[MinLength(minLength)]`**: 指定字符串或数组属性的最小长度。 * **`[Range(minimum, maximum)]`**: 指定数值属性的取值范围。 * **`[EmailAddress]`**: 验证属性是否为有效的电子邮件地址格式。 * **`[Phone]`**: 验证属性是否为有效的电话号码格式。 * **`[RegularExpression(pattern)]`**: 使用正则表达式验证属性值。 * **`[Compare(otherProperty)]`**: 比较当前属性值与另一个属性值是否相等 (例如用于密码确认)。 * **`[CustomValidation(typeof(ValidationClass), "ValidationMethod")]`**: 使用自定义的验证逻辑。 **示例代码 (在 3.7.3 的 `UserInputModel` 中添加验证规则):** ```csharp using System.ComponentModel.DataAnnotations; namespace WebApp.Models { public class UserInputModel { [Required(ErrorMessage = "姓名不能为空")] // 必填项,自定义错误消息 [StringLength(50, ErrorMessage = "姓名长度不能超过 50 个字符")] // 字符串长度限制 public string Name { get; set; } [Required(ErrorMessage = "邮箱不能为空")] [EmailAddress(ErrorMessage = "邮箱格式不正确")] // 邮箱格式验证 public string Email { get; set; } [StringLength(500, ErrorMessage = "留言长度不能超过 500 个字符")] public string Message { get; set; } } } ``` **客户端验证和服务器端验证的流程:** 1. **模型定义验证规则:** 在模型类中使用数据注解定义验证规则。 2. **视图生成客户端验证脚本:** ASP.NET Core MVC 的 Tag Helpers 和 HTML Helpers 会根据模型上的数据注解,自动生成客户端验证 JavaScript 代码。 3. **客户端验证执行:** 当用户在浏览器端输入数据时,客户端验证脚本会实时检查输入是否符合验证规则,并显示错误提示。 4. **表单提交和服务器端验证:** 当表单提交到服务器端时,模型绑定器会自动触发服务器端验证。 5. **检查 `ModelState.IsValid`:** 在 Controller Action 方法中,检查 `ModelState.IsValid` 属性。 * 如果 `ModelState.IsValid` 为 `true`,表示服务器端验证通过。 * 如果 `ModelState.IsValid` 为 `false`,表示服务器端验证失败,可以通过 `ModelState` 访问错误信息。 6. **返回验证结果:** 根据 `ModelState.IsValid` 的结果,返回相应的视图或响应,并在视图中显示验证错误信息。 **Graph TD 图示模型验证流程:** ```mermaid graph TD A[模型定义验证规则 (Data Annotations)] --> B[视图生成客户端验证脚本]; B --> C[浏览器端用户输入]; C --> D{客户端验证}; D -- 通过 --> E[表单提交]; D -- 失败 --> F[显示客户端错误提示]; E --> G[服务器端模型绑定]; G --> H{服务器端验证 (ModelState.IsValid)?}; H -- 是 --> I[Action 方法业务逻辑]; H -- 否 --> J[返回视图和 ModelState]; J --> K[视图显示服务器端错误提示]; I --> L[返回响应]; style A fill:#f9f,stroke:#333,stroke-width:2px style B fill:#ccf,stroke:#333,stroke-width:2px style C fill:#fff,stroke:#333,stroke-width:2px style D fill:#ccf,stroke:#333,stroke-width:2px style E fill:#f9f,stroke:#333,stroke-width:2px style F fill:#fdd,stroke:#333,stroke-width:2px style G fill:#ccf,stroke:#333,stroke-width:2px style H fill:#ddd,stroke:#333,stroke-width:2px style I fill:#ccf,stroke:#333,stroke-width:2px style J fill:#ccf,stroke:#333,stroke-width:2px style K fill:#fdd,stroke:#333,stroke-width:2px style L fill:#ccf,stroke:#333,stroke-width:2px ``` ### 3.7.6 表单助手 (Form Helpers) ASP.NET Core MVC 提供了两种主要的表单助手 (Form Helpers) 来简化 HTML 表单的创建和管理:Tag Helpers 和 HTML Helpers。在 ASP.NET Core MVC 中,推荐使用 Tag Helpers,它们更加简洁、语义化,并且与 HTML 更加自然地融合。 **Tag Helpers:** Tag Helpers 是 ASP.NET Core MVC 中用于在 Razor 视图中生成和增强 HTML 元素的组件。它们使用特性 (Attributes) 的形式添加到现有的 HTML 标签上,为 HTML 元素添加服务器端的功能。 **常用的表单 Tag Helpers:** * **`` Tag Helpers:** * `asp-controller`: 指定表单提交的目标 Controller。 * `asp-action`: 指定表单提交的目标 Action 方法。 * `asp-route-{routeName}`: 用于根据路由名称生成表单的 `action` 属性。 * `asp-route-{parameterName}`: 用于向路由添加参数。 * `method`: 指定表单提交的 HTTP 方法。 * **``, ``, `<select>` Tag Helpers:** * `asp-for`: 将输入控件绑定到模型属性,用于模型绑定和验证。 * `asp-validation-for`: 显示模型属性的验证错误信息。 * **`<span>` Tag Helpers:** * `asp-validation-summary`: 显示模型级别的验证错误摘要。 **示例代码 (使用 Tag Helpers 创建表单,如 3.7.3 示例所示):** ```cshtml @model WebApp.Models.UserInputModel <form asp-controller="Home" asp-action="SubmitForm" method="post"> <div> <label asp-for="Name">姓名:</label> <input asp-for="Name" /> <span asp-validation-for="Name" class="text-danger"></span> </div> <div> <label asp-for="Email">邮箱:</label> <input asp-for="Email" /> <span asp-validation-for="Email" class="text-danger"></span> </div> <div> <label asp-for="Message">留言:</label> <textarea asp-for="Message">
提交
``` **HTML Helpers (简要介绍,不推荐在新项目中使用):** HTML Helpers 是 ASP.NET MVC (之前的版本) 中用于生成 HTML 控件的方法。它们是 C# 代码,需要在 Razor 视图中使用 `@Html.` 前缀调用。虽然 HTML Helpers 在旧项目中仍然存在,但在 ASP.NET Core MVC 中,Tag Helpers 是更推荐的选择。 **常见的 HTML Helpers (仅供参考):** * `Html.BeginForm()`: 生成 `` 元素。 * `Html.TextBoxFor()`, `Html.PasswordFor()`, `Html.TextAreaFor()`, `Html.DropDownListFor()`: 生成各种输入控件,并绑定到模型属性。 * `Html.ValidationMessageFor()`, `Html.ValidationSummary()`: 显示验证错误信息。 **Tag Helpers 的优势:** * **更简洁、语义化:** Tag Helpers 使用特性添加到 HTML 标签上,代码更加简洁,更符合 HTML 的语义。 * **更好的可读性:** HTML 结构和服务器端逻辑更加清晰地分离,代码可读性更高。 * **更易于学习和使用:** Tag Helpers 更容易学习和使用,特别是对于前端开发者来说更加友好。 * **更好的性能:** Tag Helpers 在编译时执行,性能比 HTML Helpers 略有提升。 ### 3.7.7 安全性考虑 - CSRF 防护 (CSRF Protection) 跨站请求伪造 (Cross-Site Request Forgery, CSRF) 是一种常见的 Web 安全漏洞。攻击者通过伪造用户的请求,在用户不知情的情况下执行恶意操作,例如修改密码、转账等。 **CSRF 攻击原理:** 1. 用户登录到受信任的网站 (例如银行网站)。 2. 网站使用 Cookie 或 Session 维护用户的登录状态。 3. 用户访问恶意网站或点击恶意链接。 4. 恶意网站或链接中包含伪造的请求,例如向银行网站发起转账请求。 5. 用户的浏览器在发送伪造请求时,会自动携带银行网站的 Cookie 或 Session。 6. 银行网站验证 Cookie 或 Session,误认为请求来自已登录的用户,从而执行恶意操作。 **ASP.NET Core MVC 的 CSRF 防护机制:** ASP.NET Core MVC 内置了 CSRF 防护机制,通过同步器令牌 (Synchronizer Token) 来防止 CSRF 攻击。 **CSRF 防护的工作原理:** 1. **生成 CSRF 令牌:** 当服务器端生成包含表单的视图时,会自动生成一个唯一的 CSRF 令牌,并将其添加到视图中 (通常以隐藏字段的形式,例如 `__RequestVerificationToken`)。同时,服务器端也会将该令牌存储在 Cookie 中。 2. **提交表单时携带令牌:** 当浏览器提交表单时,会自动将 CSRF 令牌包含在请求头或表单数据中。 3. **服务器端验证令牌:** 服务器端接收到请求后,会验证请求中携带的 CSRF 令牌是否与服务器端存储的令牌一致。 * 如果令牌一致,表示请求来自合法的用户操作,允许执行操作。 * 如果令牌不一致或缺失,表示请求可能是 CSRF 攻击,拒绝执行操作。 **在 ASP.NET Core MVC 中启用 CSRF 防护:** ASP.NET Core MVC 的 CSRF 防护默认是启用的,无需额外配置。只需要在 Razor 视图的表单中使用 `@Html.AntiForgeryToken()` Tag Helper 或 HTML Helper 即可生成 CSRF 令牌。 **示例代码 (在表单中添加 CSRF 令牌):** ```cshtml @Html.AntiForgeryToken()
姓名:
提交
```

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