zoukankan      html  css  js  c++  java
  • MVC 表单提交【转】

    在做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.

  • 相关阅读:
    dotnet core 获取 MacAddress 地址方法
    dotnet core 获取 MacAddress 地址方法
    dotnet core 发布只带必要的依赖文件
    dotnet core 发布只带必要的依赖文件
    Developing Universal Windows Apps 开发UWA应用 问答
    Developing Universal Windows Apps 开发UWA应用 问答
    cmd 如何跨驱动器移动文件夹
    cmd 如何跨驱动器移动文件夹
    C++ 驱动开发 error LNK2019
    C++ 驱动开发 error LNK2019
  • 原文地址:https://www.cnblogs.com/sjqq/p/7506343.html
Copyright © 2011-2022 走看看