ASP.NET MVC Model之二模型綁定
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之二模型綁定