这篇文章我们来讲讲模型绑定(Model Binding),其实在初步了解ASP.NET MVC之后,大家可能都会产生一个疑问,为什么URL片段最后会转换为例如int型或者其他类型的参数呢?这里就不得不说模型绑定了。模型绑定是指,用浏览器以HTTP请求方式发送的数据来创建.NET对象的过程。每当定义具有参数的动作方法时,一直是在依赖着这种模型绑定过程。

准备项目

我们先来创建一个MVC项目,名叫MVCModels,并在Models文件夹中创建一个新的类文件Person。

 using System;

 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 Role Role { get; set; }
} public class Address
{
public string Line { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
} public enum Role
{
Admin,
User,
Guest
}
}

另外定义一个Home控制器。

 using MVCModels.Models;
using System.Linq;
using System.Web.Mvc; namespace MVCModels.Controllers
{
public class HomeController : Controller
{
private Person[] personDate = {
new Person { PersonId = , FirstName = "Adam", LastName = "Freeman", Role = Role.Admin },
new Person { PersonId = , FirstName = "Jacqui", LastName = "Griffyth", Role = Role.User },
new Person { PersonId = , FirstName = "John", LastName = "Smith", Role = Role.Guest },
};
public ActionResult Index(int id)
{
Person dataItem = personDate.Where(p => p.PersonId == id).First();
return View(dataItem);
}
}
}

接下来再创建一个视图文件Index。

@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>Role:</label>
@Html.DisplayFor(m => m.Role)
</div>

理解模型绑定

模型绑定是HTTP请求与C#方法之间的一个桥梁,它根据 Action 方法中的 Model 类型创建 .NET 对象,并将 HTTP 请求数据经过转换赋给该对象。当我们启动项目,并导航到/Home/Index/1,我们会看见图下:

当我们请求 /Home/Index/1 URL 时,路由系统便将最后一个片段值 1 赋给了 id 变量。action invoker 通过路由信息知道当前的请求需要 Index action 方法来处理,但它调用 Index action 方法之前必须先拿到该方法参数的值。 默认的动作调用器ControllerActionInvoker,要依靠模型绑定器来生成调用动作所需要的的数据对象,模型绑定器由IModelBinder接口所定义。在本例中,动作调用器会检查Index方法,并发现它具有一个int型参数,于是会查找负责int值绑定的绑定器,并调用它的BindModel方法。

使用默认模型绑定器

虽然应用程序可以自定义模型绑定器,但是大多数情况下还是依靠内建的绑定器类DefaultModelBinder。当动作调用器找不到绑定某个类型的自定义绑定器时,就会使用这个默认的模型绑定器,默认情况下,这个模型绑定器会搜索四个位置。如下表所示:

DefaultModelBinder类查找参数数据的顺序
描述
Request.From 由用户在HTML的表单元素中提供值
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类,讲请求数据获得的字符参数值转换为参数类型,如果无法转换,那么DefaultModelBinder便不能绑定到Model。比如访问/Home/Index/apple,便会出现如图所示:

默认模型绑定器看到需要的是int值,如果视图将URL中提供的apple值转换为int型,就会出错,此时我们可以修改代码,为参数提供一个默认值,这样当默认绑定器无法转换时也不会出错了。

 ...
public ActionResult Index(int id = )
{
Person dataItem = personDate.Where(p => p.PersonId == id).First();
return View(dataItem);
}

绑定复杂类型

当动作方法参数是符合类型时(即不能用TypeConverter类进行转换的属性),DefaultModelBinder类将用反射类获取public属性集。好的,我们现在来修改代码。

 using MVCModels.Models;
using System.Linq;
using System.Web.Mvc; namespace MVCModels.Controllers
{
public class HomeController : Controller
{
private Person[] personDate = {
new Person { PersonId = , FirstName = "Adam", LastName = "Freeman", Role = Role.Admin },
new Person { PersonId = , FirstName = "Jacqui", LastName = "Griffyth", Role = Role.User },
new Person { PersonId = , FirstName = "John", LastName = "Smith", Role = Role.Guest },
};
public ActionResult Index(int id = )
{
Person dataItem = personDate.Where(p => p.PersonId == id).First();
return View(dataItem);
}
public ActionResult CreatePerson()
{
return View(new Person());
}
[HttpPost]
public ActionResult CreatePerson(Person model)
{
return View("Index", model);
}
}
}

另外创建一个CreatePerson视图。

 @model MVCModels.Models.Person
@{
ViewBag.Title = "CreatePerson";
Layout = "~/Views/Shared/_Layout.cshtml";
} <h2>CreatePerson</h2>
@using (Html.BeginForm())
{
<div>
<label>
@Html.LabelFor(m => m.PersonId)
@Html.EditorFor(m => m.PersonId)
</label>
</div>
<div>
<label>
@Html.LabelFor(m => m.FirstName)
@Html.EditorFor(m => m.FirstName)
</label>
</div>
<div>
<label>
@Html.LabelFor(m => m.LastName)
@Html.EditorFor(m => m.LastName)
</label>
</div>
<div>
<label>
@Html.LabelFor(m => m.Role)
@Html.EditorFor(m => m.Role)
</label>
</div>
<button type="submit">Submit</button>
}

在表单回递给CreatePerson方法时,默认绑定器发现动作方法需要一个Person对象,便会依次处理每个属性。绑定器会从请求中找到每一个值。如果一个属性需要另一个复合类型时,那么该过程会重复执行。例如本例中,Person类的HomeAddress属性是Address类型,在为Line属性查找值时,模型绑定器查找的是HomeAddress.Line的值,即模型对象的属性名(HomeAddress)与属性类型(Address)的属性名(Line)的组合。

Bind特性

我们还可以用bind特性为 Address 类型的参数绑定 Person 对象中的 HomeAddress 属性值,例如这样:

 public ActionResult DisplayAddress([Bind(Prefix="HomeAddress")]Address address)
{
return View(address);
}

DisplayAddress action 方法的参数类型 Address 不一定必须是 Person 的 HomeAddress 属性的类型,它可以是其他类型,只要该类型中含有City

或 Country 同名的属性就都会被绑定到。不过,要注意的是,使用 Bind 特性指定了前缀后,需要提交的表单元素的 name 属性必须有该前缀才能被绑定。Bind 特性还有两个属性,Exclude 和 Include。它们可以指定在 Mdoel 的属性中,Binder 不查找或只查找某个属性,即在查找时要么只包含这个属性要么不包含这个属性。如下面的 action 方法:

 public ActionResult DisplayAddress([Bind(Prefix = "HomeAddress", Exclude = "Country")]Address address)
{
return View(address);
}

这时 Binder 在绑定时不会对 Address 这个 Model 的 Country 属性绑定值。

ASP.NET MVC——模型绑定的更多相关文章

  1. ASP.NET MVC模型绑定的6个建议(转载)

    ASP.NET MVC模型绑定的6个建议 发表于2011-08-03 10:25| 来源博客园| 31 条评论| 作者冠军 validationasp.netmvc.netasp 摘要:ASP.NET ...

  2. ASP.NET没有魔法——ASP.NET MVC 模型绑定

    在My Blog中已经有了文章管理功能,可以发布和修改文章,但是对于文章内容来说,这里缺少最重要的排版功能,如果没有排版的博客很大程度上是无法阅读的,由于文章是通过浏览器查看的,所以文章的排版其实与网 ...

  3. ASP.NET没有魔法——ASP.NET MVC 模型绑定解析(下篇)

    上一篇<ASP.NET没有魔法——ASP.NET MVC 模型绑定解析(上篇)>文章介绍了ASP.NET MVC模型绑定的相关组件和概念,本章将介绍Controller在执行时是如何通过这 ...

  4. asp.net Mvc 模型绑定项目过多会导致页面运行时间卡

    asp.net Mvc 模型绑定项目过多会导致页面运行时间卡的问题. 解决方式就是采用ModelView方式进行精简,已减少模型绑定及验证的时间.

  5. [转] ASP.NET MVC 模型绑定的功能和问题

    摘要:本文将与你深入探究 ASP.NET MVC 模型绑定子系统的核心部分,展示模型绑定框架的每一层并提供扩展模型绑定逻辑以满足应用程序需求的各种方法. 同时,你还会看到一些经常被忽视的模型绑定技术, ...

  6. ASP.NET没有魔法——ASP.NET MVC 模型绑定解析(上篇)

    前面文章介绍了ASP.NET MVC中的模型绑定和验证功能,本着ASP.NET MVC没有魔法的精神,本章内容将从代码的角度对ASP.NET MVC如何完成模型的绑定和验证进行分析,已了解其原理. 本 ...

  7. ASP.NET MVC模型绑定1

    一.模型绑定原理 模型绑定是指为Controller的Action方法的参数提供值的过程,例如我有一个名为Blog的实体类(准确的说是ViewModel),它有一个名为Title的属性,如果我在VIE ...

  8. ASP.NET MVC 模型绑定

    模型绑定指的是MVC从浏览器发送的HTTP请求中为我们创建.NET对象,在HTTP请求和C#间起着桥梁的作用.模型绑定的一个最简单的例子是带参数的控制器action方法,比如我们注册这样的路径映射: ...

  9. 禁止ASP.NET MVC模型绑定时将空字符串绑定为null

    为model添加[DisplayFormat(ConvertEmptyStringToNull = false)] [Display(ResourceType = typeof(AppStrings) ...

随机推荐

  1. SQLSERVER走起微信公众帐号全新改版 全新首页

    SQLSERVER走起微信公众帐号全新改版 全新首页 今天,SQLSERVER走起微信公众帐号增加了首页功能 虽然还是订阅号,不过已经对版面做了比较大的修改,希望各位亲用得放心.用得安心O(∩_∩)O ...

  2. Microservice架构模式简介

    在2014年,Sam Newman,Martin Fowler在ThoughtWorks的一位同事,出版了一本新书<Building Microservices>.该书描述了如何按照Mic ...

  3. 三分钟学会用 js + css3 打造酷炫3D相册

    之前发过该文,后来不知怎么回事不见了,现在重新发一下. 中秋主题的3D旋转相册 如图,这是通过Javascript和css3来实现的.整个案例只有不到80行代码,我希望通过这个案例,让正处于迷茫期的j ...

  4. iOS的ATS配置 - 2017年前ATS规定的适配

    苹果规定 从2017年1月1日起,新提交的 app 不允许使用NSAllowsArbitraryLoads来绕过ATS(全称:App Transport Security)的限制. 以前为了能兼容ht ...

  5. Go web开发初探

    2017年的第一篇博客,也是第一次写博客,写的不好,请各位见谅. 本人之前一直学习java.java web,最近开始学习Go语言,所以也想了解一下Go语言中web的开发方式以及运行机制. 在< ...

  6. Sass之坑Compass编译报错

    前段时间在使用Compass时遇到了其为难处理的一个坑,现记录到博客希望能帮助到各位. 一.问题: 利用Koala或者是gulp编译提示如下,截图为koala编译提示错误: 二.解决办法 从问题截图上 ...

  7. win10系统下连接无线网络掉线问题解决办法

    打开驱动精灵----系统诊断 找一个可修复的驱动点击 选择连不上网中的查看更多 有连不上网络,网络连接受限,解决无线间歇性掉网问题 进入计算机管理----设备管理 修改无线网络属性(名称含有wirel ...

  8. ReactNative入门(安卓)——API(下)

    LayoutAnimation - layout动画 当布局发生改变时的动画模块,它有两个方法: 1. 最常用的方法是 LayoutAnimation.configureNext(conf<Ob ...

  9. Java中的Checked Exception——美丽世界中潜藏的恶魔?

    在使用Java编写应用的时候,我们常常需要通过第三方类库来帮助我们完成所需要的功能.有时候这些类库所提供的很多API都通过throws声明了它们所可能抛出的异常.但是在查看这些API的文档时,我们却没 ...

  10. 2016年我们重新思考移动互联网创业的风险, 微信还是APP?

    感觉这两年前端开发又火起来了,很多做内容创业和做微电商创业的人,往往都选择了运营微信号.对于做纯技术开发的人来说,一般是看不上微信号的,感觉没什么技术含量,或者说没什么技术壁垒.也有另一批人观点相反的 ...