Asp.net mvc中的模型绑定,或许大家经常用,但是具体说他是怎么一回事,可能还是会有些陌生,那么,本文就带你理解模型绑定。为了理解模型绑定,本文会先给出其定义,然后对通过比,来得出使用模型绑定的方便。最后简单的模拟一下自定义模型绑定,让大家对模型绑定有进一步的认识。

一、模型绑定的概念

mvc framework中有一种技术,他就是模型绑定:
使用 被浏览器发送的http请求里面数据 来创建.net对象的过程。接下来就让我们来看看模型绑定的好处。

二、模型绑定好处

第二部分,我们通过不使用模型绑定和使用模型绑定的两种效果的对比,得出模型绑定的优势。那么接下来先让我们来模拟一个没有模型绑定的环境。

2.1没有模型绑定的环境

  让我们先来模拟一个没有模型绑定的环境,主要是让用户填写的信息传达到Controller中,然后经过加工后显示到View上(通常情况下我们是得到model后直接把model作为一个模型实体,提交到数据库了,为了简单起见,我只是把得到的模型信息显示出来)。先利用vs2010新建一个mvc3项目,在models文件夹中新建一个Person类,代码如下:

using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;
public class Person
{
[Display(Name="编号")]
public String Id { get; set; }
[Display(Name = "姓:")]
public string FirstName { get; set; }
[Display(Name = "名:")]
public string LastName { get; set; }
  }
然后在views文件夹里面添加一个Example0视图,视图的代码如下: 
 <form method="post"/>
<table cellpadding="5" cellspacing="0" width="50%">
<tr>
<td align="right" nowrap="nowrap" width="15%">
编号 :</td>
<td>
<input name="Id" type="text" /></td>
</tr>
<tr>
<td align="right" nowrap="nowrap" width="15%">
姓 :</td>
<td>
<input name="FirstName" type="text" /></td>
</tr>
<tr>
<td align="right" nowrap="nowrap" width="15%">名 :</td>
<td><input name="LastName" type="text"/></td>
</tr>
<tr>
<td align="left" colspan="2" nowrap="nowrap" width="15%">
<input id="Submit1" type="submit" value="提交" /></td>
</tr>
<tr>
<td align="left" colspan="2">
<strong>
@ViewBag.StatusMessage
</strong>
</td>
</tr>
</table>
 然后在Controllers文件夹里面新建一个HomeController,添加如下代码: 
        public ActionResult Example0()
{
Person p = new Person();
if (Request.Form.Count > 0)
{
p.Id = Request.Form["Id"];
p.FirstName = Request.Form["FirstName"];
p.LastName = Request.Form["LastName"];
TryUpdateModel(p);
ViewBag.StatusMessage = "欢迎您!" + p.FirstName + p.LastName + "您的编号是" + p.Id + "!";
}
return View();
}
 然后配置路由,使上面的Example0页面为起始项,运行并填入数据,结果为: 

点击提交按钮。显示如下结果:

 从Controller的代码来看,我们主要是使用Request.Form.Count 来判断是否接收到了值,然后再一一的遍历我们想要得到的值,最后也算得到了。下面让我们来看一下使用模型绑定的效果:

2.2使用模型绑定

然后在Views/Home文件夹添加一个Example2.cshtml。代码如下:
 <form method="post">
<table cellpadding="5" cellspacing="0" width="50%">
<tr>
<td align="right" nowrap="nowrap" width="15%">
编号 :</td>
<td>
<input name="Id" type="text" /></td>
</tr>
<tr>
<td align="right" nowrap="nowrap" width="15%">
姓 :</td>
<td>
<input name="FirstName" type="text" /></td>
</tr>
<tr>
<td align="right" nowrap="nowrap" width="15%">名 :</td>
<td><input name="LastName" type="text"/></td>
</tr>
<tr>
<td align="left" colspan="2" nowrap="nowrap" width="15%">
<input id="Submit1" type="submit" value="提交" /></td>
</tr>
<tr>
<td align="left" colspan="2">
<strong>
@ViewBag.StatusMessage
</strong>
</td>
</tr>
</table>
最后在HomeController添加两个方法:
        public ActionResult Example2()
{
return View();
} [HttpPost]
public ActionResult Example2(Person person)
{
ViewBag.StatusMessage = "欢迎您!" + person.FirstName + person.LastName + "您的编号是" + person.Id + "!";
return View();
}
使Example2作为起始项或输入指定的URL,然后在文本框里面输入内容,如下图

在Example2方法中设置断点,以观察person的属性值,然后点击按钮提交:

发现person的各个属性已经获得了url中传过来的值,如下图:

2.3模型绑定的效果

通过上面的两种方式的实现,都是将URL中的传递的数据包装成了对象,然后把model的信息显示到View上面,明显使用模型绑定会省去很多代码,特别是在有多个属性时,这种效果更加明显,但是要注意的是前台的标签的name要和我们的model的属性的名字要一致,否则无法完成绑定。

2.4模型绑定的延伸

在我们给出的模型绑定的概念中,是把URL的请求数据创建成.net对象都算是模型绑定,我们叫上面的函数参数是一个类,叫绑定到类。如果是单纯的把其绑定到基础类型,是不是也符合定义呢?那么就让我们来看看绑定到基础类型。

2.4.1绑定到基础类型

我们先看一个将http请求中的Id绑定到函数的string Id上。在HomeController中新建两个Index方法,其中带参数的加上 [HttpPost]标签,代码如下:
        public ActionResult index()
{
return View();
}
[HttpPost]
public ActionResult index(int id)
{
ViewBag.Info = "编号是" + id;
return View();
}
对应的Index视图的代码:
<form action="Index" method="post"/>
学号:<input name="id" id =”id” type="text"/>
<input id="Submit1" type="submit" value="提交" />
<strong>@ViewBag.Info</strong>
当直接点提交按钮后,发现程序报错,如图

从提示类看错误的原因是因为HttpPost的方法接受了一个为空值的Id,所以与int id不能匹配,解决的办法是使用默认值public ActionResult index(int id=0)
这样用的另外一个好处是,如果是View中的标签的name属性一不小心写错了,如把<input name="id1" id="id1" type="text"/>,那么该方法同样使用默认值,也就是说即使没有找到与之相匹配的key,也可以使用默认值,虽然没有到达预期的效果,但不至于报错。
提交按钮,会输出:编号是0. 

2.4.2绑定到类的指定属性

在绑定到类时,或许有的时间我们不想绑定id,那么我们就可以在方法的参数前加一个限制: 
public ActionResult Example2([Bind(Include="FirstName,LastName")]Person person)
其他代码不变,调试结果:

发现Id属性值为null,Include相对的还有一个Exclude,结果如下:
 

还有一招更狠的是,假设某个字段为预留字段,在所有的控制器的所有方法都不想被绑定,也防止有些恶意用户为我们预留字段添加数据,那么可以在model中的类前面加上
 [Bind(Exclude="ReservedProperty")]
public class Person {
以上的模型绑定都是使用了默认的绑定,除了上面的两种可以绑定到的类型,还可以绑定到各种类型,如字典,泛型,以及复杂类型(上一篇中的Address属性),在此不一一的列举。但是要记住是“属性名”要相一致。看到这里,估计你也很想知道,绑定的原理。那就让我们来看第三部分。 

三、把自定义的模型使用在指定的参数上

如果想学会一件事,最好的方法就是实践一下了,同样,为了弄清模型绑定的原理,我们就自定义一个模型绑定。之前我们提过,上面的模型绑定都是使用的默认绑定,那么我们肯定想知道一下,即使是默认的绑定,那么是怎么显示调用的?因为如果知道了显式的调用方式,那么自定义的就可以按照其调用方法调用了。下面让我们看一下显示使用默认模型绑定:

3.1显式使用默认模型绑定

在看显式使用默认绑定之前,我们先看一下默认绑定DefaultModelBinder,可以按F12,发现其实现了IModelBinder接口。该接口有一个方法:
 // 摘要:
// 使用指定的控制器上下文和绑定上下文将模型绑定到一个值。
//
// 参数:
// controllerContext:
// 控制器上下文。
//
// bindingContext:
// 绑定上下文。
//
// 返回结果:
// 绑定值。
object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext);
该方法的返回值即为绑定值。我们先不管那么多,先看一下显式的调用默认模型绑定看是怎么调用的。其实在每一个参数前多省略了一个[ModelBinder(typeof(DefaultModelBinder))],或者说使用了和他一样的效果。不相信的话,你可以把上面的代码放到参数类型的前面,像这样: 
public ActionResult Example2([ModelBinder(typeof(DefaultModelBinder))]Person person) 
运行结果,看看是不是和不使用的效果一样。

知道了显式的使用默认模型绑定,那么我们是不是可以自定义一个模型绑定也来实现一下呢?

3.2 使用自定义绑定

  和默认模型绑定一样,我们也来实现接口IModelBinder,然后实现其方法BindModel,从参数和返回值的说明来看,ModelBindingContext可能会有些陌生,先放一下,一会单独说明,回想一下模型绑定,就是使用URL请求数据来创建.net对象,想创建说明样的对象肯定是我们说了算,请求的参数来自ControllerContext,创建的对象来自于我们的心中,不过也就是返回值的类型了。
所以不影响我们自定义模型绑定,我现在想实现一个把接收到的请求数据转化成一个Person类,那么是不是就可以实现一个
简单的自定义绑定,为了区分默认的绑定类的效果还是自定义的效果,我在Person的Id属性前面加个S,还等什么呢,开始贴代码: 

public class CustomModelBinder:IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
Person person = new Person();
person.Id =”S”+controllerContext.HttpContext.Request["Id"].ToString();
person.FirstName = controllerContext.HttpContext.Request["FirstName"].ToString();
person.LastName = controllerContext.HttpContext.Request["LastName"].ToString();
return person;
}
}

为了使用自定义的类,我们就在views/Home中添加一个Example3然后在HomeController中添加如下代码:

public ActionResult Example3()
{
return View();
}

[HttpPost]
public ActionResult Example3([ModelBinder(typeof(CustomModelBinder))]Person person)//
{
ViewBag.StatusMessage = "欢迎您!" + person.FirstName + person.LastName + "您的编号是" + person.Id + "!";
return View();
}

然后把起始页改为Example3.运行,填入如下数据,点击提交按钮。

显示如下结果:

说明刚刚的自定义绑定已经起作用了,或许默认绑定的过程远比我们想想的复杂的多,但是至少通过一个自定义绑定,让我们从思想上有了简单的认识。最后我们来看一下上面提到有点陌生的那个类ModelBindingContext ,在自定义的绑定内部设断点,然后填如上面的数据,提交,来看一下bingContext对象,他的ModelName就是我们想要绑定的参数,所以称为绑定上下文。
其他的具体实现由于其原理比较复杂,不在此文说明。

四、参考文献

ASP.NET MVC Model之二模型绑定的更多相关文章

  1. ASP.NET MVC Model验证(二)

    ASP.NET MVC Model验证(二) 前言 上篇内容演示了一个简单的Model验证示例,然后在文中提及到Model验证在MVC框架中默认所处的位置在哪?本篇就是来解决这个问题的,并且会描述一下 ...

  2. ASP.NET MVC Model元数据(二)

    ASP.NET MVC Model元数据(二) 前言 在上篇中,给大家留个对Model元数据的印象,并没有对Model元数据有过多的讲解,而在本篇中也不会对Model元数据的本身来解释,而是针对于它的 ...

  3. ASP.NET MVC Model绑定(二)

    ASP.NET MVC Model绑定(二) 前言 上篇对于Model绑定的简单演示想必大家对Model绑定的使用方式有一点的了解,那大家有没有想过Model绑定器是在什么时候执行的?又或是执行的过程 ...

  4. 【ASP.NET MVC 学习笔记】- 16 Model Binding(模型绑定)

    本文参考:http://www.cnblogs.com/willick/p/3424188.html. 1.Model Binding是Http请求和Action方法之间的桥梁,是MVC框架根据Htt ...

  5. ASP.NET MVC Model绑定(四)

    ASP.NET MVC Model绑定(四) 前言 前面的篇幅对于Model绑定器IModelBinder以及实现类型.Model绑定器提供程序都作了粗略的讲解,可以把Model绑定器想象成一个大的容 ...

  6. ASP.NET MVC Model绑定(三)

    ASP.NET MVC Model绑定(三) 前言 看过前两篇的朋友想必对Model绑定有个大概的了解,然而MVC框架给我们提供了更高的可扩展性的提供程序编程模式,也就是本篇的主题了,会讲解一下Mod ...

  7. ASP.NET MVC Model绑定(一)

    ASP.NET MVC Model绑定(一) 前言 ModelMetadata系列的结束了,从本篇开始就进入Model绑定部分了,这个系列阅读过后你会对Model绑定有个比较清楚的了解, 本篇对于Mo ...

  8. ASP.NET MVC Model绑定

    ASP.NET MVC Model绑定(一) 前言 ModelMetadata系列的结束了,从本篇开始就进入Model绑定部分了,这个系列阅读过后你会对Model绑定有个比较清楚的了解, 本篇对于Mo ...

  9. ModelBinder——ASP.NET MVC Model绑定的核心

    ModelBinder——ASP.NET MVC Model绑定的核心 Model的绑定体现在从当前请求提取相应的数据绑定到目标Action方法的参数.通过前面的介绍我们知道Action方法的参数通过 ...

随机推荐

  1. B4. Concurrent JVM 锁机制(synchronized)

    [概述] JVM 通过 synchronized 关键字提供锁,用于在线程同步中保证线程安全. [synchronized 实现原理] synchronized 可以用于代码块或者方法中,产生同步代码 ...

  2. 安装composer及切换镜像为国内镜像

    一.下载composer php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" 下面的 ...

  3. 树莓派 -- 输入设备驱动 (key)

    输入设备(如按键,键盘,触摸屏等)是典型的字符设备,其一般工作原理是底层在按键或触摸等动作发生时产生一个中断,然后CPU通过SPI,I2C总线读取键值. 在这些工作中之后中断和读键值是与设备相关的,而 ...

  4. assert.throws()函数详解

    assert.throws(block[, error][, message]) Node.js FS模块方法速查 期望 block 函数抛出一个错误. 如果指定 error,它可以是一个构造函数.正 ...

  5. CODE【VS】 3160 最长公共子串 (后缀数组)

    3160 最长公共子串 题目描述 Description 给出两个由小写字母组成的字符串,求它们的最长公共子串的长度. 输入描述 Input Description 读入两个字符串 输出描述 Outp ...

  6. Apache Ambari 2.7.3.0 离线安装

    1. 准备 (内存 3G 硬盘 40G) 0)设置ssh无密码 ssh-keygencat id_rsa.pub >> authorized_keyschmod 700 ~/.sshchm ...

  7. 【Codeforces 1041D】Glider

    [链接] 我是链接,点我呀:) [题意] 题意 [题解] 二分. 枚举每一个上升区的起始位置作为起点(这样做肯定是最优的),然后如果没有掉在地上的话就尽量往右二分(只有上升区之间的间隙会让他往下掉) ...

  8. 【Codeforces 231C】To Add or Not to Add

    [链接] 我是链接,点我呀:) [题意] 题意 [题解] 把数组排个序, 显然优先用大的且小于枚举的数字a[i]的数字变成a[i] 那么肯定有一个范围j. 然后a[j~i-1]都能在k花费以内变成a[ ...

  9. HTML文件中css样式的引用

    1.1.直接在div中使用css样式制作div+css网页 如: <div style="font-size:14px; color:#FF0000;">内容</ ...

  10. TeamViewer & remote control

    TeamViewer remote control https://www.teamviewer.com/en/download/windows/ https://dl.tvcdn.de/downlo ...