第一个 MVC 应用程序(下半部分)
2.4 创建一个简单的数据录入应用程序
本章的其余部分将通过一个简单的数据录入应用程序来考查 MVC 的更多基本特性。本小节打算分步进行,目的是演示 MVC 的运用。
B1、设计一个数据模型
在 MVC 中,M 代表模型(Model),它是应用程序最重要的部分。
模型是定义应用程序主题的现实对象、过程以及规则的表示,称为域。
模型,通常称为域模型,包含应用程序域中要建立的 C#对象,称为域对象。这些域对象构成了应用程序的全部事物以及操纵这些
对象的方法。
视图和控制器以一致的方式将域暴露给客户端。
一个设计良好的 MVC 应用程序,必须从设计良好的模型开始,它是随后添加控制器和视图的焦点。
(对于 “晚会邀请”应用程序,不需要复杂的模型。因为这是一个简单的应用程序,只需要创建一个域类(可以称为 GuestResponse),由它负责存储、验证并确认“回复邀请”)
添加模型类
MVC 的约定是将建立模型的类放在 “Models”文件夹中,该文件夹是 Visual Studio 最初建立项目时创建的。
1、右击 “Models”文件夹——“添加”——“类”
2、将文件名设置为 “GuestResponse.cs”
3、单击“添加”按钮。(创建完成后修改文件内容——为模型对象类添加属性)
(可以通过问号“?” 将 “int”、“bool” 等类型的属性设置为可空的类型)
B2、★ 链接动作方法
该应用程序的目标之一是要包括一个回复邀请的表单,因此需要在 Index.cshtml 视图中添加一个指向它(动作方法)的链接。
……
@Html.ActionLink("现在回复", "RsvpForm")
……
Html.ActionLink 是一个 HTML 的辅助器方法(Helper Method)
MVC 框架附带了一组内置的辅助器方法,它们可以方便地用来渲染 HTML 的链接、文本输入框、复选框 以及其他种类的内容。
这个 ActionLink 方法有两个参数:第一个是该链接的显示文本,第二个是用户单击该链接时将要执行的动作。
(第21~23章将解释完整的 HTML 辅助器方法集合)
Html.ActionLink 方法已经检测了应用程序的 URL 路由配置,并得出 /Home/RsvpForm 是一个指向 HomeController 控制器
上 RsvpForm 动作的 URL。
(与传统的 ASP.NET 应用程序不同,MVC 的 URL 并不对应物理文件。每个动作方法有它自己的 URL,而 MVC 使用 ASP.NET
的路由系统将这些 URL 转换成动作)
创建动作方法:
此时,可以在 HomeController 类中添加一个名称为 “RsvpForm” 的方法来完成这一工作。
public ViewResult RsvpForm()
{
return View();
}
添加强类型视图:
这里打算为 RsvpForm 动作方法添加一个视图,但采取了稍有不同的方式——创建一个强类型视图。
强类型视图意在渲染一个特定的域类型,而且,如果指定了想使用的类型(本例是 GuestResponse),MVC 将能够提供一些
便于使用这个类型的便捷方法,从而可以在视图中方便地使用这个类型对象。
(在做进一步工作之前,要确保已编译了 MVC 项目。如果已经创建了 GuestResponse 类,但未进行编译,MVC 将不能为这个
类型创建强类型视图。 要编译应用程序,可以 “生成”——“生成解决方案”,或简单地按快捷键 F6)
1、在代码编辑器中右击 ResvForm 方法,然后选择 “添加视图”
2、确保将 “视图名”设置为 “ResvForm”,将“模板”设置为 “空模板”,并从“类模板”字段的下拉列表中
选择“GuestResponse(PartyInvites.Models)”,让(视图)选项中的复选框处于未选状态。
3、单击 “添加”按钮。(这是另一种结构的 HTML 文件,它包含了一个 @model 的 Razor 表达式。过一会儿就会明白,这是
强类型视图,并是为视图提供便利的关键——@model PartyInvites.Models.GuestResponse)
(在创建视图时,所选择和勾选的选项决定了视图文件的初始内容(跟别的文件没有关系),其他没什么作用。例如,
你可以将常规视图修改成强类型视图,只需在代码编辑器中添加或去除 @model 指示符 即可)
B3、建立表单
现在已经创建了强类型视图,可以扩建这个 RsvpForm.cshtml 的内容(在 RsvpForm.cshtml 文件中创建表单视图)
@using (Html.BeginForm())
{
<p>姓名:@Html.TextBoxFor(x=>x.Name) </p>
<p>邮箱:@Html.TextBoxFor(x=>x.Email) </p>
<p>手机:@Html.TextBoxFor(x=>x.Phone) </p>
<p>是否参加?@Html.DropDownListFor(x=>x.WillAttend, new[ ] {
new SelectListItem() { Text="是,我参加", value=bool.TrueString },
new SelectListItem() { Text="否,不参加", value=bool.FalseString }
}, “请选择”)
</p>
<input type="submit" value="回复邀请" />
}
这里对 GuestResponse 模型类的每一个属性都使用了一个 HTML 辅助器方法,以便渲染一个适当的 HTML 的 input 控件。
这些辅助器方法都能够用一个 lambda 表达式来选择与 input 元素有关的属性。(如:@Html.TextBoxFor(x=>x.Phone))
这个 TextBoxFor 辅助器方法会生成一个 input 元素的 HTML,将该元素的 type 参数设置为“text”,id 和 name 标签属性设置
为“Phone”,Phone 是所选域类的属性名。于是为模型属性 Phone 生成了一个文本输入框的 HTML 标记,如下所示:
<input id="Phone" name="Phone" type="text" value="" />
这种灵活的特性是能够起作用的,因为 RsvpForm 视图是强类型的,而且已经告诉 MVC,GuestResponse 是希望用该视图
渲染的类型。——这为 HTML 辅助器方法提供了所需的信息,使其能够理解从 @mldel 表达式所读取的属性是哪一种数据类型。
替代运用 lambda 表达式的另一种方法是将模型类型的属性名指定为一个字符串,如:@Html.TextBox("Email")
另一个便利的辅助器方法是 Html.BeginForm,它生成一个回递给动作方法的 HTML 表单元素(<form>元素)
这里未给辅助器方法传递任何参数,于是它假设要回递的目标是请求此 HTML 文档的同一个 URL。
一个整洁的技巧是将它封装在一个 C# 的 using 语句中,如:@using (Html.BeginForm()) { }。
正常情况下,像这样运用 using 语句,会在对象超出范围时确保收回对象所占用的资源。例如,它通常用于数据库连接。
但这里并不是清理对象,而是 Html.BeginForm 辅助器在它超出范围时关闭 HTML 的 form 元素。——这意味着,
Html.BeginForm 辅助器方法会创建 form 元素的两部分(<form>元素的开标签和闭标签),如下所示:
<form action="/Home/RsvpForm" method="post">
…这里是表单内容…
</form>
这里的关键是演示如何用 HTML 辅助器方法创建一个表单。
B4、处理表单
这里尚未告诉 MVC,将表单递交给服务器时要做什么。(此时,单击“恢复邀请”按钮只会清除掉表单中已经输入的值。这是因为
该表单会回递给 Home 控制器中的 RsvpForm 动作方法,这只是告诉 MVC 再次渲染该视图——视图被再次渲染时,输入的数据会消失)
为了接收并处理表单所递交的数据,这里打算使用一个聪明的特性——添加第二个 RsvpForm 动作方法,以形成如下作用:
一种方法用于响应 HTTP 的 GET 请求:GET 请求是某人单击一个链接时,浏览器正常发出的请求。当有人第一次访问/Home
/RsvpForm 时,这个动作负责显示最初的空白表单。
一种方法用于响应 HTTP 的 POST 请求:默认情况下,用 Html.BeginForm() 渲染的表单是由浏览器作为一个 POST 请求
递交的。这个动作负责接收所递交的数据,并决定用它做什么。
以独立的 C#方法分别处理 GET 和 POST 请求,有助于保持控制器代码整洁,因为这两种方法有不同的职责。
这两种方法都由相同的 URL 进行调用,但 MVC 确保会根据所处理的是 GET 请求或 POST 请求,来调用合适的方法。
在 HomeController.cs 文件中添加一个支持 POST 请求的动作方法:
……
using PartyInvites.Models;
……
[ HttpGet ]
public ViewResult RsvpForm() { return View(); }
[ HttpPost ]
public ViewResult RsvpForm(GuestResponse gr)
{
return View("Thanks", gr);
}
这里在已有的 RsvpForm 动作方法上添加了 HttpGet 注解属性。这是告诉 MVC,该方法应该仅用于 GET 请求。
然后添加了一个重载版的 RsvpForm 方法,它带有一个 GuestResponse 参数,并运用了 HttpPost 注解属性。(该注解属性告诉 MVC ,这个新方法将处理 POST 请求)
这里已经引入了 PartyInvites.Models 命名空间,这样便可以直接使用 GuestResponse 模型类型,而不需要使用这个类的限定名。
B5、添加验证
验证是为了防止用户输入无意义的数据,甚至是递交空白的表单。
在 MVC 应用程序中,验证典型地运用于域模型,而不是用户界面。这意味着可以在一个地方(模型类中)定义验证条件,而在运用模型类的任何地方生效。
ASP.NET MVC 支持验证规则声明,这是以 System.ComponentModel.DataAnnotations 命名空间中的注解属性进行定义的 —— 意即,验证约束是使用标准的 C# 注解属性特性来表示的。
如下演示如何将这些注解属性运用于 GuestResponse 模型类:
using System.ComponentModel.DataAnnotation;
[ Required( ErrorMessage = "Please enter your name" )] // 意思是运用 Name 属性的地方不能为空,为空则显示对应的错误信息
public string Name { get; set; }
[ Required( ErrorMessage = "Please enter your email address" )] //一个属性可以有多个注解属性
[ RegularExpression( ".+\\@.+\\..+", ErrorMessage = "Please enter a valid email address" ) ]
public string Email { get; set; }
MVC 会自动地侦测这些验证注解属性,并在模型绑定过程中将它们用于验证数据。
一个可空的 bool 型(bool?)有3个可能的值:true、false 和 null。 如果用户尚未选择,系统会默认用 null 来表示,这会让 Required 注解属性能够报告一个验证错误。这是 MVC 框架如何优雅地将 C# 特性与 HTML 和 HTTP 相融合的一个很好的示例。
可以在控制器中使用 ModelState.IsValid 属性来检查是否有验证问题。(如下所示,在 HOME 控制器类的启用 POST 的 RsvpForm 动作方法中的实现)
[ HttpPost ]
public ViewResult RsvpForm( GuestResponse guestResponse)
{
if( ModelState.IsValid)
{
return View("Thanks", guestResponse) ; // 第一个参数是视图名
}
else
return View() ;
}
如果没有验证错误,便让 MVC 渲染 Thanks 视图。 如果有验证错误,则通过调用不带参数的 View 方法重新渲染 RsvpForm 视图。
在有错误时,仅显示表单并不十分有用,还需要给用户提供一些指示,告诉他们有什么问题,以及为什么不能接受他们所递交的表单。其实现办法是在 RsvpForm 视图中使用 Html.ValidationSummary(验证摘要)辅助器方法。
注意,在表单中输入的数据是被保留的,而且在带有验证摘要的视图被重新渲染时,这些数据会被再次显示出来。这是模型绑定特性的另一个好处,它简化了表单数据的工作。
高亮显示无效字段:
当模型类的某个属性验证失败时(前提是对应的属性运用了 Required 注解属性),HTML 辅助器方法会生成稍有不同的 HTML(在 input 标签内产生了一个值为 "input-validation-error" 的 class 标签属性)——通过创建样式表便可以利用这一特性,该样式表可以为这个 class 以及其他 HTML 辅助器方法所生成的 class 设置一些不同的 CSS 样式(这样就可以对不同的 class 值设置一些不同的显示效果)
MVC 项目的约定是:将静态内容(如 CSS 样式表等)放在名称为 Content 的文件夹中(可能要自己新建)
第一个 MVC 应用程序(下半部分)的更多相关文章
- 【MVC 4】1.第一个 MVC 应用程序
作者:[美]Adam Freeman 来源:<精通ASP.NET MVC 4> ASP.NET MVC 是微软的一个 Web开发框架,它整合了“模型—视图—控制器(MVC)”架构 ...
- 创建第一个MVC应用程序
整个国庆期假,Insus.NET没有出门,在家静心修炼MVC.这意味着Insus.NET将来的日子里会以MVC为学习,开发,应用作为重点,不过现在才开始踏出第一步...... 路慢慢...... 下载 ...
- 第一个 MVC 应用程序(上半部分)(《精通 ASP.NET MVC5》 的第二章)
本章将使用 ASP.NET MVC 框架创建一个简单的数据录入应用程序. 笔者会将过程分解成一个个的步骤,以便能够看出如何构造 ASP.NET MVC 应用程序.(对于一些未进行解释的内容,笔者提供了 ...
- 《精通ASP.NET MVC5》第2章 第一个MVC应用程序
控制器 public class NewHomeController : Controller { // GET: /NewHome/ public ...
- 跨平台应用集成(在ASP.NET Core MVC 应用程序中集成 Microsoft Graph)
作者:陈希章 发表于 2017年6月25日 谈一谈.NET 的跨平台 终于要写到这一篇了.跨平台的支持可以说是 Office 365 平台在设计伊始就考虑的目标.我在前面的文章已经提到过了,Micro ...
- 将最小的OWIN身份验证添加到现有的ASP.NET MVC应用程序
https://weblog.west-wind.com/posts/2015/Apr/29/Adding-minimal-OWIN-Identity-Authentication-to-an-Exi ...
- Entity Framework Core系列之实战(ASP.NET Core MVC应用程序)
本示例演示在ASP.NET 应用程序中使用EF CORE创建数据库并对其做基本的增删改查操作.当然我们默认你的机器上已经安装了.NET CORE SDK以及合适的IDE.本例使用的是Visual St ...
- MVC应用程序使用Entity Framework
创建空的MVC应用程序,为了想使用Entity Framework的类库,发现即无法正常引用.如下图,Insus.NET已经明确引了System.Data.Entity(下图Highlight的代码) ...
- ASP.NET + MVC5 入门完整教程三 (上) ---第一个MVC项目
https://blog.csdn.net/qq_21419015/article/details/80420815 第一个MVC应用程序 1创建MVC项目 打开VS ,File--新建--项目,选择 ...
随机推荐
- Python之路----递归函数
1.小练一下 用map来处理字符串列表,把列表中所有人都变成sb,比方alex_sb name=['alex','wupeiqi','yuanhao','nezha'] # def func(item ...
- 文件和打印机共享 win7 and xp
Win7 摘自:https://www.xp510.com/article/4249.html 首先开启服务 方法:开始---所有程序---附件---运行---输入services.msc----确定 ...
- python中hasattr, getattr,setattr及delattr四个方法
通过一个实例来说明,这四个函数的用法: 首先一个如下的一个简单的类: class Animal(object): def __init__(self,name, zone): self.name = ...
- Python Web学习笔记之TCP的3次握手与4次挥手过程
前言 尽管TCP和UDP都使用相同的网络层(IP),TCP却向应用层提供与UDP完全不同的服务.TCP提供一种面向连接的.可靠的字节流服务. 面向连接意味着两个使用TCP的应用(通常是一个客户和一个服 ...
- Java并发之FairSync和NonfairSync
Java并发中的fairSync和NonfairSync主要区别为: 如果当前线程不是锁的占有者,则NonfairSync并不判断是否有等待队列,直接使用compareAndSwap去进行锁的占用; ...
- 20145127《java程序设计》第二次实验
一.实验内容及其步骤 1.要想对某个程序进行单元测试,我们先是在eclipse中建立了一个新的项目,项目的名字是TDDDmeo.并在这个新的项目里右键单击创建一个source floder.并将flo ...
- bzoj 1010 玩具装箱toy -斜率优化
P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中.P教授有编号为1...N的N件玩具,第i件玩具 ...
- bzoj 2038 A-小Z的袜子[hose] - 莫队算法
作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命…… 具体来说,小Z把这N只袜子从1到N编号,然后从 ...
- DTMF在VOIP中的解决方案
双音多频DTMF(Dual Tone Multi-Frequency)信令,因其提供更高的拨号速率,迅速取代了传统转盘式电话机使用的拨号脉冲信令.DTMF也应用在交互式控制中,诸如语言菜单.语言邮件. ...
- tensorflow拟合随机生成的三维数据【学习笔记】
平台信息:PC:ubuntu18.04.i5.anaconda2.cuda9.0.cudnn7.0.5.tensorflow1.10.GTX1060 作者:庄泽彬(欢迎转载,请注明作者) 说明:感谢t ...