模型绑定(Model Binding)是指,用浏览器以Http请求方式发送的数据来创建.Net对象的过程。
准备示例项目
新建一个空的MVC项目,名叫MvcModels,接下去会以此项目来演示各种功能。
在Models文件夹中创建一个Person.cs类文件,代码如下图所示:
namespace MvcModels.Models
{
public class Person
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
public Address HomeAddress { get; set; }
public bool IsApproved { get; set; }
public Role Role { get; set; }
}
public class Address
{
public string Line1 { get; set; }
public string Line2 { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
}
public enum Role
{
Admin,
User,
Guest
}
}
定义一个Home控制器,代码如下图所示:
public class HomeController : Controller
{
private Person[] personData = {
new Person { PersonId = 1,FirstName = "Adam",LastName = "Freeman" },
new Person { PersonId = 2,FirstName = "Jacqui",LastName = "Griffyth"},
new Person { PersonId = 3,FirstName = "John",LastName = "Smith" },
new Person { PersonId = 4,FirstName = "Anne",LastName = "Jones"}
};
// GET: Home
public ActionResult Index(int id)
{
Person dataItem = personData.Where(p => p.PersonId == id).First();
return View(dataItem);
}
}
新增Index控制器对应的Index.cshtml页面,代码如下:
@model MvcModels.Models.Person
@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Person</h2>
<div><label>ID:</label> @Html.DisplayFor(m => m.PersonId)</div>
<div><label>First Name:</label>@Html.DisplayFor(m => m.FirstName)</div>
<div><label>Last Name:</label>@Html.DisplayFor(m => m.LastName)</div>
<div><label>Roles:</label>@Html.DisplayFor(m => m.Role)</div>
新增_layout.cshtml布局页面,代码如下:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
<style>
label {
display:inline-block; width:100px;font-weight:bold;margin:5px;
}
form label {
float:left;
}
input.text-box {
float:left;margin:5px
}
button[type=submit] {
margin-top:5px;
float:left;
clear:left;
}
form div {
clear:both;
}
</style>
</head>
<body>
<div>
@RenderBody()
</div>
</body>
</html>
运行程序,并导航到/Home/Index/1,结果如下图所示:
默认的动作绑定器ControllerActionInvoker要依靠模型绑定器来生成调用动作所需的数据对象。模型绑定器由IModelBinder接口所定义,接口如下图所示:
public interface IModelBinder
{
object BindModel(ControllerContext controllerContext,ModelBindingContext bindingContext)
}
在一个MVC应用程序中,可以有多个模型绑定器,而每个绑定器可以负责绑定一个或者多个模型类型。它会考察该方法所定义的参数,并查找各个参数类型所依赖的模型绑定器。
在上述示例中,动作调用器会检查Index方法,并发现它具有一个int型的参数。于是会查找负责int值绑定的绑定器,并调用BindModel方法。
使用默认的模型绑定器
虽然程序可以定义自定义的模型绑定器,大多数程序都是依靠内建的模型绑定器DefaultModelBinder.当动作调用器找不到绑定某个类型的自定义绑定器时,这个默认的模型绑定器便是由动作调用器所使用的一个绑定器。默认情况下,这个模型绑定器会搜索四个位置:
源 | 描述 |
Request.Form | 由用户在HTML的form(表单)元素中提供的值 |
RouteData.Values | 用应用程序路由获得的值 |
Request.QueryString | 包含在请求URL中的查询字符串部分的数据 |
Request.Files | 请求中上传的文件 |
这些位置被依序搜索。例如,在上述简单示例中,DefaultModelBinder会为id参数查找以下的一个值:
1、Request.Form["id"]
2、RouteData.Values["id"]
3、Request.QueryString["id"]
4、Request.Files["id"]
只要找到值,便会停止搜索。在上述例子中,搜索到第二步就停了,不会到第三步。
当处理简单参数类型时,DefaultModelBinder会尝试使用 System.ComponentModel.TypeDescriptor类。将已经从请求数据获得的字符串值转化成参数类型。如果无法转为这个值:例如给int值传一个“apple”,程序就会报错:
解决这个问题有两种办法:
一、在动作方法参数中设置可空类型(nullable),这为绑定器提供一个退路,一个可空的int参数可以不必为数字值,这让模型绑定器在调用动作时,这可以让动作方法参数设置为Null。
public ActionResult Index(int? id)
二、 在动作方法中运用默认值,当模型绑定器无法为id参数找到一个值时,将默认值1来代替,如下所示:
public ActionResult Index(int