ModelBinder
我們在利用asp.net mvc做些服務端操作時,例如增刪改等,很多時候都需要和資料庫打交道,要想把資料提交給資料庫,第一個條件就是擷取頁面的表單值。在傳統的asp.net中,擷取值是非常容易的,因為很多都是些伺服器端控制項,而asp.net mvc中擷取值並不是靠伺服器控制項的屬性來擷取。我們來看一下使用者新增一則留言的處理方式,當然這裡為了簡單,只是讓使用者輸入標題和內容,其它的略過。
第一:建立新增留言的partial view,有點類似asp.net中的使用者控制項。
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<GuestBook.Common
.Models.GuestBookInfo>" %>
<script language ="javascript" type ="text/javascript" src ="http://www.cnblogs.com/Scripts/jquery-1.3.2.min.js"></script>
<script language ="javascript" type ="text/javascript" >
function check() {
var IsOK = false;
var err = "";
if (jQuery.trim($("#sTitle").val()) == "") {
err += "請輸入留言標題\n";
}
if (jQuery.trim($("#sContent").val()) == "") {
err += "請輸入留言內容\n";
}
if (err != "") {
alert(err);
return false;
}
return true;
}
</script>
<% using (Html.BeginForm())
{%>
<fieldset>
<p>
<label for="Title">
標題:</label>
<%= Html.TextBox("sTitle", Model.sTitle)%>
</p>
<p>
<label for="EventDate">
內容:</label>
<%=Html.TextBox("sContent", Model.sContent)%>
</p>
<p>
<input type="submit" onclick ="return check();" value="Save" />
</p>
</fieldset>
<% }
%>
第二:Controller類的修改。
說明:下面的部分代碼可以會讓大家迷惑,ViewData["flag"]是啥東西,其實這是我為了儲存一個操作處理結果,因為提交留言後往往會轉向到另外的View中,例如留言列表頁,這時在使用者提交操作後,應該反饋給使用者執行的結果(成功還是失敗),這裡有兩種情況:
(1):提交後View不切換,則利用ViewData["flag"]就可以完成,在頁面中判斷ViewData["flag"]是否存在,如果存在則根據對應的值顯示不同的提示。
(2):提交後View切換,例如轉到Index.aspx中,此時ViewData就不能勝任了,我只能給GuestBookInfo的基類Message屬性賦值,在index.aspx頁面判斷Message的值,分別做出對應處理。這時有兩種方法:
1>:利用return View("Index", models);這種方法頁面的地址並不會發生變化,當然頁面內容會變化。
2>:return RedirectToAction("Index");這種方法連結和內容都會變化。這是比第一種方法好的地方。
問題: index中的Model由於是一個記錄集,為了實現如上的提示功能,不得不給每個記錄對象的Message賦值,如果不這樣做,在View中很難知道哪一個對象的Message屬性是我們賦的值。不知道大家在面臨這種問題時都是如何處理的,請多多指教。
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(GuestBookInfo model)
{
try
{
inter.Add(model);
var models = inter.FindAllInfo();
ViewData["flag"] = 1;
//model.Message = "已經成功建立";
foreach (var i in models)
{
i.Message = "已經成功建立";
}
return View("Index", models);
//return RedirectToAction("Index");
}
catch(Exception ex)
{
ModelState.AddModelError("ex",ex);
return View(model);
}
}
留言列表頁的View部分代碼:(提示部分),這裡取記錄集第一個對象的Message值。
<% =Html.MessageBox (Model.First ())%>
在上面代碼中代碼中,並沒有顯示的給出model賦值,但實際上程式運行時,會自動把表單的相關值賦給對象。這點看起來特別神奇,MVC 為我們提供了一個自動化的操作,這一切都歸功於IModelBinder 介面,系統預設會找它DefaultModelBinder來完成這一神聖的任務。DefaultModelBinder 內部通過大量的反射完成最終的賦值操作,基本上能適應開發所需。至於如何?大家可以到網上去搜尋下資料,既然有預設的,我們也可以自訂ModelBinder。
1:建立GuestBookBinder,讓它繼承IModelBinder,並實現其方法。這裡我們可以根據實際業務需要,修改方法,這裡只是一個簡單實現。
public class GuestBookBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var info = bindingContext.Model ?? new GuestBookInfo();
var properties = bindingContext.ModelType.GetProperties();
foreach (var item in properties)
{
if (bindingContext.PropertyFilter(item.Name))
{
var result = bindingContext.ValueProvider[item.Name];
if (null == result)
{ break; }
var value = result.ConvertTo(item.PropertyType);
item.SetValue(info, value, null);
}
}
return info;
}
}
2:註冊GuestBookBinder,自訂Binder寫好後,系統並不會自動識別,需要在應用程式初始化進行註冊,ControllerActionInvoker.GetParameterValue 根據 ModelBinders.Binders.GetBinder() 來找對應的 IModelBinder,如沒找到則返回預設的 DefaultModelBinder。
protected void Application_Start()
{
ControllerBuilder.Current.DefaultNamespaces.Add("GuestBook.MVC.Controller");
ModelBinders.Binders.Add(typeof(GuestBookInfo ), new GuestBookBinder ());
RegisterRoutes(RouteTable.Routes);
}
3:除了上面的註冊方法外,可以直接把 ModelBinderAttribute 用在對應的實體上 ,但不推薦這樣做。
[ModelBinder(typeof(GuestBookBinder))]
public class GuestBookInfo
4:除了由 ControllerActionInvoker.GetParameterValue() 自動完成 BindModel 操作外,還提供了兩個方法:這兩個方法唯一的區別在於,TryUpdateModel不會拋異常,前者會。
1>:Controller.UpdateModel()
2>:Controller.TryUpdateModel()
樣本:例如更新一則留言時,我們可以這樣寫:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues)
{
GuestBookInfo model = new GuestBookInfo();
model.ID = id;
model = inter.GetInfo(model);
UpdateModel(model );
inter.Edit(model);
return RedirectToAction("Index");
}
總結:這篇文章主要總結了些IModelBinder 介面的作用,以及如何自訂Binder類。
註:本文參考:http://www.rainsts.net/article.asp?id=779