【转自】: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. iOS从info.plist获取项目的名称及版本号

    NSString *executableFile = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundl ...

  2. android加固系列—4.加固前先学会破解,无源码调试apk

    [版权所有,转载请注明出处.出处:http://www.cnblogs.com/joey-hua/p/5138585.html] 项目关键java代码为,将tv设置为从jni读取的字符串,这里的破解内 ...

  3. iOS 多线程 浅述

    什么是进程? 进程是指在系统中正在运行的一个应用程序. 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内. 什么是线程? 1个进程要想执行任务,必须得有线程(每1个进程至少要有1条线程 ...

  4. App开发流程之使用GCD

    GCD即为Grand Central Dispatch的缩写,是一种主要用于异步处理任务的安全的高性能解决方案. 在此不对比其他异步处理技术,只记录GCD的使用及说明. 先记录一些必要的概念:线程,同 ...

  5. 【代码笔记】iOS-提醒时间的选择

    一,效果图. 二,工程图. 三,代码. RootViewController.h #import <UIKit/UIKit.h> @interface RootViewController ...

  6. Content-Type: application/vnd.ms-excel">

    如果要将查询结果导出到Excel,只需将页面的Context-Type修改一下就可以了:   header( "Content-Type: application/vnd.ms-excel& ...

  7. mac 终端 常用指令

    开始正式研究ios 应用开发,由于是从C开始学起,所以学习下常用的mac终端指令,方便后续常用操作. mac 终端 常用指令: 1.ls指令 用途:列出文件 常用参数 -w 以简洁的形式列出所有文件和 ...

  8. 使用windows服务更新站点地图

    由于公司平台访问人数逐渐增多,公司项目的数据库已经几次出现宕机现象.为减轻数据库压力,我上个月对公司项目做了下调整.把新闻板块提取出来单独一个站点,单独一个数据库.减少了主站点和数据库的负担和压力. ...

  9. 谈谈用ASP.NET开发的大型网站有哪些架构方式(成本)

    在上篇文章里(http://www.cnblogs.com/ms0017/archive/2011/07/26/2117676.html),列举了国内外用ASP.NET开发的大型网站有哪些.最后提到了 ...

  10. PHP isset() 检测变量是否设置

    isset() 用于检测变量是否设置. isset() PHP isset() 用于检测一个或多个变量是否设置,如果被检测的变量存在则返回 TRUE,否则返回 FALSE. 语法: 1 bool is ...