上一节我们创建了自己的第一个MVC3项目,并了解了Controller和View的添加方法。今天我们将仿照大米返利网注册模块写个小例子,来进一步了解Model、Action、Form等相关内容。
【情景假设】
- 首页--欢迎页面,简单介绍大米返利网,并提供注册链接;
- 注册--用户使用网站之前要先注册为会员,注册页面还要对用户填写的信息进行有效性验证;
- 注册完成--完成之后会跳转到一个提示页面,并向用户邮箱发送一封邮件。
一. 首页
1. 将上一节的Index页面用作首页,再添加一些说明文字。
首页 View代码@{
ViewBag.Title = "首页";
}
<h2>@ViewBag.hello</h2>
<p>大米返利网提供淘宝网等多家商城的返现优惠,<br/>
返现比例高,提现速度快,注册赠1元,满3元提现。</p>
<p>点此注册</p>
接下来我们就要为“点此注册”提供链接页面了。
二. 添加注册页面
1. 创建数据Model
MVC中的M代表的领域模型,是应用程序中极其重要的部分之一,一个设计完好的MVC项目往往从设计完好的model开始,然后在此基础上继续添加controller和view。在我们的项目中,model是对现实世界对象的封装,定义规则、处理等等。具体实现时Model一般就是对项目中通用性对象的属性、方法进行封装而来的C#类,然后controller和view以一定的方式暴露给客户端。
接下来我们添加一个用户信息的model类:右键models文件夹->Add->Class->UserInfo.cs->Ok.
UserInfo.cs Code /// <summary>
/// 注册用户实体
/// </summary>
public class UserInfo
{
/// <summary>
/// 自动编号
/// </summary>
public int Id { get; set; }
/// <summary>
/// 用户名
/// </summary>
public string UserName { get; set; }
/// <summary>
/// 密码(明文简单示例)
/// </summary>
public string Password { get; set; }
/// <summary>
/// qq号码
/// </summary>
public string QQ { get; set; }
/// <summary>
/// 邮箱地址
/// </summary>
public string Email { get; set; }
}
2. 添加Action
在IndexController中添加新的action:
//注册
public ActionResult Register()
{
return View();
}
3. 添加强类型View
- 创建view:强类型view目的是展现针对具体类型的实体,指定具体类型之后MVC会为其提供许多快捷的操作。需要注意的是,在添加强类型View之前,我们要先编译整个MVC项目,否则添加View时就会找不到先前添加的UserInfo实体。
添加步骤:
在Register Action代码块内右键->Add View->选中 Create a strongly type view复选框->Model class下拉框选择UserInfo->提供的模板选择Empty->Add。如下图所示:
添加完成之后我们发现新添加的View是以@model的Razor代码开头的。接下来我们将会看到,这正式强类型view以及它能提供诸多便捷的关键所在。
三、编辑表单
1. View代码
<h1>大米返利网</h1>
@using(Html.BeginForm())
{
<p>用户名:@Html.TextBoxFor(m=>m.UserName)</p>
<p>密码:@Html.PasswordFor(m=>m.Password)</p>
<p>确认密码:@Html.PasswordFor(m=>m.Password)</p>
<p>QQ:@Html.TextBoxFor(m=>m.QQ)</p>
<p>Email:@Html.TextBoxFor(m=>m.Email)</p>
<input type="submit" value="马上注册"/>
}
这里用的是Razor语法,使用过程中VS为我们提供了丰富的智能感知。以前不熟悉的同学可能会看着满眼的@符号不太自在,用一段时间就该上瘾了,因为它真的很好上手。运行效果如下:
2. Html几个helper方法:
首先,我们看一下页面源代码:
页面源代码<h1>大米返利网</h1>
<form action="/index/register" method="post">
<p>用户名:<input id="UserName" name="UserName" type="text" value="" /></p>
<p>密码:<input id="Password" name="Password" type="password" /></p>
<p>确认密码:<input id="Password" name="Password" type="password" /></p>
<p>QQ:<input id="QQ" name="QQ" type="text" value="" /></p>
<p>Email:<input id="Email" name="Email" type="text" value="" /></p>
<input type="submit" value="马上注册"/>
</form>
- 不难看出,通过Razor语法中的Html helper方法,将Model中的属性用Input控件形式展现出来了。例如
@Html.TextBoxFor(m=>m.UserName)
生成html时,input控件type=”text”, id和name属性都被赋值为"UserName“。对应html代码为:
<input id="UserName" name="UserName" type="text" value="" />
- 对于强类型view,书写lamda语法时有着丰富的智能感知。如果不想写成lamda形式,还可以这样 @Html.TextBoxFor(“UserName”)
- Html.BeginForm:
代码格式为@using(Html.BeginForm()){ …},通常使用using关键字是为了走出花括号时释放较占资源的对象,而在这里可以理解为关闭<form>标签。生成form属性时,默认的action会提交回当前的url,而method默认设置为post。最终生成的html源码为:<form action="/index/register" method="post"> ……</form>。
另外,在WebForm开发时,每个页面只允许使用一个服务端form,并且包含ViewState以及postback逻辑,而在MVC中是没有服务器端form这个概念的,没有ViewState以及postback机制,每个页面可以放置多个form。
- Html.ActionLink:用来添加action页面的链接,我们可以在首页为“点此注册”添加链接:
@Html.ActionLink("点此注册","Register","Index")
四. 表单提交
1. HttpGet和HttpPost:
为了接收并处理提交的表单数据,我们还需要再添加一个Register action,这两个action的作用是:
- 一个用来响应Http Get请求: 为action添加HttpGet特性(也可以省略),Get请求通常是用户第一次访问页面时,通过该action初始化空白表单。
- 一个用来响应Http Post请求:为acton方法添加HttpPost特性,Html.BeginForm()创建的窗体默认被浏览器处理为Post请求。这个版本的action方法负责接收提交的表单数据并进行相应处理。
[HttpGet]
public ActionResult Register()
{
return View();
}
[HttpPost]
public ActionResult Register(UserInfo userInfo)
{
return View("Complete",userInfo);
}
2.Model Binding
在上面的post方法中,使用了MVC中一个非常不错的特性---Model Binding,它可以解析传来的数据并将其对应到领域模型的属性。其实这个Model Binding过程是双向的,当创建form数据时,input控件的值是根据与其name对应的model属性来赋值的;反过来,当提交form表单时,通过model binding又可以根据input控件的name属性来为model实体同名的属性赋值,进而提交到post action方法。
五、表单验证
在MVC应用程序中,我们一般把验证添加在model实体而不放在用户界面,这样只要我们在一处定义了验证规则便可以多处生效。ASP.NET MVC总具体实现方式是:使用System.ComponentModel.DataAnnotations 中定义的特性,将其声明在model属性作为验证规则就可以生效了。
1. Model实体添加验证规则
Model Validation Codeusing System.ComponentModel.DataAnnotations;
namespace DamifanliMvc3.Models
{
/// <summary>
/// 注册用户实体
/// </summary>
public class UserInfo
{
/// <summary>
/// 自动编号
/// </summary>
public int Id { get; set; }
/// <summary>
/// 用户名
/// </summary>
[Required(ErrorMessage = "请输入用户名")]
[RegularExpression("^[a-zA-Z][a-zA-Z0-9]{2,14}$", ErrorMessage = "请输入3-15位字母或数字")]
public string UserName { get; set; }
/// <summary>
/// 密码(明文简单示例)
/// </summary>
[Required(ErrorMessage = "请输入密码")]
public string Password { get; set; }
/// <summary>
/// qq号码
/// </summary>
[Required(ErrorMessage = "请输入QQ号码")]
[RegularExpression("[1-9][0-9]{4,}",ErrorMessage = "请输入正确的qq号码")]
public string QQ { get; set; }
/// <summary>
/// 邮箱地址
/// </summary>
[Required(ErrorMessage = "请输入邮箱地址")]
[RegularExpression(@"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*",ErrorMessage = "请输入正确的邮箱地址")]
public string Email { get; set; }
}
}
2.ModelState.IsValid
我们可以在Controller中使用ModelState.IsValid来检验是否存在验证问题。
public ActionResult Register(UserInfo userInfo)
{
if(ModelState.IsValid)
{
return View("Complete", userInfo); //Complete Action后续创建
}
return View();
}
3.错误提示
当用户输入不符合规则时,我们可以在view中使用Html.ValidationSummary()来提示用户。
@using(Html.BeginForm())
{
@Html.ValidationSummary()
<p>用户名:@Html.TextBoxFor(m=>m.UserName)</p>
……
}
该方法会在页面中放置一系列隐藏的li,MVC可以令这些位置可见并显示model验证属性中定义的错误信息,如下图所示。点击注册按钮时该页面不会进行跳转,直到所有输入都符合规范为止。值得庆幸的是,提交失败时之前填写的数据仍然会保留在页面中。
查看页面源代码:
<p>
用户名:<input class="input-validation-error" data-val="true" data-val-regex="请输入3-15位字母或数字" data-val-regex-pattern="^[a-zA-Z][a-zA-Z0-9]{2,14}$" data-val-required="请输入用户名" id="UserName" name="UserName" type="text" value="" />
</p>
六、注册完成页面
1.添加Complete View:
在前面的post提交的Register中,我们已经给出了注册完成时要跳转的目标”Complete”,并且传递了变量userInfo,接下来我们添加一个强类型UserInfo类型的View。
修改代码如下:
@model DamifanliMvc3.Models.UserInfo
@{
ViewBag.Title = "注册完成";
}
<h2>注册完成</h2>
<p>
恭喜,您已注册成功,请妥善保管注册信息:<br/>
账号:@Model.UserName<br/>
QQ:@Model.QQ<br/>
Email:@Model.Email<br/>
大米返利网祝您购物愉快!
</p>
2. 发送邮件通知
在展示Complete View的同时,我们使用WebMail类来发送通知邮件。
@{
try
{
WebMail.SmtpServer = "smtp.sina.com";
WebMail.SmtpPort = 587;
WebMail.EnableSsl = true;
WebMail.UserName = "CathyChen";
WebMail.Password = "damifanli";
WebMail.From = "cathychen@sina.com";
WebMail.Send(@Model.Email,"成功注册大米返利网",@Model.UserName+",您已成功注册大米返利网,祝您购物愉快!");
}
catch
{
@:抱歉,通知邮件发送失败!
}
}
小结:
到这里,今天的学习基本结束了。当然了这只是一个简单的示例,实际使用中还有很多可以改进的地方,比如将发送邮件功能放在单独的模块中调用而不是将代码块嵌在View中,以便重复使用;另外,这里的错误处理使用的try…catch,其实可以跳转到单独的错误页面。