1. 程式人生 > >ASP.NET MVC Model之二模型綁定

ASP.NET MVC Model之二模型綁定

數據包 set count 效果 模型 shtml 獲得 tex turn

Asp.net mvc中的模型綁定,或許大家經常用,但是具體說他是怎麽一回事,可能還是會有些陌生,那麽,本文就帶你理解模型綁定。為了理解模型綁定,本文會先給出其定義,然後對通過比,來得出使用模型綁定的方便。最後簡單的模擬一下自定義模型綁定,讓大家對模型綁定有進一步的認識。

一、模型綁定的概念


mvc framework中有一種技術,他就是模型綁定:
使用 被瀏覽器發送的http請求裏面數據 來創建.net對象的過程。接下來就讓我們來看看模型綁定的好處。

二、模型綁定好處

第二部分,我們通過不使用模型綁定和使用模型綁定的兩種效果的對比,得出模型綁定的優勢。那麽接下來先讓我們來模擬一個沒有模型綁定的環境。

2.1沒有模型綁定的環境

  讓我們先來模擬一個沒有模型綁定的環境,主要是讓用戶填寫的信息傳達到Controller中,然後經過加工後顯示到View上(通常情況下我們是得到model後直接把model作為一個模型實體,提交到數據庫了,為了簡單起見,我只是把得到的模型信息顯示出來)。先利用vs2010新建一個mvc3項目,在models文件夾中新建一個Person類,代碼如下:

技術分享

技術分享
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;
    public class Person
    {
        [Display(Name="編號")]
        public String Id { get; set; }
        [Display(Name = "姓:")]
        public string FirstName { get; set; }
        [Display(Name = "名:")]
        public string LastName { get; set; }
  }
技術分享

然後在views文件夾裏面添加一個Example0視圖,視圖的代碼如下:
技術分享 技術分享
 <form method="post"/>
    <table cellpadding="5" cellspacing="0" width="50%">
        <tr>
            <td align="right" nowrap="nowrap" width="15%">
                編號 :</td>
            <td>
        <input name="Id" type="text" /></td>
        </tr>
        <tr>
            <td align="right" nowrap="nowrap" width="15%">
                姓 :</td>
         <td>
        <input name="FirstName" type="text" /></td>
        </tr>
        <tr>
            <td align="right" nowrap="nowrap" width="15%">名 :</td>
            <td><input name="LastName" type="text"/></td>
        </tr>
        <tr>
            <td align="left" colspan="2" nowrap="nowrap" width="15%">
        <input id="Submit1" type="submit" value="提交" /></td>
        </tr>
        <tr>
            <td align="left" colspan="2">
            <strong>
            @ViewBag.StatusMessage
            </strong>
            </td>
        </tr>
    </table>
技術分享
 然後在Controllers文件夾裏面新建一個HomeController,添加如下代碼: 
技術分享 技術分享
        public ActionResult Example0()
        {
            Person p = new Person();
            if (Request.Form.Count > 0)
            {
                p.Id = Request.Form["Id"];
                p.FirstName = Request.Form["FirstName"];
                p.LastName = Request.Form["LastName"];
                TryUpdateModel(p);
                ViewBag.StatusMessage = "歡迎您!" + p.FirstName + p.LastName + "您的編號是" + p.Id + "!";
            }
            return View();
        }
技術分享
 然後配置路由,使上面的Example0頁面為起始項,運行並填入數據,結果為: 

技術分享

點擊提交按鈕。顯示如下結果:

技術分享

 從Controller的代碼來看,我們主要是使用Request.Form.Count 來判斷是否接收到了值,然後再一一的遍歷我們想要得到的值,最後也算得到了。下面讓我們來看一下使用模型綁定的效果:

2.2使用模型綁定

然後在Views/Home文件夾添加一個Example2.cshtml。代碼如下:
技術分享 技術分享
 <form method="post">
    <table cellpadding="5" cellspacing="0" width="50%">
        <tr>
            <td align="right" nowrap="nowrap" width="15%">
                編號 :</td>
            <td>
        <input name="Id" type="text" /></td>
        </tr>
        <tr>
            <td align="right" nowrap="nowrap" width="15%">
                姓 :</td>
         <td>
        <input name="FirstName" type="text" /></td>
        </tr>
        <tr>
            <td align="right" nowrap="nowrap" width="15%">名 :</td>
            <td><input name="LastName" type="text"/></td>
        </tr>
        <tr>
            <td align="left" colspan="2" nowrap="nowrap" width="15%">
        <input id="Submit1" type="submit" value="提交" /></td>
        </tr>
        <tr>
            <td align="left" colspan="2">
            <strong>
            @ViewBag.StatusMessage
            </strong>
            </td>
        </tr>
    </table>
技術分享
最後在HomeController添加兩個方法:
技術分享 技術分享
        public ActionResult Example2()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Example2(Person person)
        {
            ViewBag.StatusMessage = "歡迎您!" + person.FirstName + person.LastName + "您的編號是" + person.Id + "!";
            return View();
        }
技術分享
使Example2作為起始項或輸入指定的URL,然後在文本框裏面輸入內容,如下圖

技術分享

在Example2方法中設置斷點,以觀察person的屬性值,然後點擊按鈕提交:

技術分享

發現person的各個屬性已經獲得了url中傳過來的值,如下圖:

技術分享

2.3模型綁定的效果

通過上面的兩種方式的實現,都是將URL中的傳遞的數據包裝成了對象,然後把model的信息顯示到View上面,明顯使用模型綁定會省去很多代碼,特別是在有多個屬性時,這種效果更加明顯,但是要註意的是前臺的標簽的name要和我們的model的屬性的名字要一致,否則無法完成綁定。


2.4模型綁定的延伸

在我們給出的模型綁定的概念中,是把URL的請求數據創建成.net對象都算是模型綁定,我們叫上面的函數參數是一個類,叫綁定到類。如果是單純的把其綁定到基礎類型,是不是也符合定義呢?那麽就讓我們來看看綁定到基礎類型。

2.4.1綁定到基礎類型

我們先看一個將http請求中的Id綁定到函數的string Id上。在HomeController中新建兩個Index方法,其中帶參數的加上 [HttpPost]標簽,代碼如下:
技術分享 技術分享
        public ActionResult index()
        {
            return View();
        }
        [HttpPost]
        public ActionResult index(int id)
        {
            ViewBag.Info = "編號是" + id;
            return View();
        }
技術分享
對應的Index視圖的代碼:
技術分享
<form action="Index" method="post"/>
學號:<input name="id" id =”id” type="text"/>
<input id="Submit1" type="submit" value="提交" />
<strong>@ViewBag.Info</strong>
當直接點提交按鈕後,發現程序報錯,如圖

技術分享

從提示類看錯誤的原因是因為HttpPost的方法接受了一個為空值的Id,所以與int id不能匹配,解決的辦法是使用默認值public ActionResult index(int id=0)
這樣用的另外一個好處是,如果是View中的標簽的name屬性一不小心寫錯了,如把<input name="id1" id="id1" type="text"/>,那麽該方法同樣使用默認值,也就是說即使沒有找到與之相匹配的key,也可以使用默認值,雖然沒有到達預期的效果,但不至於報錯。
提交按鈕,會輸出:編號是0.

2.4.2綁定到類的指定屬性

在綁定到類時,或許有的時間我們不想綁定id,那麽我們就可以在方法的參數前加一個限制: 
public ActionResult Example2([Bind(Include="FirstName,LastName")]Person person)
其他代碼不變,調試結果:

技術分享

發現Id屬性值為null,Include相對的還有一個Exclude,結果如下:
 

技術分享


還有一招更狠的是,假設某個字段為預留字段,在所有的控制器的所有方法都不想被綁定,也防止有些惡意用戶為我們預留字段添加數據,那麽可以在model中的類前面加上
 [Bind(Exclude="ReservedProperty")]
public class Person {
以上的模型綁定都是使用了默認的綁定,除了上面的兩種可以綁定到的類型,還可以綁定到各種類型,如字典,泛型,以及復雜類型(上一篇中的Address屬性),在此不一一的列舉。但是要記住是“屬性名”要相一致。看到這裏,估計你也很想知道,綁定的原理。那就讓我們來看第三部分。 

三、把自定義的模型使用在指定的參數上

如果想學會一件事,最好的方法就是實踐一下了,同樣,為了弄清模型綁定的原理,我們就自定義一個模型綁定。之前我們提過,上面的模型綁定都是使用的默認綁定,那麽我們肯定想知道一下,即使是默認的綁定,那麽是怎麽顯示調用的?因為如果知道了顯式的調用方式,那麽自定義的就可以按照其調用方法調用了。下面讓我們看一下顯示使用默認模型綁定:

3.1顯式使用默認模型綁定

在看顯式使用默認綁定之前,我們先看一下默認綁定DefaultModelBinder,可以按F12,發現其實現了IModelBinder接口。該接口有一個方法:
技術分享
 // 摘要:
        //     使用指定的控制器上下文和綁定上下文將模型綁定到一個值。
        //
        // 參數:
        //   controllerContext:
        //     控制器上下文。
        //
        //   bindingContext:
        //     綁定上下文。
        //
        // 返回結果:
        //     綁定值。
        object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext);
技術分享
該方法的返回值即為綁定值。我們先不管那麽多,先看一下顯式的調用默認模型綁定看是怎麽調用的。其實在每一個參數前多省略了一個[ModelBinder(typeof(DefaultModelBinder))],或者說使用了和他一樣的效果。不相信的話,你可以把上面的代碼放到參數類型的前面,像這樣: 
public ActionResult Example2([ModelBinder(typeof(DefaultModelBinder))]Person person) 
運行結果,看看是不是和不使用的效果一樣。

技術分享

知道了顯式的使用默認模型綁定,那麽我們是不是可以自定義一個模型綁定也來實現一下呢?

3.2 使用自定義綁定

  和默認模型綁定一樣,我們也來實現接口IModelBinder,然後實現其方法BindModel,從參數和返回值的說明來看,ModelBindingContext可能會有些陌生,先放一下,一會單獨說明,回想一下模型綁定,就是使用URL請求數據來創建.net對象,想創建說明樣的對象肯定是我們說了算,請求的參數來自ControllerContext,創建的對象來自於我們的心中,不過也就是返回值的類型了。
所以不影響我們自定義模型綁定,我現在想實現一個把接收到的請求數據轉化成一個Person類,那麽是不是就可以實現一個
簡單的自定義綁定,為了區分默認的綁定類的效果還是自定義的效果,我在Person的Id屬性前面加個S,還等什麽呢,開始貼代碼:

public class CustomModelBinder:IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
Person person = new Person();
person.Id =”S”+controllerContext.HttpContext.Request["Id"].ToString();
person.FirstName = controllerContext.HttpContext.Request["FirstName"].ToString();
person.LastName = controllerContext.HttpContext.Request["LastName"].ToString();
return person;
}
}

為了使用自定義的類,我們就在views/Home中添加一個Example3然後在HomeController中添加如下代碼:

public ActionResult Example3()
{
return View();
}

[HttpPost]
public ActionResult Example3([ModelBinder(typeof(CustomModelBinder))]Person person)//
{
ViewBag.StatusMessage = "歡迎您!" + person.FirstName + person.LastName + "您的編號是" + person.Id + "!";
return View();
}

然後把起始頁改為Example3.運行,填入如下數據,點擊提交按鈕。

技術分享

顯示如下結果:

技術分享

說明剛剛的自定義綁定已經起作用了,或許默認綁定的過程遠比我們想想的復雜的多,但是至少通過一個自定義綁定,讓我們從思想上有了簡單的認識。最後我們來看一下上面提到有點陌生的那個類ModelBindingContext ,在自定義的綁定內部設斷點,然後填如上面的數據,提交,來看一下bingContext對象,他的ModelName就是我們想要綁定的參數,所以稱為綁定上下文。
其他的具體實現由於其原理比較復雜,不在此文說明。

技術分享

四、參考文獻

ASP.NET MVC Model之二模型綁定