本章描述用于创建 HTML 表单的内置标签助手。这些标签助手确保表单提交到正确的操作或页面处理程序方法,并确保元素准确地表示特定的模型属性。
本章解释 ASP.NET Core 提供的创建 HTML 表单的功能。展示如何使用标签助手来选择表单目标和关联的 imput、textarea 和 select 元素。
1 准备工作
本章使用了前一章中的项目。
为准备这一章,替换 Views/Shared 文件夹的 _SimpleLayout.cshtml 文件中的内容。
<!DOCTYPE html>
<html>
<head>
<title>@ViewBag.Title</title>
<link href="/lib/twitter-bootstrap/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<div class="m-2">
@RenderBody()
</div>
</body>
</html>
本章使用控制器视图和 Razor Pages 来呈现相似的内容。为了更容易区分控制器和页面,将如下所示的路由添加到 Startup 类中。
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapControllerRoute("forms",
"controllers/{controller=Home}/{action=Index}/{id?}");
endpoints.MapDefaultControllerRoute();
endpoints.MapRazorPages();
});
新路由引入了一个静态路径段,使 URL 明显地以控制器为目标。使用浏览器请求http://localhost:5000/controllers/home/list
,这会显示一个产品列表。
2 理解表单处理模式
大多数 HTML 表单如下图所示处理数据。首先,浏览器发送一个 HTTP GET 请求,这会生成一个包含表单的 HTML 响应,使用户能够向应用程序提供数据。用户单击一个按钮使用 HTTP POST 请求提交表单数据,应用程序接收和处理用户的数据,处理完数据后发送一个响应将浏览器重定向到一个 URL,该 URL 提供了对用户操的确认。
这称为 Post/Redirect/Get 模式,这个重定向很重要,因为它意味着用户可以单击浏览器的 reload 按钮而不发送另一个 Post 请求,不然可能会导致无意中重复操作。
2.1 创建控制器来处理表单
处理表单的控制器是通过结合前面章节中描述的特性创建的。在 Controllers 文件夹中添加一个名为 FormController.cs 的类文件。
public class FormController : Controller
{
private DataContext context;
public FormController(DataContext dbContext)
{
context = dbContext;
}
public async Task<IActionResult> Index(long id = 1)
{
return View("Form", await context.Products.FindAsync(id));
}
[HttpPost]
public IActionResult SubmitForm()
{
var data = Request.Form.Keys.Where(k => !k.StartsWith(""));
foreach (string key in data)
{
TempData[key] = string.Join(",", Request.Form[key]);
}
return RedirectToAction(nameof(Results));
}
public IActionResult Results()
{
return View(TempData);
}
}
Index 操作方法选择一个名为 Form 的视图,它向用户呈现一个 HTML 表单。
当用户提交表单时,它由 SubmitForm 操作只能接收 HTTP POST 请求。这个操作方法处理通过 Request.Form 属性得到的 HTML 表单数据,以便可以使用临时数据特性存储它。每个表单数据值都以字符串数组的形式呈现,将其转换为以逗号分隔的字符串用于存储。浏览器重定向到 Results 操作方法,该方法选择默认视图并提供临时数据作为视图模型。
创建 Views/From 文件夹,添加 From.cshtml 视图文件。
@model Product
@{
Layout = "_SimpleLayout";
}
<h5 class="bg-primary text-white text-center p-2">HTML Form</h5>
<form action="/controllers/form/submitform" method="post">
<div class="form-group">
<label>Name</label>
<input class="form-control" name="Name" value="@Model.Name" />
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
这个视图包含一个简单的 HTML 表单,配置为使用 POST 请求将数据提交给 Submitfom 方法。表单包含一个imput 元素,该元素的值是使用 Razor 表达式设置的。接下来给 Views/From 文件夹添加一个名为 Results.cshtml 的 Razor 视图。
@model TempDataDictionary
@{
Layout = "_SimpleLayout";
}
<table class="table table-striped table-bordered table-sm">
<thead>
<tr class="bg-primary text-white text-center">
<th colspan="2">Form Data</th>
</tr>
</thead>
<tbody>
@foreach (string key in Model.Keys)
{
<tr>
<th>@key</th>
<td>@Model[key]</td>
</tr>
}
</tbody>
</table>
<a class="btn btn-primary" asp-action="Index">Return</a>
这个视图向用户显示表单数据。并使用浏览器请求 http:/localhost:5000/controllers/form
以査看 HTML表单。在文本字段中输入一个值,并单击 Submit 发送一个 POST 请求,该请求将由 SubmitForm 操作处理。表单数据存储为临时数据,浏览器重定向。
2.2 创建 Razor Pages 来处理表单
同样的模式可以使用 Razor Pages 实现。需要一个页面来呈现和处理表单数据,另一个页面显示结果。给 Pages 文件夹添加一个名为 FormHandler.cshtml 的 Razor Pages。
@page "/pages/form/{id:long?}"
@model FormHandlerModel
@using Microsoft.AspNetCore.Mvc.RazorPages
<div class="m-2">
<h5 class="bg-primary text-white text-center p-2">HTML Form</h5>
<form asp-page="FormHandler" method="post">
<div class="form-group">
<label>Name</label>
<input class="form-control" name="Name" value="@Model.Product.Name" />
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
@functions
{
[IgnoreAntiforgeryToken]
public class FormHandlerModel : PageModel
{
private DataContext context;
public FormHandlerModel(DataContext dbContext)
{
context = dbContext;
}
public Product Product { get; set; }
public async Task OnGetAsync(long id = 1)
{
Product = await context.Products.FindAsync(id);
}
public IActionResult OnPost()
{
foreach (string key in
Request.Form.Keys.Where(k => !k.StartsWith("_")))
{
TempData[key] = string.Join(", ", Request.Form[key]);
}
return RedirectToPage("FormResults");
}
}
}
OnGetAsync 处理程序方法从数据库中检索 Product,视图使用该产品设置 HTML 表单中输入元素的值。该表单配置为发送一个将由 OnPost 处理程序方法处理的 HTTP POST 请求。表单数摊存储为临时数据,并向浏览器发送一个到 FormResults 表单的重定向。
要创建浏览器将被重定到的页面,向 Pages 文件夹添加一个名为 FormResults.cshtml 的 Razor Pages。
@page "/pages/results"
<div class="m-2">
<table class="table table-striped table-bordered table-sm">
<thead>
<tr class="bg-primary text-white text-center">
<th colspan="2">Form Data</th>
</tr>
</thead>
<tbody>
@foreach (string key in TempData.Keys)
{
<tr>
<th>@key</th>
<td>@TempData[key]</td>
</tr>
}
</tbody>
</table>
<a class="btn btn-primary" asp-page="FormHandler">Return</a>
</div>
使用浏览器导航到 http:/localhost:5000/pages/form
,在文本字段中输入一个值,然后单击 Submit 按钮。表单数据由 OnPost 方法处理,浏览器重定向到 /pages/results,从而显示表单数据。
3 使用标签助手改进HTML表单
上面示例展示了处理 HTML 表单的基本机制,但是 ASP.NET Core 包含转换表单元素的标签助手。接下来描述标签助手并演示它们的用法。
3.1 使用表单元素
FormTagHelper 类是表单元素的内置标签助手类,用于管理 HTML 表单的配置,以便它们能够针对正确的操作或页面处理程序,而不需要硬编码 URL。
表单元素的内置标签助手属性:
名称 | 描述 |
---|---|
asp-controller | 此属性用于为操作属性 URL 指定路由系统的 controller 值。如果省略,那么使用呈现视图的控制器 |
asp-action | 此属性用于为 action属性 URL,的路由系统指定 action 值的操作方法。如果省略,就使用呈现视图的操作 |
asp-page | 此属性用于指定 Razor Pages 的名称 |
asp-page-handler | 此属性用于指定处理程序方法的名称,该处理程序方法用于处理请求。 |
asp-route-* | 名称以 asp-route 开头的属性用于为操作属性 URL 指定附加值,以便使用 asp-route-id 属性为路由系统提供 id 段的值 |
asp-route | 此属性指定将用于为操作生成 URL 属性的路由名称 |
asp-antiforgery | 这个属性控制是否将防伪信息添加到视图中 |
asp-fragmen | 此属性为生成的 URL 指定一个片段 |
设置表单目标
asp-action 属性用于指定将接收 HTTP 请求的操作的名称。修改在Views/Form 文件夹的 Form.cshtml 视图,以应用标签助手。
<form asp-action="submitform" method="post">
asp-page 属性用于选择 Razor Pages 作为表单的目标。 在 Pages 文件夹的 FormHandler.cshtm 文件中设置表单目标。
<form asp-page="FormHandler" method="post">
3.2 改变表单按钮
发送表单的按钮可以在表单元素之外定义。在这些情况下,按钮具有一个 form 属性,该属性的值对应于它所关联的表单元素的 id 属性,以及一个表单 action 属性,该属性指定表单的目标URL。
<form asp-action="submitform" method="post" id="htmlform">
<div class="form-group">
<label>Name</label>
<input class="form-control" name="Name" value="@Model.Name" />
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<button form="htmlform" asp-action="submitform" class="btn btn-primary mt-2">
Sumit(Outside Form)
</button>
添加到表单元素的 id 属性的值被按钮用作 form 属性的值,它告诉浏览器,在单击按钮时提交哪个表单。
也可用于 Razor Pages。
<form asp-page="FormHandler" method="post" id="htmlform">
<div class="form-group">
<label>Name</label>
<input class="form-control" name="Name" value="@Model.Product.Name" />
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<button form="htmlform" asp-page="FormHandler" class="btn btn-primary mt-2">
Sumit(Outside Form)
</button>
使用浏览器请求 http://localhost:5000/controllers/form
或 http://localhost:5000/pages/form
。
4 处理 input 元素
input 元素是 HTML 表单的主干,InputTagHelper 类用于转换 input 元素,以下属性反映它们要收集的视图模型属性的数据类型和格式。
input 元素的内置标签助手属性:
名称 | 描述 |
---|---|
asp-for | 这个属性用于指定 input 元素所表示的视图模型属性 |
asp-format | 这个属性用于指定 input 元素所表示的视图模型属性的值的格式 |
asp-for 属性设置为视图模型属性的名称,然后用于设置 input 元素的 name、id、type 和 value属性。在Views/Form 文件夹的 Form.cshtml 文件使用。
<label>Name</label>
@*<input class="form-control" name="Name" value="@Model.Name" />*@
<input class="form-control" asp-for="Name" />
这个标签助手使用一个模型表达式,这就是为什么在指定 asp-for 属性的值时不使用@字符。如果査看在使用浏览器请求 http:/localhost:5000/controllers/form
时应用程序返回的 HTML,可看到标签助手将 input 元素转换为如下形式:
<input class="form-control" type="text" id="Name" name="Name" value="Kayak">
id 和 name 属性的值是通过模型表达式获得的,从而确保在创建表单时不会引入拼写错误。
4.1 转换 input 元素的类型属性
input 元素的 type 属性告诉浏览器如何显示元素,以及它应该如何限制用户输入的值。input 元素默认配置是 text 类型,没有任何输入限制。下面在 Views/Form 文件夹的 Form.cshtml 中 type 属性使用 number 类型。
<div class="form-group">
<label>Id</label>
<input class="form-control" asp-for="ProductId" />
</div>
新元素使用 asp-for 属性来选择视图模型的 Productld 属性。使用浏览器请求http://localhost:5000/controllers/form
,查看标签助手转换的元素如下。
<input class="form-control" type="number" data-val="true"
data-val-required="The ProductId field is required."
id="ProductId" name="ProductId" value="1">
type 属性的值由 asp-for 属性指定的视图模型属性的类型决定。ProductId属性的类型是 C# long类型,它导致标签助手将 input 元素的 type 属性设置为 number,这将限制元素使其只接收数字字符。data-val 和 data-val 所需的属性添加到 input 元素中帮助验证。也可以通过显式地定义 input 元素上的 type 属性可覆盖默认。
4.2 格式化 input 元素值
当 action 方法为视图提供视图模型对象时,标签助手使用 asp-for 属性值来设置 input 元素的 value 属性。asp-format 属性用于指定数据值的格式。修改Form.cshtml。
<div class="form-group">
<label>Price</label>
<input class="form-control" asp-for="Price" asp-format="{0:#,###.00}"/>
</div>
通过模型类应用格式化
如果总是希望对模型属性使用相同的格式,就可以使用 DisplayFommat 属性来装饰 C#类属性在 using System.ComponentModel.DataAnnotations
名称空间中定义。Displayformat 属性需要两个数来格式化数据值:DisplayFormat 参数指定格式化字符串,将 ApplyformatnEdiMode设量为 true 意味着将值应用于编辑的元素(包括jmput 元素)时应该使用格式化。
在 Models 文件夹的 Product.cs 文件中应用格式化属性。
[DisplayFormat(DataFormatString = "{0:c2}", ApplyFormatInEditMode = true)]
public decimal Price { get; set; }
asp-format 属性优先于 DisplayFormat 属性,因此从视图中删除该属性。并使用浏览器请求 http://localhost:5000/controllers/Form/index/5
,会看到由属性定义的格式化字符串已经应用。
4.3 在 input 元素中显示相关数据的值
在使用 Entity Framework Core 时,经常需要显示从相关数据中获得的数据值,使用 asp-for 属性很容易做到这一点,因为模型表达式允许选择嵌套的导航属性。
在 Controllers 文件夹的 FormController.cs 文件中包含相关数据。
public async Task<IActionResult> Index(long id = 1)
{
var result = await context.Products.Include(p => p.Category)
.Include(p => p.Supplier).FirstAsync(p => p.ProductId == id);
return View("Form", result);
}
在Views/Form 文件夹的 Form.cshtml 文件中显示相关数据。
<div class="form-group">
<label>Category</label>
<input class="form-control" asp-for="Category.Name" />
</div>
<div class="form-group">
<label>Supplier</label>
<input class="form-control" asp-for="Supplier.Name" />
</div>
asp-for 属性的值是相对于视图模型对象表示的,可以包含嵌套属性,允许选择EntityFramework Core 分配给 Category 和 Supplier 导航属性的相关对象的 Name 属性。Razor Pages 使用了相同的技术,只是属性是相对于页面模型对象表示的。
<div class="form-group">
<label>Name</label>
<input class="form-control" asp-for="Product.Name" />
</div>
<div class="form-group">
<label>Price</label>
<input class="form-control" asp-for="Product.Price" />
</div>
<div class="form-group">
<label>Category</label>
<input class="form-control" asp-for="Product.Category.Name" />
</div>
<div class="form-group">
<label>Supplier</label>
<input class="form-control" asp-for="Product.Supplier.Name" />
</div>
......
public async Task OnGetAsync(long id = 1)
{
Product = await context.Products.Include(p => p.Category)
.Include(p => p.Supplier).FirstAsync(p => p.ProductId == id);
}
使对控制器的更改生效,并使用浏览器请求 http://localhost:5000/controllers/form/index/5
,和http://localhost:5000/pages/form
。
5 使用 label 元素
LabelTagHelper 类用于转换 label 元素,因此 for 属性的设置与用于转换 input 元素的方法一致。
标签助手设置 label 元素的内容,以便它包含所选视图模型属性的名称。标签助手设置 for 属性,该属性表示与特定 input 元素的关联,并在单击关联的标签时使 input 元素获得焦点。
在 Views/Fomm 文件夹的 Form.cshtml 中,将 asp-for 属性应用于表单视图,以将每个 label 元素与表示相同视图模型属性的 imput 元素相关联。
<div class="form-group">
<label asp-for="ProductId"></label>
<input class="form-control" asp-for="ProductId" />
</div>
<div class="form-group">
<label asp-for="Name"></label>
<input class="form-control" asp-for="Name" />
</div>
<div class="form-group">
<label asp-for="Price"></label>
<input class="form-control" asp-for="Price" />
</div>
<div class="form-group">
<label asp-for="Category.Name">Category</label>
<input class="form-control" asp-for="Category.Name" />
</div>
<div class="form-group">
<label asp-for="Supplier.Name">Supplier</label>
<input class="form-control" asp-for="Supplier.Name" />
</div>
6 使用 select 和 option 元素
select 和 option 元素用于向用户提供一组固定的选择。
SelectTagHelper 负责转换 select 元素,并支持以下描述的属性。
名称 | 描述 |
---|---|
asp-for | 此属性用于指定 select 元素所表示的视图或页面模型属性 |
asp-items | 此属性用于为 select 元素中包含的 option 元素指定值源 |
在 Views/Form 文件夹的 Form.cshtml 中用 select 元素替换了类别的 input 元素。
<div class="form-group">
<label asp-for="Category.Name">Category</label>
<select class="form-control" asp-for="CategoryId">
<option value="1">Watersports</option>
<option value="2">Soccer</option>
<option value="3">Chess</option>
</select>
</div>
所选的属性添加到 option 元素中,与视图模型的 CategoryId 值相对应。
<option value="2" selected="selected">Soccer</option>
选择 option 元素的任务是由 OptionTagHelper 类执行的,该类通过 TagHelperContext. Items 集合接收来自 SelectTagHelper 的指令,结果是 select 元素显示与 Product 对象的 CategoryId 值相关联的类别名称。
填充 select 元素
asp-items 属性用于为标签助手提供 SelectListltem 对象的列表序列,为这些对象生成 option元素。在 Controllers 文件夹的 FormController.cs 的 Index方法, 修改表单控制器的索引操作,以通过视图包向视图提供一系列 SelectListltem 对象。
ViewBag.Categories = new SelectList(context.Categories, "CategoryId", "Name");
可直接创建 SelectListltem 对象,但是 ASP.NET Core 提供了 SelectList 类来适应现有的数据序列。在本例中,从数据库中获得的 Category 对象序列传递给 SelectList 构造函数,还传递了应该用作 option 元素的值和标签的属性名称。在 Views/Form 文件夹的 Form.cshtml 中,更新了 form 视图以使用 SelectList。
<select class="form-control" asp-for="CategoryId" asp-items="@ViewBag.Categories">
</select>
7 处理文本区域
textarea 元素用于从用户那里请求大量文本,TextAreaTagHelper 负贵转换 textarea 元素。
TextAreaTagHelper 相对简单,为 asp-for 属性提供的值用于设置 textarea 元素上的 id 和 name属性。asp-for属性选择的属性值用作textarea元素的内容。在 Vews/Fomm 文件夹的 Form.cshtm 替换了Supplier.Name属性的输入元素,带有已应用 asp-for 属性的文本区域。
<textarea class="form-control" asp-for="Supplier.Name"></textarea>
标签:Core,ASP,Form,10,元素,视图,表单,asp,属性
From: https://www.cnblogs.com/nullcodeworld/p/18246657