面向 Web 开发初学者的 ASP.NET MVC






4.85/5 (64投票s)
ASP.NET MVC 5 简介,面向对 Web 开发、MVC 框架和 Web 应用程序框架完全陌生的 .NET 开发人员。
引言
本教程面向对 Web 应用程序世界完全陌生的 .NET 开发人员,他们希望开始使用熟悉的 Microsoft .NET 技术。
必备组件
- HTML – 基本技能(网页结构、标签)
- CSS – 基本技能,包括对 Bootstrap 框架的基本熟悉
- C# – 您应该能熟练编写 C# 应用程序,并熟悉以下功能
- LINQ
- 匿名类型
- 表达式
- .NET Framework 库 – 您应该熟悉流行的框架功能,例如
- Entity Framework Code First(基础)
- 动态变量
开发环境
在本教程中,我将使用 Visual Studio 2013 Ultimate 版进行所有演示。您可以使用 Visual Studio 2012 及更高版本的任何版本。有免费的 Express 版本可用——请务必下载 Visual Studio Express for Web 版。
如果您不使用 Visual Studio 2013,则只能创建 MVC 4 项目,除非您安装 ASP.NET and Web Tools 2013.1 for Visual Studio 2012 包,而示例将基于 ASP.NET MVC 5。但这没关系,因为版本之间的差异主要在于身份验证功能而不是语法。
什么是 Web 应用程序框架?
简而言之,Web 应用程序框架允许您创建动态生成 HTML 页面(通常,尽管我们稍后会提到其他类型的响应)的应用程序,而不是在您的 Web 服务器上存储预先创建的 HTML 页面。
这允许创建功能强大、智能的网站,其功能远远超出显示静态数据。当今世界上大多数动态网站(即不仅显示静态 HTML 页面的网站)都是使用某种 Web 应用程序框架创建的。
什么是 MVC?
MVC 不是 Microsoft 技术。它代表模型-视图-控制器。它是一种常见的设计模式,存在于许多 Web 应用程序框架中,例如 Ruby on Rails、Django 和 Zend Framework。MVC 通常用于构建面向用户的应用程序(即具有图形用户界面 - GUI 的应用程序)。
如果您来自 WPF 世界,MVC 与 MVVM(模型-视图-视图模型)有些相似,但我们不会在本教程中深入探讨它们之间的差异。
Model(模型)
模型是一个简单的普通类,代表您希望对用户可见的数据结构。典型的模型类将只包含“哑”的公共属性。例如,对于 Person 模型,您将包含以下属性
- 名称
- 地址
- 电子邮件
- 电话
MVC 的其他组件将使用模型类来执行逻辑(例如,将 Person 添加到数据库)并将其显示给用户(呈现显示有关 John Smith 数据的 HTML 页面)。
重要的是要认识到此模型是为 **视图** 设计的,而不一定是为整个应用程序设计的。在您的应用程序内部、服务器端拥有一个 Person 模型类(例如,处理 Person 的信用卡详细信息),然后在 MVC 项目中拥有一个 Person 模型类是完全正常的。这称为视图模型。
View(视图)
视图是用户与我们的 Web 应用程序交互时将看到的结果。这通常是一个 HTML 页面,但它也可以是表示为 XML 或 JSON 的原始数据,或二进制数据(例如,一个 .zip 文件)。
当用户执行请求时,Web 应用程序框架会动态创建视图,并且视图不会存储在服务器上(超出内部实现的缓存机制)。
Controller(控制器)
控制器是一个类,它执行视图和模型之间的链接。例如,如果用户请求我们应用程序中所有 Person 的列表,则控制器类将包含访问数据库、查询适当的用户集,然后使用给定模型(这将是数据库返回的 Person 列表)创建视图的代码。
每个控制器都公开一组公共方法,称为动作。这是您应用程序的 API。每个视图都与单个控制器关联,但一个控制器可能具有返回不同视图的多个动作。
将业务逻辑放入控制器类是一种不好的做法。控制器只应负责检索数据和处理数据,而业务逻辑本身应委托给可能甚至不一定是 MVC Web 应用程序一部分的适当类和接口。
路由
路由是负责将 URL 解析或 **路由** 到特定控制器中的特定动作的过程。例如,如果我们的假想 Person 应用程序托管在 http://www.mypersonmanager.com,并且我们想要调用 **GetPersons** 动作(它是 **Person** 控制器类中的一个方法),我们的路由通常看起来像 http://www.mypersonmanager.com/person/getpersons。
路由还用于为动作传递参数。例如,如果我们有一个 **GetSpecificPerson** 动作接受 **Id** 参数,并且我们想在 Id 为 6 的情况下调用它,我们通常会使用以下语法向其传递参数:http://www.mypersonmanager.com/person/getspecificperson/6。
请注意,此处显示的语法是一个通用示例,虽然大多数 Web 应用程序框架通常遵循这些约定,但它们之间可能存在差异。
什么是 Microsoft ASP.NET MVC?
简而言之,今天的 ASP.NET 可以指代 ASP.NET MVC 框架所依赖的技术和库集。
ASP.NET Web Forms
ASP.NET Web Forms 是 .NET 开发人员在 ASP.NET MVC 引入之前常称的“ASP.NET”(因此造成了混淆)。它引入了类似于开发 Windows Forms 应用程序的概念——包括可拖动控件、页面状态和代码隐藏文件。
ASP.NET Web Forms 的主要优点是易于创建 Web 应用程序,最初可以使用工具包中的控件几乎不编写任何代码来创建。但是,Web Forms 不强制执行现代设计模式,有时可能会创建杂乱无章且非标准的 HTML 页面,并将用户与 Microsoft 控件和 JavaScript 库耦合。
ASP.NET Web Forms 仍在被许多 .NET 开发人员使用。
ASP.NET MVC
ASP.NET MVC 于 2008 年推出,基于 ASP.NET 堆栈,作为现有、著名的开源 MVC Web 应用程序框架(如 Ruby on Rails 和 Django)的竞争对手。与它们一样,ASP.NET MVC 也是开源的。
ASP.NET MVC 的主要优点是它更灵活,允许您使用外部库、实现自己的逻辑,并创建清晰、兼容的 HTML 页面和易于测试的应用程序逻辑。但是,它确实需要更陡峭的学习曲线,并且通常需要更多的代码。
您的第一个 ASP.NET 应用程序 - PersonManager
创建新的 ASP.NET MVC 应用程序
我们的第一个应用程序将非常简单:它将使用 Entity Framework 从数据库加载一组用户,并将其显示给用户。它还将允许向数据库添加新用户。
要创建新的 ASP.NET MVC 应用程序,您需要创建一个新项目,然后转到“Web”选项卡。如果您使用的是 Visual Studio Express for Web,则在创建新项目时会立即看到此项目选项。
在这种情况下,选择 MVC 选项,然后单击 **“更改身份验证”** 按钮并选择 **“无身份验证”**。在早期版本的 Visual Studio 中,此屏幕可能看起来有些不同。如果您的版本中存在任何其他选项,请务必取消选中它们。我们不会在本教程中探讨其他模板,但如果您愿意,可以尝试它们——它们包含预创建的演示应用程序,对学习很有用。
Visual Studio 将创建一个包含预创建模型、视图和控制器的默认应用程序。
约定优于配置
ASP.NET MVC 遵循流行的“约定优于配置”原则,该原则倾向于命名约定,而不是定义内容是什么的复杂配置文件。
要开始使用 ASP.NET MVC,请熟悉以下约定
- **控制器** 必须以 _名称_Controller 的语法命名,并放置在 Controllers 文件夹中。
- **视图** 没有特定的命名约定,但必须放置在 Views 文件夹中。
- **应用程序数据**,例如其他配置文件、二进制文件或本地数据库文件,应放置在 App_Data 文件夹中。
创建模型
模型是应用程序的骨干,因此我们将首先创建它。在这种情况下,我们只有一个模型——Person。让我们在 Models 文件夹中创建该类。
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public string Email { get; set; }
public long PhoneNumber { get; set; }
}
正如所承诺的,这是一个非常简单的类,没有什么特别之处,只有普通的属性。
创建控制器
目前,保留 Visual Studio 创建的现有控制器和视图。通过右键单击 Controllers 文件夹,然后选择 Add -> Controller 来创建新控制器。在显示的基架对话框中,选择 MVC 5 Controller。
同样,如果您使用的是旧版 Visual Studio(Visual Studio 2013 及更高版本支持 MVC 5),您可能会看到不同的对话框。无论如何,请务必创建一个空的 MVC 控制器。
将您的控制器命名为 **PersonController**。请记住控制器命名约定!
如您所见,这个全新的控制器是一个简单的类,它继承自 **Controller**,并且只包含一个方法——Index,该方法返回与此 Action 关联的 View。
public ActionResult Index()
{
ViewBag.MyHeader = "Hello World!";
return View();
}
创建视图
每个动作都可以与一个视图关联,而无需明确命名视图(如您所见,Index 方法调用 View 方法时不带任何参数)。这种关联是通过另一个“约定优于配置”实例创建的。如果您的动作名为 Index,ASP.NET MVC 将自动查找名为 Index 的视图(您可以将其命名为不同,并使用接受视图名称的 View 方法的重载)。继续右键单击 Index 动作,然后单击 **Add View** 创建一个新视图。
如您所见,Visual Studio 已经知道如何命名此控制器,因为您单击了 Index 动作内部。现在继续创建视图。
让我们看看结果。
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
ASP.NET MVC Razor 标记语法
如您所见,此页面包含 HTML 标签,但它也包含一个特殊语法,即“@”字符,它表示 **一个 C# 代码块**,而不是 HTML。这称为标记语法——ASP.NET(或任何 Web 应用程序框架)魔力的核心。这就是您能够创建动态内容而不仅仅是编写静态 HTML 页面的原因。
ASP.NET MVC 支持不同的 **视图引擎**,它们负责渲染视图的 HTML。默认视图引擎称为 Razor,专为 ASP.NET MVC 设计,对于我们的目的而言,没有理由使用其他引擎。不同的视图引擎可能具有不同的标记语法(例如,经典的 ASP.NET 引擎使用 <% 标签)。
Razor 具有相当智能的标记语法,不需要像其他一些引擎那样需要终止标签。例如,您可以执行以下操作
<ul>
@for (int i = 0; i < 10; i++)
{
<li>@i</li>
}
</ul>
正如您直观地可以判断的,这个简单的标记块的结果将是一个包含数字 0 到 9 的列表。
Razor 知道 C# 的 *for* 语句开始,这要归功于 * @ * 字符。然后它搜索表示代码块的括号。如果我们没有包含此字符,Razor 会将其视为普通文本。
另请注意 Razor 如何在 HTML 语法中间解释代码块——我们使用 * @i * 语句来指示我们希望将 * i * 的当前值放在列表项中,并且我们不需要换行或以任何方式关闭标签。这仅在我们只打印成员时有效。例如,您不能以相同的方式放置 * for * 语句。
标记序列中的代码是您熟悉的 C# 和 .NET,您可以使用任何您喜欢的命名空间,只需在页面顶部添加 @using 语句——同样,就像一个普通的类一样。您还可以在 Razor 标记段上放置断点,这些断点将在运行时触发。
如果您发现自己正在视图中编写大量代码,请仔细检查自己。视图只应包含用于文本表示从控制器渲染数据的代码。与数据交互、调用外部资源或(即使是假设上)可以在视图之外重用的代码,应始终放在控制器中。
ViewBag
ViewBag 只是一个在控制器和视图之间共享的对象。它是一种在两者之间转换数据块的有用方式。请注意,ViewBag 是动态类型,而不是强类型(在运行时确定),因此您将无法使用 IntelliSense 帮助您查找 ViewBag 对象中可用的内容。
还有两个用于控制器和视图之间数据传输的共享对象
- ViewData – 本质上是一个字典,其中键是字符串,值是对象。对于较大的数据集效率更高。
- TempData – 临时数据,只在同一会话中持久化,主要用于为特定用户的特定会话保留数据。
让我们尝试从 ViewBag 对象上的属性打印标题到我们的新 HTML 页面,我们将从控制器设置该属性。
切换回控制器。在我们的 Index 方法中,就在我们返回视图之前,添加以下行
ViewBag.MyHeader = "Hello World!";
切换回视图。将 h2 标签替换为以下内容
<h2>@ViewBag.MyHeader</h2>
现在,按下 F5 开始调试。这将启动您的默认浏览器实例,托管在 IIS Express 的本地实例上。您网站的基本 URL 将是 https://,后跟一个随机端口号(默认情况下——您可以在项目属性窗口中更改它)。将以下 URL 粘贴到地址栏中:https://:99999/Person/Index。将 99999 替换为您在浏览器启动时看到的随机端口号。
ASP.NET MVC 路由
它奏效了!您可以看到路由非常直观——我们访问了 Person 控制器,然后访问了 Index Action。请注意,我们 **没有** 使用 **PersonController** 作为控制器名称——这是 ASP.NET MVC 控制器命名约定的一部分。现在回到浏览器并从 URL 中删除 Index 段——您可以看到页面仍然正确加载;再次,更多约定优于配置——当未提供 Action 名称时,ASP MVC 的默认路由系统将查找名为 Index 的 Action。这有助于创建更简洁、对搜索引擎友好的 URL。
您可以通过修改 App_Start 文件夹下的 RouteConfig 类来创建自定义和更复杂的路由规则。
布局页 (Layout Page)
注意,我们全新的视图看起来非常漂亮,而我们却没做任何工作?这是因为布局页面。大多数 Web 应用程序在整个网站中都具有一致的外观——相同的页眉、菜单和页脚,以及我们可能希望在全站范围内提供的其他项目。要在 ASP.NET MVC 中实现这一点,我们使用布局页面。
布局页面是一个普通的视图,只是它不与任何动作或控制器关联。当您创建新视图时,Visual Studio 会询问您是否希望将其与布局页面关联——默认情况下,此选项是启用的。
默认情况下,布局页面名为 _Layout.cshtml,它位于 Views 文件夹下的 Shared 文件夹中。您可以通过修改 _ViewStart.cshtml 文件来更改此默认值。
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
打开布局页面。您会注意到 **RenderBody** 方法在 HTML div 内部被调用。这是每个视图将被渲染的地方。
在 ASP.NET MVC 5 中,默认布局页面加载 Bootstrap CSS 库,这意味着您可以在使用布局页面的任何页面中使用它。这就是我们刚刚添加的标题具有与普通 HTML 样式不同的样式的原因。
为您的模型创建存储库
现在我们回到计划我们的应用程序。我们需要创建一个存储应用程序中 **人员** 的存储库。我们将使用 Entity Framework 来实现。
本教程将假定您熟悉 Entity Framework Code First 的工作原理,因此请继续创建一个包含 Person 的 DbSet 的简单 PersonManagerDbContext。我们将把此数据上下文的实例作为私有字段存储在我们的 PersonController 中,并在构造函数中对其进行初始化。
private PersonManagerDataContext mDataContext;
public PersonController()
{
mDataContext = new PersonManagerDataContext();
}
现在,继续用 Persons 填充此表(您可以通过创建一个控制台应用程序项目,引用当前项目,并将 Person 对象添加到 PersonManagerDbContext 的实例中,然后调用 context.SaveChanges() 来轻松完成此操作)。
将视图绑定到模型
所以现在我们可以通过调用 mDataContext.Persons 轻松访问数据库中的 Persons。但是我们如何将其提供给视图呢?
一种方法是使用共享对象之一——ViewBag 或 ViewData。我们可以向 ViewBag 添加一个 Person 属性,并从视图中访问它。这种方法存在几个问题
- 必要的类型转换 – 您需要将属性转换回字符串(或它们的任何类型)。这导致 CLR 的另一次装箱和拆箱实例,效率较低。但更重要的是,它可能导致不必要的运行时类型转换错误。
- 动态类型化——由于类型在运行时解析,因此没有 IntelliSense 可用。即使使用 ViewData 字典,您也无法在编译时知道您是否在键值中拼写错误。
- 性能影响——除了类型转换所需的性能影响外,动态类型和字典的效率低于强类型和集合。当然,在较小的规模上,这不会很明显。
为了避免这种情况,我们可以将模型实例提供给视图。为此,打开我们之前处理过的 Index 视图,并在页面顶部添加以下行
@model IEnumerable<PersonManager.Models.Person>
@_model_ 是 Razor 保留的关键字,它声明与此视图关联的当前模型类型。然后您可以使用 Model 关键字访问此模型类型的实例。请注意,与 C# 一样,大小写很重要。大写 M 的 _Model_ 表示对模型实例的调用,而小写 m 的 _model_ 表示声明(类似于 _using_)。
Model 是强类型化的,您现在可以通过简单地声明属性名称来访问模型类的属性。显然我们想要一个所有成员的列表,所以我们指定了一个 Persons 的 IEnumerable。
现在我们需要将 Person 类实例注入到 View 中。回到你的 Controller 类,并修改 return 语句,如下所示
return View(mDataContext.Persons);
请注意,此 View 方法的重载接受一个 Object,因此如果您注入了错误的 Model 类类型,它只会在运行时确定。
以下是如果我们将集合中的第一个项目而不是 Persons 的 IEnumerable 传递,然后运行应用程序并导航到 Person 控制器上的 Index Action 时会发生的情况
显示模型
现在我们有了可用的模型,我们可以使用 Razor 标记构建页面。标记如下所示
@using PersonManager.Models
@model IEnumerable<PersonManager.Models.Person>
@{
ViewBag.Title = "Persons";
}
<h2>Persons</h2>
<table class="table">
<thead>
<tr>
<th>#</th>
<th>First Name</th>
<th>Last Name</th>
<th>Address</th>
<th>Phone</th>
<th>Email</th>
</tr>
</thead>
<tbody>
@foreach (Person person in Model)
{
<tr>
<td>@person.PersonId</td>
<td>@person.FirstName</td>
<td>@person.LastName</td>
<td>@person.Address</td>
<td>@person.PhoneNumber</td>
<td>@person.Email</td>
</tr>
}
</tbody>
</table>
代码非常简单:我们静态声明了一个 HTML 表格,创建了它的头部部分,并通过使用 *foreach* 语句动态创建表格行,每行代表从数据库中检索到的一个人。
请注意 Person 类的 using 语句;这与 model 语句不同,并且与我们在传统类中使用的 using 语句相同。
实现添加人员的动作
现在我们将实现向存储库添加新 Person 的功能。为此,我们需要创建两个 Action
- GET 动作 – 此动作将由浏览器最初调用,以向用户显示提交表单。
- POST 动作 – 当我们提交表单时,将调用此动作。
但是我们应该创建两个视图吗?不一定!只有 GET 动作需要实际返回一个视图。提交表单后,我们可能只想将用户重定向回主页。
让我们实现这两个动作
[HttpGet]
public ActionResult AddPerson()
{
return View();
}
[HttpPost]
public ActionResult AddPerson(Person person)
{
mDataContext.Persons.Add(person);
mDataContext.SaveChanges();
return RedirectToAction("Index");
}
请注意,我们为了保持一致性和清晰度,将两个 Action 都命名为相同(因为一个没有另一个就无法真正存在)。但是 ASP.NET 如何知道在每种使用情况下访问哪个 Action 呢?这要归功于 *[HttpGet]* 和 *[HttpPost]* 属性。当 HTTP GET 请求到达 /AddPerson 路由时,它将被路由到第一个 Action,返回一个视图(我们友好的表单)。HTTP POST 请求将直接路由到第二个 Action,该 Action 自然接受一个 Person 对象以添加到数据库中。
添加服务器端验证
设计任何面向用户应用程序的基本规则之一是永远不要信任您的用户。我们希望确保所有字段都填充了数据,并在将数据添加到数据库之前执行其他基本测试。
我们可以通过在 *Person* 参数上添加一系列笨拙的 *if* 语句来做到这一点,但这有点难以阅读。如果我们要将这些规则应用到其他地方呢?我们只会重复代码。
ASP.NET 通过直接在我们的模型类上使用数据验证属性 (System.ComponentModel.DataAnnotations) 帮助我们进行验证。请随意在 MSDN 上自行探索此命名空间。现在,让我们添加一些这些属性。
public class Person
{
[Key]
[Required]
public int PersonId { get; set; }
[Required]
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Required]
[Display(Name = "Last Name")]
public string LastName { get; set; }
[Required]
public string Address { get; set; }
[Required]
[EmailAddress]
public string Email { get; set; }
[Required]
[Display(Name = "Phone Number")]
public long PhoneNumber { get; set; }
}
还有更多有用的具有常见规则的属性,以及 *RegularExpression* 属性,允许您使用正则表达式自定义验证模式。
现在回到控制器,修改 AddPerson POST Action
[HttpPost]
public ActionResult AddPerson(Person person)
{
if (ModelState.IsValid)
{
mDataContext.Persons.Add(person);
mDataContext.SaveChanges();
RedirectToAction("Index");
}
return View();
}
如果我们将模型绑定到视图的所有属性都正确验证,则 ModelState.IsValid 将返回 true。如果验证失败,我们将不会将更改提交到数据库。如果用户尝试提交此表单,它将首先进行验证,并且一旦返回视图,ASP.NET MVC 将自动显示验证错误(我们稍后会看到如何实现)。
最后,正如您可能自己理解的那样,RedirectToAction 在被调用时会将用户重定向到请求的 Action。
创建表单并提交数据
让我们回到 AddPerson GET Action,并添加一个新视图。粘贴以下代码
@model PersonManager.Models.Person
<h2>Add a new person to the database</h2>
@using (Html.BeginForm())
{
<div class="form-group">
@Html.LabelFor(model => model.FirstName)
@Html.TextBoxFor(model => model.FirstName, new { Class = "form-control" })
@Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="form-group">
@Html.LabelFor(model => model.LastName)
@Html.TextBoxFor(model => model.LastName, new { Class = "form-control" })
@Html.ValidationMessageFor(model => model.LastName)
</div>
<div class="form-group">
@Html.LabelFor(model => model.Address)
@Html.TextBoxFor(model => model.Address, new { Class = "form-control" })
@Html.ValidationMessageFor(model => model.Address)
</div>
<div class="form-group">
@Html.LabelFor(model => model.Email)
@Html.TextBoxFor(model => model.Email, new { Class = "form-control" })
@Html.ValidationMessageFor(model => model.Email)
</div>
<div class="form-group">
@Html.LabelFor(model => model.PhoneNumber)
@Html.TextBoxFor(model => model.PhoneNumber, new { Class = "form-control" })
@Html.ValidationMessageFor(model => model.Email)
</div>
<input type="submit" class="btn btn-default"/>
}
继续运行应用程序,然后在浏览器中导航到 Person/AddPerson 路由。
在 Person 控制器中的 POST AddPerson 方法的开头放置一个断点,向表单添加一些数据并提交它。
如果将 *person* 变量添加到监视窗口,您将能够看到您刚刚输入到表单中的相同值。
让我们仔细看看这个魔术是如何发生的。如您所见,我们将此视图绑定到 *Person* 类型(这次不是它们的集合,因为我们只想提交一个 *Person*)。正因为如此,我们可以使用 ASP.NET MVC 的表单助手。
- *Html.BeginForm()* 将为我们渲染表单本身,并将适当的提交 URL 作为表单标签的 *action* 属性注入(以便表单知道将自身提交到何处)。默认情况下,它将假定我们对 GET 和 POST Actions 进行了相同的命名(再次强调,约定优于配置),但也有重载允许您为提交表单命名不同的 Action 或 Controller。
- *Html.TextBoxFor* 将创建一个 *文本框* 类型的输入框,但重要的是它绑定到模型类的指定属性!当我们向服务器提交表单时,ASP.NET MVC 将把此文本框的值注入到我们发送的模型的匹配属性中,因此在 POST AddPerson 方法中,我们可以直接调用 *person.FirstName* 或 *person.LastName* 并获取用户提交的值。这是通过接受模型类类型的简单表达式完成的,如您在代码示例中看到的。
- *Html.LabelFor* 将为同一属性的 *input* 标签创建一个 *label* HTML 标签。默认标签将只是模型的属性名称,但您可以通过在模型类中使用 Display 属性(请参阅之前的 Person 类代码示例)来更改它。
- *Html.ValidationMessageFor* 将根据我们在 *Person* 模型类中通过 DataAnnotations 定义的验证规则显示验证消息。
如果您不使用模型绑定,实现相同的逻辑将更加麻烦。您需要自己编写 HTML 标签,其中 *value* 属性将是 * @ViewBag.MyValue * 之类的内容。这不是推荐的方法。
在 ASP.NET MVC HTML 助手中添加 HTML 属性
许多 ASP.NET MVC 的 HTML 助手为我们生成方便的 HTML,但如果我们要自定义 HTML 怎么办?(例如,添加一个 *class* 属性来样式化由 *TextBoxFor* 助手创建的 *文本框*)
我们可以很简单地做到这一点,通过使用一个接受包含我们要添加的 HTML 属性的对象的助手的重载。请看上面的例子。我创建了一个只包含一个名为 Class 的 *string* 属性的对象——ASP.NET MVC 将其添加为 *Class* 属性。您可以添加任何类型和组合的 HTML 属性,甚至是非标准的属性(例如用于 jQuery 数据操作的属性等等)。
添加客户端验证
还记得我们说过“永远不要相信用户”吗?虽然这是真的,但我们也不希望用户将表单发送到服务器并等待响应,只是为了发现他忘记了一个字段。我们还希望避免这种不必要的服务器流量。
这就是客户端验证发挥作用的地方。有多种方法可以实现这一点,无论是通过 HTML 5(仅在现代浏览器中支持)还是通过 jQuery 等库(具有更广泛的支持)。
ASP.NET MVC 有一个很酷的功能,它会自动使用我们通过 DataAnnotations 属性设置的规则来实现 jQuery 客户端验证。这又允许我们在一个地方定义验证规则。
请注意,客户端验证本身绝不应该被信任,因为如果用户的浏览器禁用了 JavaScript,它将不会触发。您应该始终进行服务器端验证。
为此,您需要安装名为 Microsoft jQuery Unobtrusive Validation 的 NuGet 包。安装完成后,将其作为 Bundle 添加到 BundleConfig.cs 文件中,如下所示
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.validate*"));
捆绑包是 ASP.NET MVC 的另一个独特概念,本质上是脚本或其他类型文件的组——因为一些 JavaScript 库和框架以多个不同的文件形式出现。在这种情况下,我们创建了一个包,它收集了 *Scripts* 文件夹中所有包含 *jquery.validate* 的文件(注意星号)。
现在转到布局页面并在页面底部添加此行
@Scripts.Render("~/bundles/jqueryval")
这将渲染带有链接到 Bundle 中所有脚本的 *<script>* 标签的 HTML。
这就是您需要做的一切。如果您重新加载并查看 HTML 页面的源代码,您将看到类似以下内容
_data-*_ 属性是 ASP.NET MVC 添加的特殊属性,并由 jQuery 解析以执行验证。您可以通过在模型类上的 DataAnnotation 属性中提供参数来自定义显示的错误消息(请参阅示例)。这同样会影响客户端和服务器验证。
接下来呢?
这是本 ASP.NET MVC 基础教程的结束,但关于这个框架还有很多需要学习。我没有将这些主题包含在教程中,以免示例过于复杂和难以理解,但我鼓励您阅读更多关于这些主题的信息
- 部分视图 (Partial Views)
- 不同类型的 ActionResult(您从 Action 返回的内容)——尤其是 JsonResult
- 授权和身份验证(Windows 和个人用户帐户)
- Web API(技术上,不完全是 ASP.NET MVC 的一部分,但密切相关)