MVC学习系列-表单数据提交

在Asp.Net MVC项目中,View负责页面展示、收集数据,展示的数据是从Controller的Action中获取,将收集的数据提交到Controller的Action。这里的数据,可能是基础类型,或者是Model,或者是Model的部分内容,或者是集合比如List或Dictionary。

据从View传递到Controller的Action时,有以下几种方式,

1.RouteData(url中的路由数据),

2.QueryString(http get的查询参数如?page=2),

3.Forms(表单post的数据),

4.或者ajax交互的json数据。

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

下面就列举了获取View传递的数据的几种方式

方法1.

public ActionResult Create()
{
    Recipe recipe = new Recipe();
    recipe.Name = Request.Form["Name"];
    // ...
   return View();
}
方法2.
public ActionResult Create(FormCollectionvalues)
{
    Recipe recipe = new Recipe();
    recipe.Name = values["Name"];       
    // ...
   return View();
}
方法3.

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

1. 简单类型

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

<pre name="code" class="csharp"><pre name="code" class="csharp">public class Book
    {
        public int BookId { get; set; }
        public string BookName { get; set; }
        public string Author { get; set; }
        public DateTime PublishedDate { get; set; }
    }

public ActionResult Create(Book book) {
            //TO DO
            //Insert book into Database
            return RedirectToAction("Index");
        }



对应的View页面代码如下:

<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中加上变量名称前缀的情形:
<pre name="code" class="html"><pre name="code" class="html"><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>


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; }
    }

相应的View页面的代码如下所示:

<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>

3. 集合类型

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

<span style="font-size:12px;">public class Book
    {
        public int BookId { get; set; }
        public string BookName { get; set; }
        public string Author { get; set; }
        public DateTime PublishedDate { get; set; }
    }</span><span style="font-size: 14px;">
</span>

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

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>类型

public ActionResult Create(IDictionary<string, Book> books) {
            //TO DO
            //Insert book into Database
            return RedirectToAction("Index");
        }
相应的View页面的代码如下:

<pre name="code" class="html"><pre name="code" class="html"><pre name="code" class="html"><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 就可以轻松实现各种类型的自动绑定了。 

5.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 并在页面作出提示。
参考:https://msdn.microsoft.com/zh-cn/library/system.web.mvc.controller_methods(v=vs.118).aspx


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。