Model Binding To A List
[文章来源see here]
Using the DefaultModelBinder in ASP.NET MVC, you can bind submitted form values to arguments of an action method. But what if that argument is a collection? Can you bind a posted form to an ICollection<T>?
Sure thing! It’s really easy if you’re posting a bunch of primitive types. For example, suppose you have the following action method.
public ActionResult UpdateInts(ICollection<int> ints) {
return View(ints);
}
You can bind to that by simply submitting a bunch of form fields each having the same name. For example, here’s an example of a form that would bind to this, assuming you keep each value a proper integer.
<form method="post" action="/Home/UpdateInts">
<input type="text" name="ints" value="1" />
<input type="text" name="ints" value="4" />
<input type="text" name="ints" value="2" />
<input type="text" name="ints" value="8" />
<input type="submit" />
</form>
If you were to take fiddler and look at what data actually gets posted when clicking the submit button, you’d see the following.
ints=1&ints=4&ints=2&ints=8
The default model binder sees all these name/value pairs with the same name and converts that to a collection with the key ints, which is then matched up with the ints parameter to your action method. Pretty simple!
Where it gets trickier is when you want to post a list of complex types. Suppose you have the following class and action method.
public class Book {
public string Title { get; set; }
public string Author { get; set; }
public DateTime DatePublished { get; set; }
}
//Action method on HomeController
public ActionResult UpdateProducts(ICollection<Book> books) {
return View(books);
}
You might think we could simply post the following to that action method:
Title=title+one&Author=author+one&DateTime=1/23/1975 &Title=author+two&Author=author+two&DateTime=6/6/2007…
Notice how we simply repeat each property of the book in the form post data? Unfortunately, that wouldn’t be a very robust approach. One reason is that we can’t distinguish from the fact that there may well be another Title input unrelated to our list of books which could throw off our binding.
Another reason is that the checkbox input does not submit a value if it isn’t checked. Most input fields, when left blank, will submit the field name with a blank value. With a checkbox, neither the name nor value is submitted if it’s unchecked! This again can throw off the ability of the model binder to match up submitted form values to the correct object in the list.
To bind complex objects, we need to provide an index for each item, rather than relying on the order of items. This ensures we can unambiguously match up the submitted properties with the correct object.
Here’s an example of a form that submits three books.
<form method="post" action="/Home/Create">
<input type="text" name="[0].Title" value="Curious George" />
<input type="text" name="[0].Author" value="H.A. Rey" />
<input type="text" name="[0].DatePublished" value="2/23/1973" />
<input type="text" name="[1].Title" value="Code Complete" />
<input type="text" name="[1].Author" value="Steve McConnell" />
<input type="text" name="[1].DatePublished" value="6/9/2004" />
<input type="text" name="[2].Title" value="The Two Towers" />
<input type="text" name="[2].Author" value="JRR Tolkien" />
<input type="text" name="[2].DatePublished" value="6/1/2005" />
<input type="submit" />
</form>
Note that the index must be an unbroken sequence of integers starting at 0 and increasing by 1 for each element.
The new expression based helpers in ASP.NET MVC 2 will produce the correct format within a for loop. Here’s an example of a view that outputs this format:
<%@ Page Inherits="ViewPage<IList<Book>>" %>
<% for (int i = 0; i < 3; i++) { %>
<%: Html.TextBoxFor(m => m[i].Title) %>
<%: Html.TextBoxFor(m => m[i].Author) %>
<%: Html.TextBoxFor(m => m[i].DatePublished) %>
<% } %>
It also works with our templated helpers. For example, we can take the part inside the for loop and put it in a Books.ascx editor template.
<%@ Control Inherits="ViewUserControl<Book>" %>
<%: Html.TextBoxFor(m => m.Title) %>
<%: Html.TextBoxFor(m => m.Author) %>
<%: Html.TextBoxFor(m => m.DatePublished) %>
Just add a folder named EditorTemplates within the Views/Shared folder and add Books.ascx to this folder.
Now change the original view to look like:
<%@ Page Inherits="ViewPage<IList<Book>>" %>
<% for (int i = 0; i < 3; i++) { %>
<%: Html.EditorFor(m => m[i]) %>
<% } %>
Non-Sequential Indices
Well that’s all great and all, but what happens when you can’t guarantee that the submitted values will maintain a sequential index? For example, suppose you want to allow deleting rows before submitting a list of books via JavaScript.
The good news is that by introducing an extra hidden input, you can allow for arbitrary indices. In the example below, we provide a hidden input with the.Index suffix for each item we need to bind to the list. The name of each of these hidden inputs are the same, so as described earlier, this will give the model binder a nice collection of indices to look for when binding to the list.
<form method="post" action="/Home/Create">
<input type="hidden" name="products.Index" value="cold" />
<input type="text" name="products[cold].Name" value="Beer" />
<input type="text" name="products[cold].Price" value="7.32" />
<input type="hidden" name="products.Index" value="123" />
<input type="text" name="products[123].Name" value="Chips" />
<input type="text" name="products[123].Price" value="2.23" />
<input type="hidden" name="products.Index" value="caliente" />
<input type="text" name="products[caliente].Name" value="Salsa" />
<input type="text" name="products[caliente].Price" value="1.23" />
<input type="submit" />
</form>
Unfortunately, we don’t have a helper for generating these hidden inputs. However, I’ve hacked together an extension method which can render this out for you.
When you’re creating a form to bind a list, add the following hidden input and it will add the appropriate hidden input to allow for a broken sequence of indices. Use at your own risk!I’ve only tested this in a couple of scenarios. I’ve included a sample project with multiple samples of binding to a list which includes the source code for this helper.
<%: Html.HiddenIndexerInputForModel() %>
This is something we may consider adding to a future version of ASP.NET MVC. In the meanwhile, give it a whirl and let us know how it works out for you.
Model Binding To A List的更多相关文章
- [ASP.NET MVC 小牛之路]15 - Model Binding
Model Binding(模型绑定)是 MVC 框架根据 HTTP 请求数据创建 .NET 对象的一个过程.我们之前所有示例中传递给 Action 方法参数的对象都是在 Model Binding ...
- Asp.net MVC使用Model Binding解除Session, Cookie等依赖
上篇文章"Asp.net MVC使用Filter解除Session, Cookie等依赖"介绍了如何使用Filter来解除对于Session, Cookie的依赖.其实这个也可以通 ...
- [ASP.NET MVC] Model Binding With NameValueCollectionValueProvider
[ASP.NET MVC] Model Binding With NameValueCollectionValueProvider 范例下载 范例程序代码:点此下载 问题情景 一般Web网站,都是以H ...
- ASP.NET MVC3 Dynamically added form fields model binding
Adding new Item to a list of items, inline is a very nice feature you can provide to your user. Thi ...
- 【ASP.NET MVC 学习笔记】- 16 Model Binding(模型绑定)
本文参考:http://www.cnblogs.com/willick/p/3424188.html. 1.Model Binding是Http请求和Action方法之间的桥梁,是MVC框架根据Htt ...
- .NET Core开发日志——Model Binding
ASP.NET Core MVC中所提供的Model Binding功能简单但实用,其主要目的是将请求中包含的数据映射到action的方法参数中.这样就避免了开发者像在Web Forms时代那样需要从 ...
- 运用模型绑定和web窗体显示和检索数据(Retrieving and displaying data with model binding and web forms)
原文 http://www.asp.net/web-forms/overview/presenting-and-managing-data/model-binding/retrieving-data ...
- [置顶] ASP.NET MVC - Model Binding
Http Request 到Input Model的绑定按照model的类型可分为四种情况. Primitive type Collection of primitive type Complex t ...
- MVC3 Model Binding验证方式
1.使用ModelState在Action中进行验证 [HttpPost] public ViewResult MakeBooking(Appointment appt) { if (string.I ...
随机推荐
- sscanf()函数的用法
来自:http://blog.csdn.net/tigerjibo/article/details/6442151 sscanf 名称: sscanf() - 从一个字符串中读进与指定格式相符的数据. ...
- ASP.NET WebAPI从入门
在新出的MVC4中,增加了WebAPI,用于提供REST风格的WebService,新生成的WebAPI项目和典型的MVC项目一样,包含主要的Models.Views.Controllers等文件夹和 ...
- 【Cocos得知】技术要点通常的积累
1.粒子特效 CCParticleSystem*sp = CCParticleSnow::create(); sp->setTexture(CCTextureCache::sharedTextu ...
- NYoj The partial sum problem(简单深搜+优化)
题目链接:http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=927 代码: #include <stdio.h> #include & ...
- MIFARE系列6《射频卡与读写器的通信》
1. ATR(Answer to request) 读写器呼叫磁场内的卡片.卡片对呼叫做出应答. 对刚进入磁场得到电复位处于休闲状态的卡片,卡请求(REQA,0x26):对于已进行过读写操作并进入休眠 ...
- 从头开始学JavaScript (五)——操作符(二)
原文:从头开始学JavaScript (五)--操作符(二) 一.乘性操作符 1.乘法:* 乘法操作符的一些特殊规则: 如果操作数都是数值,按照常规的乘法计算,如果乘积超过了ECMAscri ...
- CSharp设计模式读书笔记(13):代理模式(学习难度:★★★☆☆,使用频率:★★★★☆)
代理模式:给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问. 模式角色与结构: 示例代码: using System; using System.Collections.Generi ...
- 安全系列之二:OAuth2.0 开放授权协议
本文提取出OAuth2.0规范RFC6749的主要内容,部分内容从文档复制出来,给大家讲讲第三方授权背后的故事. 先是举个知乎的QQ登录授权的例子,然后讲四种授权方式,两种令牌,接着是看看协议流程,分 ...
- 经典Loading 动漫赏析
0. 传统的菊花Loading动画 假设作为程序猿的你还在用菊花作为Loading动画,是时候换个口味了.来看下5种不错的Loading动画. 几种颜色组成的动画,给用户一个美感. 1.android ...
- MySQL编程(0) - Mysql中文乱码问题解决方案
MySQL 5.6 for Windows 解压缩版配置安装: http://jingyan.baidu.com/article/f3ad7d0ffc061a09c3345bf0.html MySQL ...