模型绑定
一.认识模型绑定
类时介绍了一下:将浏览器请求映射到数据对象。
这句话刚看上去不大明白意思,还是用自己的话总结一下:
模型绑定实际上是:
服务器端代码利用用户在表单中输入的数据(或其它HTTP请求携带的数据),来构造动作方法所需要的参数对象的过程。数据的流向是从客户端的HTML表单到服务器端动作方法。
二.使用默认模型绑定
1)绑定简单类型
打开VS,新建一个空模板的MVC 3项目如下:
namespace MvcModelBind.Models { public class Sheep { private string _name = "No name!"; public string Name { get { return _name; } set { _name = value; } } } }
在Controllers文件夹下添加一个控制器,如下:
public ActionResult ModelBindSheep(Sheep sheep) { return View(sheep); }
F6编译项目,为上面的方法新建一个强类型视图,如下:
@model MvcModelBind.Models.Sheep @{ ViewBag.Title = "ModelBindSheep"; } <h2>ModelBinding示例:绑定Sheep对象的Name属性</h2> @using (Html.BeginForm("ModelBindSheep", "Sheep")) { @:小羊的名字:@Html.TextBoxFor(n => n.Name, new { style = "background-color:#FF83FA" })<br /> @:目前小羊的名字是:@Model.Name <br /> <input type="submit" name="btn" value="提交" /> }
运行查看网页:注意将网址改成对应的:/控制器名/action名:
2)绑定复合类型
a)绑定复合类型简单示例
上面绑定的仅仅是一个string型的属性Name,接下来绑定一个复杂类型AdditionalInformation AddInfo
namespace MvcModelBind.Models { public class AdditionalInformation { public string Country { get; set; } public string City { get; set; } } }
public class Sheep { private string _name = "No name!"; public string Name { get { return _name; } set { _name = value; } } public AdditionalInformation AddInfo { get; set; } }
更改ModelBindSheep方法对应的视图代码为:
@model MvcModelBind.Models.Sheep @{ ViewBag.Title = "ModelBindSheep"; } <h2>ModelBinding示例:绑定Sheep对象的Name属性</h2> @using (Html.BeginForm("ModelBindSheep", "Sheep")) { @:小羊的名字:@Html.TextBoxFor(n => n.Name, new { style = "background-color:#FF83FA" })<br /> @:目前小羊的名字是:@Model.Name <br /> @:小羊所在国家: @Html.EditorFor(c=>c.AddInfo.Country) <br /> @:小羊所在的城市: @Html.EditorFor(c=>c.AddInfo.City) <br /> <input type="submit" name="btn" value="提交" /> }
运行查看网页,对应的国家及城市Html源码:
小羊所在国家: <input class="text-box single-line" id="AddInfo_Country" name="AddInfo.Country" type="text" value="" /> <br /> 小羊所在的城市: <input class="text-box single-line" id="AddInfo_City" name="AddInfo.City" type="text" value="" /> <br />
可以看到name属性是模型Sheep类的AddInfo属性名+对应的AdditionalInformation类的Country/City属性名组合而成。
b)指定自定义前缀
@model MvcModelBind.Models.Sheep
我在视图代码中增加另一个Sheep实例:
@using MvcModelBind.Models; @model MvcModelBind.Models.Sheep @{ Sheep anotherSheep = new Sheep { Name = "Tom", AddInfo = new AdditionalInformation { Country = "America", City = "sanfrancisco" } }; } @{ ViewBag.Title = "ModelBindSheep"; } <h2>ModelBinding示例:绑定Sheep对象的Name属性</h2> @using (Html.BeginForm("ModelBindSheep", "Sheep")) { @:这是当前小羊的名字: @Html.EditorFor(a=>a.Name) <br /> @:这是当前小羊的国家: @Html.EditorFor(a=>a.AddInfo.Country) <br /> @:这是当前小羊的城市: @Html.EditorFor(a=>a.AddInfo.City) <p >--------------------------------------------------------</p> @:这是额外小羊的名字: @Html.EditorFor(a=>anotherSheep.Name) <br /> @:这是额外小羊的国家: @Html.EditorFor(a=>anotherSheep.AddInfo.Country) <br /> @:这是额外小羊的城市: @Html.EditorFor(a=>anotherSheep.AddInfo.City) <br /> <input type="submit" name="btn" value="提交" /> }
编译运行,无论我如何修改虚线下面的三个TextBox的值,点击提交按钮后这三个TextBox始终是显示:
public ActionResult ModelBindSheep(Sheep sheep,Sheep sheep1) { return View(sheep); }
编译运行,还是和上面一样,无论我如何修改虚线下面的三个TextBox的值,点击提交按钮后这三个TextBox始终是恢复上图的样子。
其实模型绑定器在查找sheep1对应的参数值时,会去查找name为sheep1.Name/AddInfo.Country/AddInfo.City的数据源,发现压根就找不到,所以点击提交按钮后,虚线下面的三个TextBox又恢复原值。
<p >--------------------------------------------------------</p> 这是额外小羊的名字: <input class="text-box single-line" id="anotherSheep_Name" name="anotherSheep.Name" type="text" value="Tom" /> <br /> 这是额外小羊的国家: <input class="text-box single-line" id="anotherSheep_AddInfo_Country" name="anotherSheep.AddInfo.Country" type="text" value="America" /> <br /> 这是额外小羊的城市: <input class="text-box single-line" id="anotherSheep_AddInfo_City" name="anotherSheep.AddInfo.City" type="text" value="sanfrancisco" /> <br />
可见,这些name都有一个前缀:anotherSheep,这是我在视图中定义的额外Sheep类的实例名。
public ActionResult ModelBindSheep(Sheep sheep, Sheep anotherSheep) { return View(sheep); }
这时候,编译运行,修改这三个TextBox值,提交页面,会发现值都会随之变化了;
public ActionResult ModelBindSheep(Sheep sheep,[Bind(Prefix="anotherSheep")] Sheep sheep1) { return View(sheep); }
该方式是利用Bind注解属性来告诉模型绑定器找数据源时,应该找数据源name以什么来开头的。
c)绑定或不绑定某些属性
假如我不想绑定Sheep中的Name属性,只想绑定AddInfo属性,但是我前台页面又有对应的Name数据源,因为绑定器会自动找到并绑定它。
public ActionResult ModelBindSheep([Bind(Include="AddInfo")] Sheep sheep) { return View(sheep); }
或:
public ActionResult ModelBindSheep([Bind(Exclude="Name")] Sheep sheep) { return View(sheep); }
或者在类定义上使用:
[Bind(Exclude = "Name")] public class Sheep { private string _name = "No name!"; public string Name { get { return _name; } set { _name = value; } } public AdditionalInformation AddInfo { get; set; } }
或:
[Bind(Include = "AddInfo")] public class Sheep { private string _name = "No name!"; public string Name { get { return _name; } set { _name = value; } } public AdditionalInformation AddInfo { get; set; } }
但是一个需要注意的是:如果在类定义上使用了:
[Bind(Exclude = "Name")]
又在动作方法参数上使用了:
[Bind(Include="Name")]
那么,这个Name属性仍然是不会被绑定的!
3)绑定到集合
上面的示例均是绑定的单独对象,即使使用额外对象也是屈指可数,实际应用中可能会要求绑定几十到几百个对象。
@using MvcModelBind.Models; @model List<MvcModelBind.Models.Sheep> @{ ViewBag.Title = "ModelBindSheep"; int i = 0; } <h2>绑定到集合</h2> @using (Html.BeginForm("ModelBindSheep", "Sheep")) { for ( i = 0; i < Model.Count; i++) { @:第 @(i+1) 只羊的名字: @Html.EditorFor(n=>n[i].Name) <br /> @:第 @(i+1) 只羊的国家: @Html.EditorFor(n=>n[i].AddInfo.Country) <br /> @:第 @(i+1) 只羊的城市: @Html.EditorFor(n=>n[i].AddInfo.City) <br /> <p>----------------------------------------------------</p> } <input type="submit" name="btn" value="提交" /> }
对应的方法修改为:
public ActionResult ModelBindSheep(List<Sheep> sheeps) { if (sheeps==null) { sheeps = new List<Sheep>() { new Sheep { Name="Tom" , AddInfo=new AdditionalInformation{Country="China",City="ShangHai"}}, new Sheep { Name="Jack" , AddInfo=new AdditionalInformation{Country="America",City="sanfrancisco"}}, new Sheep { Name="Jerry" , AddInfo=new AdditionalInformation{Country="France",City="London"}}, }; } return View(sheeps); }
编译运行:
<form action="/Sheep/ModelBindSheep" method="post"> 第 1 只羊的名字: <input class="text-box single-line" name="[0].Name" type="text" value="Tom" /> <br /> 第 1 只羊的国家: <input class="text-box single-line" name="[0].AddInfo.Country" type="text" value="China" /> <br /> 第 1 只羊的城市: <input class="text-box single-line" name="[0].AddInfo.City" type="text" value="ShangHai" /> <br /> <p>----------------------------------------------------</p> 第 2 只羊的名字: <input class="text-box single-line" name="[1].Name" type="text" value="Jack" /> <br /> 第 2 只羊的国家: <input class="text-box single-line" name="[1].AddInfo.Country" type="text" value="America" /> <br /> 第 2 只羊的城市: <input class="text-box single-line" name="[1].AddInfo.City" type="text" value="sanfrancisco" /> <br /> <p>----------------------------------------------------</p> 第 3 只羊的名字: <input class="text-box single-line" name="[2].Name" type="text" value="Jerry" /> <br /> 第 3 只羊的国家: <input class="text-box single-line" name="[2].AddInfo.Country" type="text" value="France" /> <br /> 第 3 只羊的城市: <input class="text-box single-line" name="[2].AddInfo.City" type="text" value="London" /> <br /> <p>----------------------------------------------------</p> <input type="submit" name="btn" value="提交" /> </form>
修改对应TextBox的值,提交表单后,可以看到值都随之变化,说明绑定成功!
4)绑定非数字索引的集合
这里借助于隐藏Input元素,作为指定数据的的键,只要将表单中的视图代码修改为:
@using (Html.BeginForm("ModelBindSheep", "Sheep")) { <input type="hidden" name="index" value="firstSheep" /> @:第 @(i+1) 只羊的名字: @Html.Editor("[firstSheep].Name") <br /> @:第 @(i+1) 只羊的国家: @Html.Editor("[firstSheep].AddInfo.Country") <br /> @:第 @(++i) 只羊的城市: @Html.Editor("[firstSheep].AddInfo.City") <br /> <p>----------------------------------------------------</p> <input type="hidden" name="index" value="secondSheep" /> @:第 @(i+1) 只羊的名字: @Html.Editor("[secondSheep].Name") <br /> @:第 @(i+1) 只羊的国家: @Html.Editor("[secondSheep].AddInfo.Country") <br /> @:第 @(++i) 只羊的城市: @Html.Editor("[secondSheep].AddInfo.City") <br /> <p>----------------------------------------------------</p> <input type="hidden" name="index" value="thirdSheep" /> @:第 @(i+1) 只羊的名字: @Html.Editor("[thirdSheep].Name") <br /> @:第 @(i+1) 只羊的国家: @Html.Editor("[thirdSheep].AddInfo.Country") <br /> @:第 @(i+1) 只羊的城市: @Html.Editor("[thirdSheep].AddInfo.City") <br /> <input type="submit" name="btn" value="提交" /> }
即可;
5)绑定到字典
@using MvcModelBind.Models; @model Dictionary<string,MvcModelBind.Models.Sheep> @{ ViewBag.Title = "ModelBindSheep"; int i = 0; } <h2>绑定到字典</h2> @using (Html.BeginForm("ModelBindSheep", "Sheep")) { <input type="hidden" name="[0].key" value="firstSheep" /> @:第 @(i+1) 只羊的名字: @Html.Editor("[0].value.Name") <br /> @:第 @(i+1) 只羊的国家: @Html.Editor("[0].value.AddInfo.Country") <br /> @:第 @(++i) 只羊的城市: @Html.Editor("[0].value.AddInfo.City") <p>----------------------------------------------------</p> <input type="hidden" name="[1].key" value="secondSheep" /> @:第 @(i+1) 只羊的名字: @Html.Editor("[1].value.Name") <br /> @:第 @(i+1) 只羊的国家: @Html.Editor("[1].value.AddInfo.Country") <br /> @:第 @(++i) 只羊的城市: @Html.Editor("[1].value.AddInfo.City") <p>----------------------------------------------------</p> <input type="hidden" name="[2].key" value="thirdSheep" /> @:第 @(i+1) 只羊的名字: @Html.Editor("[2].value.Name") <br /> @:第 @(i+1) 只羊的国家: @Html.Editor("[2].value.AddInfo.Country") <br /> @:第 @(++i) 只羊的城市: @Html.Editor("[2].value.AddInfo.City") <br /> <input type="submit" name="btn" value="提交" /> }
对应的方法修改为:
public ActionResult ModelBindSheep(Dictionary<string,Sheep> sheeps) { if (sheeps == null) { sheeps = new Dictionary<string, Sheep>(); sheeps.Add("firstSheep", new Sheep { Name="Tom" , AddInfo=new AdditionalInformation{Country="China",City="ShangHai"}}); sheeps.Add("secondSheep", new Sheep { Name = "Jack", AddInfo = new AdditionalInformation { Country = "America", City = "sanfrancisco" }}); sheeps.Add("thirdSheep", new Sheep { Name = "Jerry", AddInfo = new AdditionalInformation { Country = "France", City = "London" }}); } return View(sheeps); }
编译运行,修改TextBox的值,点击提交按钮,同样是可以实现绑定的!