【转自】: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. 修改mac host

    /etc/hosts 把host 复制到桌面  修改  然后  替换原来的

  2. IOS开发之UI布局

    前言:本篇随笔会经常更新,随着本人对布局的深入学习,会不断补充新的知识.新的使用技巧.新的认识等等. 1.Autoresizing(在代码中使用) 先简单的看看下面的代码,以及左边运行出来的效果,然后 ...

  3. IOS之UI--动态设置NavigationBar的颜色以及透明度

    前言:有时候我们需要设置UINavigationController的导航条NavigationBar的颜色为透明度,这时候就需要使用到NavigationBar的barStyle这个属性: 再看QQ ...

  4. 跨域iframe的高度自适应

    If you cannot hear the sound of the genuine in you, you will all of your life spend your days on the ...

  5. javascript和web debug技术

    在前端开发中,调试技术是必不可少的技能,本文将介绍五种前端开发必备的调试技术. Weinre移动调试 DOM 断点 debugger断点 native方法hook 远程映射本地调试 Weinre 在移 ...

  6. TypeId和IidManager关系

    IidInformation结构 数据类型 名字 string name TypeId::hash_t hash uint16_t parent string groupName size_t siz ...

  7. python里面出现中文的时候报错 'ascii' codec can't encode characters in position

    编码问题,在头部添加 import sys reload(sys) sys.setdefaultencoding( "utf-8" ) http://www.xuebuyuan.c ...

  8. .Net中使用aliases让相同命名空间的dll引用共存

    有些不得已的时候,我们需要同时在代码中使用某个dll的不同版本.比如用低版本的dll中的方法导出数据,然后使用高版本的方法导入数据来实现数据的升级. 又或者需要同时使用第三方的dll不同版本.如何使它 ...

  9. ASP.NET features need application service database support

    搭建的web程序出现如上图所示的错误 原因程序使用以下ASP.NET 特性 Membership (the SqlMembershipProvider class). Role management ...

  10. ORA-00030: User session ID does not exist.

    同事在Toad里面执行SQL语句时,突然无线网络中断了,让我检查一下具体情况,如下所示(有些信息,用xxx替换,因为是在处理那些历史归档数据,使用的一个特殊用户,所以可以用下面SQL找到对应的会话信息 ...