asp.net mvc (三)

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

你可能感兴趣的:(asp.net)