【转自】:http://www.cnblogs.com/dengdl/archive/2011/07/14/2106849.html

在做Asp.Net MVC项目中,都知道View负责页面展示数据或者提供页面收集数据,而所展示的数据或者收集的数据都是从Controller的Action中获取或提交到Controller的Action。

这里的数据,可能是基础类型,或者是Model,或者是Model的部分内容,或者是集合比如List或Dictionary。

数据从View传递到Controller的Action时,有几种方式,RouteData(url中的路由数据),QueryString(http get的查询参数如?page=2),Forms(表单post的数据), 或者ajax交互的json数据。

而在Controller的action中,常常希望获得这些View传递的数据,并且最好能绑定到Action希望的类型,这些类型可能是Action的基础类型参数,或者需要更新的Model,或者只更新Model的部分内容,或者是一些集合的结构如List或Dictionary。

古董方法:

[AcceptVerbs(HttpVerbs.Post)]

publicActionResultCreate()

{

Reciperecipe = newRecipe();

recipe.Name = Request.Form["Name"];

// ...

returnView();

}

前进一步:

publicActionResultCreate(FormCollectionvalues)

{

Reciperecipe = newRecipe();

recipe.Name = values["Name"];

// ...

returnView();

}

神奇的DefaultModelBinder:

Asp.Net Mvc内建功能(DefaultModelBinder)可以实现简单类型、复杂类型、集合类型,以及字典类型的自动绑定。

1. 简单类型

这里,我们将下面这个Book类称为简单类型:

public class Book
    {
        public int BookId { get; set; }
        public string BookName { get; set; }
        public string Author { get; set; }
        public DateTime PublishedDate { get; set; }
    }

假设现在需要实现添加Book的功能,那么在BookController中,会定义如下的Action:

[AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Create(Book book) {
            //TO DO
            //Insert book into Database
            return RedirectToAction("Index");
        }

现在的问题便是,在View中如何命名TextBox来达到自动绑定,如下:

<div>
        <%using (Html.BeginForm("Create", "Book")) { %>
        <div>
            Book Name: <%=Html.TextBox("BookName")%>
        </div>
        <div>
            Author: <%=Html.TextBox("Author")%>
        </div>
        <div>
            Published Date: <%=Html.TextBox("PublishedDate")%>
        </div>
        <div>
            <input type="submit" id="submit" name="submit" value="submit" />
        </div>
        <%} %>
    </div>

注意TextBox的name必须是对应绑定类型的PropertyName(不区分大小写)。 这样,页面表单submit后,我们便可以在BookController的“Create” Action中得到自动绑定的book对象。这里,Asp.Net Mvc还支持在TextBox的name中加上变量名称前缀的情形:

<div>
        <%using (Html.BeginForm("Create", "Book")) { %>
        <div>
            Book Name: <%=Html.TextBox("book.BookName")%>
        </div>
        <div>
            Author: <%=Html.TextBox("book.Author")%>
        </div>
        <div>
            Published Date: <%=Html.TextBox("book.PublishedDate")%>
        </div>
        <div>
            <input type="submit" id="submit" name="submit" value="submit" />
        </div>
        <%} %>
    </div>

需要注意的是:
1)前缀"book"必须与Action中接收的Book参数名一致
2)如果加了前缀,那么所有的都要加

2. 复杂类型

现在对Book类作些许改动,并引入Author类:

public class Book
    {
        public int BookId { get; set; }
        public string BookName { get; set; }
        public Author Author { get; set; }
        public DateTime PublishedDate { get; set; }
    }

public class Author {
        public int AuthorId { get; set; }
        public string AuthorName { get; set; }
        public string Nation { get; set; }
    }

这里,将改动后的Book类称为复杂类。这时,Book类多了一个对Author类的引用。现在,保持BookController中的"Create" Action不变,来看View中的TextBox改如何命名以实现Book类型的自动绑定:

<div>
        <%using (Html.BeginForm("Create", "Book")) { %>
        <div>
            Book Name: <%=Html.TextBox("BookName")%>
        </div>
        <div>
            Published Date: <%=Html.TextBox("PublishedDate")%>
        </div>
        <div>
            Author's Name: <%=Html.TextBox("Author.AuthorName")%>
        </div>
        <div>
            Author's Nation: <%=Html.TextBox("Author.Nation")%>
        </div>
        <div>
            <input type="submit" id="submit" name="submit" value="submit" />
        </div>
        <%} %>
    </div>

OK,测试通过,想必你也知道命名规则了,要绑定Book类型中的Author类型,必须加上"Author."的前缀。
如果你喜欢,你还可以在所有TextBox名称前面再加"book."的前缀。

3. 集合类型

为避免问题复杂化,我们用回原来的简单Book类型:

public class Book
    {
        public int BookId { get; set; }
        public string BookName { get; set; }
        public string Author { get; set; }
        public DateTime PublishedDate { get; set; }
    }

现在,把BookController的"Create" Action改为接收IList<Book>的参数:

[AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Create(IList<Book> books) {
            //TO DO
            //Insert book into Database
            return RedirectToAction("Index");
        }

然后,在View中运用以下命名规则,以自动绑定IList<book>类型,

<div>
        <%using (Html.BeginForm("Create", "Book")) { %>
        <div>
            Book Name: <%=Html.TextBox("books[0].BookName")%>
        </div>
        <div>
            Published Date: <%=Html.TextBox("books[0].PublishedDate")%>
        </div>
        <div>
            Author's Name: <%=Html.TextBox("books[0].Author")%>
        </div>
        <div>
            Book Name: <%=Html.TextBox("books[1].BookName")%>
        </div>
        <div>
            Published Date: <%=Html.TextBox("books[1].PublishedDate")%>
        </div>
        <div>
            Author's Name: <%=Html.TextBox("books[1].Author")%>
        </div>
        <div>
            <input type="submit" id="submit" name="submit" value="submit" />
        </div>
        <%} %>
    </div>

可以看到如下规则:Action的变量名"books"加上中括号和索引作为前缀,索引必须从0开始,并且必须连续。
通过此命名规则,可以绑定任意集合类型:IList<Book>, ICollection<Book>, IEnumerable<Book>, List<Book>, Book[]等。

4. 字典类型

仍以简单Book类型为例,现在将"Create" Action改为接收IDictionary<Book>类型,

[AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Create(IDictionary<string, Book> books) {
            //TO DO
            //Insert book into Database
            return RedirectToAction("Index");
        }

相应的,View中的命名如下:

<div>
        <%using (Html.BeginForm("Create", "Book")) { %>
        <div>
            Book SN: <%=Html.TextBox("books[0].Key") %>
        </div>
        <div>
            Book Name: <%=Html.TextBox("books[0].Value.BookName")%>
        </div>
        <div>
            Published Date: <%=Html.TextBox("books[0].Value.PublishedDate")%>
        </div>
        <div>
            Author's Name: <%=Html.TextBox("books[0].Value.Author")%>
        </div>
        <div>
            Book SN: <%=Html.TextBox("books[1].Key") %>
        </div>
        <div>
            Book Name: <%=Html.TextBox("books[1].Value.BookName")%>
        </div>
        <div>
            Published Date: <%=Html.TextBox("books[1].Value.PublishedDate")%>
        </div>
        <div>
            Author's Name: <%=Html.TextBox("books[1].Value.Author")%>
        </div>
        <div>
            <input type="submit" id="submit" name="submit" value="submit" />
        </div>
        <%} %>
    </div>

可以看出,对于IDictioinary<Book>类型,在命名规则上,相比于集合类型,多了"Key"和"Value”的字眼。另,此规则也适用于Action参数类型为Dictionary<Book>的情形。

简单类型、复杂类型、集合类型,以及字典类型 还能混合着用,而且绑定的数据来源也不局限于Form提交的表达数据,还可以是RouteData(url中的路由数据),QueryString(http get的查询参数如?page=2),或者ajax交互的json数据。

所以,只要我们遵循一定的命名规则,灵活的运用DefaultModelBinder 就可以轻松实现各种类型的自动绑定了。

BindAttribute:

DefaultModelBinder 已经很强大了,而在有些时候BindAttribute则会为你锦上添花。

BindAttribute中有三个重要的成员:string Exclude, string Include, string Prefix。
"Exclude"用于指定要排除的Property,"Include"用于指定包含在内的Property,"Prefix"用于指定前缀。

看个例子,

Book类:

Create Action:

对应的View:

先说,"Prefix"吧,默认情况下,DefaultModelBinder可以自动识别以Action的参数名命名的前缀,也就是说,在上述View中,给每个TextBox的名称都加一个"book“前缀,不需要在做任何改动,在Action中仍可得到Book的实例。

加上前缀”book"的View:

这时,如果我们加的前缀不是"book",那么就需要BindAttribute的协助了,
假设,我们加上一个"b"的前缀:

那么,为了在Action中得到相应的Book实例,需要在Action的Book参数上应用BindAttribute:

现在来看"Exclude"和"Include",其实这两个东西一次应用一个就可以了。现在我希望Binding的时候将"BookName"和"Author"都排除(当然,这里这样做没什么意义)。出于简化问题的考虑,View去掉TextBox名称的前缀:

然后,将Action改为:

默认情况下,多个Property用逗号隔开。

BindAttribute出了可以应用在Action的参数上外,还可以应用在Model类定义中:

如果在Model类定义中,和在Action的参数上都应用了BindAttribute,那么则会取两者的交集。个人认为,还是应尽量避免它们打架为妙。

所以,BindAttribute 对于前缀的使用及部分Model的绑定很有用。

TryUpdateModel/UpdateModel

Mvc中经常遇到的一个典型用例是View通过From或者Ajax提交数据更新相应的Model,或者更新Model的部分内容,并且需要检查提交的数据对于Model的数据约束是否有效。

这个时候TryUpdateModel就有用武之地了,它可以设置需要更新模型属性列表的(白名单)或要排除属性的列表(黑名单) 先看更新相关模型的所有属性:

publicActionResult Edit(int id, FormCollection collection)

{

var oldData = _r.GetSingleData(id);

if(TryUpdateModel(oldData, collection.AllKeys))

{

_r.Save();

}

}

更新除ID,Name外的Model属性:

publicActionResult Edit(Guid id, FormCollection collection)

{

var oldData = _r.GetSingleData(id);

if(TryUpdateModel(oldData,"", collection.AllKeys,newstring[]{"ID","Name"}))

{

_r.Save();

}

}

publicActionResult Save()

{

Customer customer =newCustomer();

try   {

UpdateModel(customer,new[] {"Name","Email",

"Phone","Deposit"});

return RedirectToAction("...");

}

catch(InvalidOperationException)

{

returnView(customer);

}

}

UpdateModel 和TryUpdateModel 有许多重载形式以供多种灵活的运用,而且它还将自动检查模型绑定数据是否有错误,如果有错误将自动添加到ModelState 并在页面作出提示。真是个好用的宝贝。

自定义ModelBinder

这是一个终极BOSS,由你自己亲手打造,一般来说,如果前面的武器不能解决的,都可以使用这个干掉,当然一般问题前面的方法都可以解决。

要想修炼custom model binder, 自己google.

参考:

http://blog.csdn.net/aspgreener/article/details/4986190

http://blog.csdn.net/aspgreener/article/details/4986379

http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx

http://odetocode.com/blogs/scott/archive/2009/04/27/6-tips-for-asp-net-mvc-model-binding.aspx

http://demo.tc/Post/655

http://msdn.microsoft.com/zh-cn/library/system.web.mvc.controller.tryupdatemodel.aspx

http://davidhayden.com/blog/dave/archive/2008/09/08/ASPNETMVCUpdateModelTryUpdateModelDataBinding.aspx

http://www.joe-stevens.com/2010/02/17/asp-net-mvc-using-controller-updatemodel-when-using-a-viewmodel/

http://kb.cnblogs.com/page/69750/

http://www.cnblogs.com/ldp615/archive/2010/07/30/SensitiveWordsFilterModelBinder.html

 
分类: C#
 
好文要顶 已关注 收藏该文  

MVC 表单提交【转】的更多相关文章

  1. [Spring MVC] - 表单提交

    Spring MVC自带的表单标签比较简单,很多时候需要借助EL和JSTL来完成. 下面是一个比较简单的表单提交页面功能: 1.User model package com.my.controller ...

  2. asp.net mvc表单提交的几种方式

    asp.net MVC中form提交和控制器接受form提交过来的数据 MVC中form提交和在控制器中怎样接受 1.cshtml页面form提交2.控制器处理表单提交数据4种方式方法1:使用传统的R ...

  3. Asp.Net Mvc表单提交(批量提交)

    Asp.Net Mvc中Action的参数可以自动接收和反序列化form表单的值, 采用form表单提交 name=value类型,只要Action参数的变量名和input的name相同就行 html ...

  4. ASP.NET MVC 表单提交多层子级实体集合数据到控制器中

    于遇到了项目中实体类嵌套多层子级实体集合,并且子级实体集合的数据需要提交保存到数据库中的问题.针对此情况需要进行一些特殊的处理才可以将整个 实体类及子级实体集合数据提交表单到控制器中,解决的方法是根据 ...

  5. Spring MVC表单提交

    实际应用中,列表中的单条记录的修改,可能需要传很多对象参数到后台服务器,Spring MVC表单标签<form:> 提供了一种简洁的提交方式. <form id="form ...

  6. ASP.NET\ASP.NET MVC表单提交遇到的问题结论

    同步提交的两种基本方式 1,用type=“submit”按钮.form没有必要runat=“server” <form method="post" action=" ...

  7. Asp.Net Mvc表单提交之List集合

    一.说明 1.Asp.Net Mvc中Action的参数可以自动接收和反序列化form表单的值, 2.对于name=value类型,只要Action参数的变量名和input的name相同就行,不区分大 ...

  8. MVC表单提交写法1

    初学MVC,感觉跟以前的aspx页面差别很大,我们就先来看看MVC的表单是怎么提交的吧. 现在我们用一个最简单的例子来看一看MVC是怎么提交表单的(这一个例子中,我们的关注点是如何提交表单,所以不涉及 ...

  9. MVC 表单提交

    用户提交表单 写法一(推荐) 一,不带参数 <body> <!--一下写法生成:<form action="/Home/Index" method=&quo ...

随机推荐

  1. 在android用Get方式发送http请求

    烦人的日子终于过去啦,终于又可以写博客啦,对自己的android学习做个总结,方便以后查看...... 一.在android用Get方式发送http请求,使用的是java标准类,也比较简单. 主要分以 ...

  2. nginx反向代理配置及优化

    nginx反向代理配置及优化前言: 由于服务器apache抗不住目前的并发.加上前端squid配置后,问题依然无法解决.而页面程序大部分是动态.无法使用fastcgi来处理.因此想使用nginx做为反 ...

  3. 【代码笔记】iOS-将图片处理成圆的

    一,效果图. 二,工程图. 三,代码. ViewController.m - (void)viewDidLoad { [super viewDidLoad]; // Do any additional ...

  4. iOS_UITableView性能优化那些事

    UITableView在实际开发中使用频率实在是很高, 因此, UITableView的性能优化是必不可少的, 本文下面就略微总结一下UITableView性能优化那些事. 本文着重介绍具体方法, 原 ...

  5. 转:能和LoadRunner匹敌的VS2010/2012Web负载测试

    原文出处:http://www.cnblogs.com/aarond/archive/2013/04/18/performance.html VS自带的Web负载测试真的很大程度上能和专业的loadr ...

  6. symfony2 controller

    1.基本概念 一次http请求    输入(Request):header信息.get信息.post数据等 输出(Response):symfony经过处理返回的信息,包括页面.json字符串.URL ...

  7. 软工_个人项目反(shai)思(zhao)

    这次作业成绩还算不错,但是也收获了很多的经验与教训,在这里总结一下. 需要继续改进的地方 作业提交方面仍旧有些问题.如助教所说,在GitHub中并没有保存已经编译好的exe文件,导致助教在检查作业的时 ...

  8. 在VC环境下执行代码出现错误

    这是在执行代码过程中出现的错误,源代码在别的电脑上能运行,在自己的VC里运行就出现错误,在网上也搜过解决办法,但还是有点不太理解,是编程环境的问题h还是代码本身也存在问题???

  9. go sync.Mutex 设计思想与演化过程 (一)

    go语言在云计算时代将会如日中天,还抱着.NET不放的人将会被淘汰.学习go语言和.NET完全不一样,它有非常简单的runtime 和 类库.最好的办法就是将整个源代码读一遍,这是我见过最简洁的系统类 ...

  10. 数据表格,查询、导出共用一个form表单,实现文件流方式下载

    在开发中遇到问题是这样的: 在维护老的管理系统的过程中,老板说让加导出功能:项目中,查询的筛选条件是用的表单提交的方式写的. 解决方案有两种: 一.用ajax方式导出 var array = $('# ...