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