zoukankan      html  css  js  c++  java
  • Asp.net MVC 示例项目"Suteki.Shop"分析之ViewData

         使用强类型的ViewData好处有许多,比如说在IDE中就会有更好的支持,比如代码提示。同时在View与Controller
    之间有更严谨的“约定”。在Suteki.Shop项目中作者对强类型的ViewPage引入是通过MvcContrib实现的,下面就是
    ViewPage<T>代码(Suteki.Shop\Views\ViewPage.cs):     

    public class ViewPage<T> : MvcContrib.FluentHtml.ModelViewPage<T> where T : class 
    {
            
    public ViewPage() : base(new LowercaseFirstCharacterOfNameBehaviour())
            {}
    }

    public class ViewUserControl<T> : MvcContrib.FluentHtml.ModelViewUserControl<T> where T : class
    {
            
    public ViewUserControl() : base(new LowercaseFirstCharacterOfNameBehaviour())
            {}
    }


         可以看出ViewPage和ViewUserControl只是对MvcContrib中ModelViewPage,ModelViewUserControl的继承,
    代码很简单,没什么太多可说的。

         强类型的ViewData使用形如:ViewPage<TViewData>,我们可以通过打开一个View看一下,比如“编辑用户信
    息”时的视图头声明部分:
          

    <%@ Page Title="" Language="C#"  Inherits="Suteki.Shop.ViewPage<ShopViewData>"

        
        
         其中的ShopViewData就是TViewData。在Suteki.Shop中作者使用ShopViewData对Model中大部分类作了相应
    的属性和数据绑定的统一封装,感觉ShopViewData就是Model的集合体或者是“缩影”,这样的好处就我看来主要是在
    View中进行强类型ViewData绑定时统一参数,这里感觉有偷懒之嫌。不过因此造成其自身视图数据的“庸肿”,其内部
    有太多的属性,还是就是绑定传递时的效率可能也会存在一些问题(只是猜测,未测试过,呵呵)。

         好了,下面就开始正文。
       
         首先我们要看一下Suteki.Common\ViewData文件夹下面的几个类,包括:
        
         IErrorViewData,IMessageViewData,ViewDataBase等,其类图如下:

        
            
        
         从图中看出,ViewDataBase是其体系“核心”, 其实现了 IMessageViewData, IErrorViewData这两个接口。
    实体代码如下:
       

    public abstract class ViewDataBase : IMessageViewData, IErrorViewData
    {
            
    public string Message { getset; }
            
    public string ErrorMessage { getset; }

            
    public ViewDataBase WithErrorMessage(string errorMessage)
            {
                
    this.ErrorMessage = errorMessage;
                
    return this;
            }

            
    public ViewDataBase WithMessage(string message)
            {
                
    this.Message = message;
                
    return this;
            }
    }

       

          该抽象类的属性MessageErrorMessage分别实现了IMessageViewDataIErrorViewData的接口属性。主要
     用于显示临时操作信息(比如“成功添加用户”,“成功编辑用户”等)。其所提供的两个方法“WithErrorMessage”
     和“WithMessage”只是对相应属性的简单绑定而已。
     
         有了ViewDataBase之后,下面就来看一下其子类实现了,下面是相应类图:
        
        
        正如前面所介绍的那样,子类中最“重要”的当属“ShopViewData”,其包括了基本所有Model中的类型,并将
    它们以“属性”的方法提供出来以便于前台View使用,同时ShopViewData还提供了与其属性相关的绑定方法(均以
    With...”开头),下面就是其代码。   

    Code

        
         为了便于使用,Suteki.Shop还以静态属性的方式进行了封闭,最终以ShopView这个类开放出来提
    供给Action和View使用,其实现代码如下:
        

    /// <summary>
    /// So you can write 
    /// ShopView.Data.WithProducts(myProducts);
    /// </summary>
    public class ShopView
    {
         
    public static ShopViewData Data { get { return new ShopViewData(); } }
    }

            
         下面以“编辑用户”这个Action来看一下其使用方法: 

    [AcceptVerbs(HttpVerbs.Post), UnitOfWork]
    public ActionResult Edit([DataBind] User user, string password)
    {
            
    if(! string.IsNullOrEmpty(password))
            {
                user.Password 
    = userService.HashPassword(password);
            }

            
    try
            {
                user.Validate();
            }
            
    catch (ValidationException validationException)
            {
                validationException.CopyToModelState(ModelState, 
    "user");
                
    return View("Edit", EditViewData.WithUser(user));
            }

            
    return View("Edit", EditViewData.WithUser(user).WithMessage("Changes have been saved")); 
    }

       

         注意其中的EditViewData属性就是初始化一个ShopViewData实例并调用该实例的WithRoles()方法
    来完成对用户规则的获取。然后在"Edit"这个Action的返回语句中继续绑定其他信息,如当前编辑的用户信息
    “user”,以及操作提示信息“Changes have been saved”。

         这样就可以在View中对ShopViewData进行显示操作了。这里要说明的是在View中对Message的显示是
    通过下面这一行完成的:
         

    <%= Html.MessageBox(ViewData.Model) %>

         
         而这个方法是对HtmlHelper这个MVC类的扩展方法,其方法定义如下:  

    public static string MessageBox(this HtmlHelper htmlHelper, IMessageViewData messageViewData)
    {
        
    if (messageViewData.Message == nullreturn string.Empty;

        HtmlTextWriter writer 
    = new HtmlTextWriter(new StringWriter());

        writer.AddAttribute(
    "class""message");
        writer.RenderBeginTag(HtmlTextWriterTag.Div);
        writer.Write(messageViewData.Message);
        writer.RenderEndTag();
        
    return writer.InnerWriter.ToString();
    }

         大家看到了其传入的参数是IMessageViewData类型,而传入的是“ShopViewData”类型,如下图所
    示:

       
          而看过上面内容的话,就可以通过其类图中实现的方法看出这个继承实现链表: 

          ShopViewData ==> ViewDataBase == > IMessageViewData


        
         所以扩展文法直接就完成了这种“向上转型”操作。    
        
         除了“编辑用户”这种在Action中直接绑定Message字段属性的方式,Suteki.Shop还提供了Filter
    方式的“操作信息”绑定,比如CopyMessageFromTempDataToViewData(Suteki.Shop\Filters),
    其代码如下:

    public class CopyMessageFromTempDataToViewData : ActionFilterAttribute
    {
            
    public override void OnActionExecuted(ActionExecutedContext filterContext) 
            {
                    var result 
    = filterContext.Result as ViewResult;

                    
    if(result != null && filterContext.Controller.TempData.ContainsKey("message"))
                    {
                        var model 
    = result.ViewData.Model as ShopViewData;

                        
    if(model != null && string.IsNullOrEmpty(model.Message))
                        {
                            model.Message 
    = filterContext.Controller.TempData["message"as string;
                        }
                    }
            }
    }
        


        
         大家请注意,上面的filterContext.Controller类型是ControllerBase(详细说明参见我之前写的这
    篇文章),其提供了Message属性来实现临时数据TempData["message"]的获取来绑定工作,代码如
    下:

    [Rescue("Default"), Authenticate, CopyMessageFromTempDataToViewData]
    public abstract class ControllerBase : Controller, IProvidesBaseService
    {
            
            
         
    public string Message
         {
             
    get { return TempData["message"as string; }
             
    set { TempData["message"= value; }
         }
    }


        
         这样就可以通过CopyMessageFromTempDataToViewData这个Filter来实现将临时数据绑定到
    ShopViewData中的Message属性,并提供给前台View使用了。当然这是有条件的,就是上面代码中
    的这一行:

        if(model != null && string.IsNullOrEmpty(model.Message)) 


         从逻辑上看,这样做应该是防止对已绑定操作信息(model.Message不为空)进行“误覆盖”吧。
       
       
         好了,今天的内容就先到这里了。
       
       
         原文链接:http://www.cnblogs.com/daizhj/archive/2009/05/25/1454871.html

         作者: daizhj,代震军,LaoD

         Tags: mvc,Suteki.Shop

         网址: http://daizhj.cnblogs.com/
      
       
       
      
       
       
       
       

  • 相关阅读:
    vs2008及以上的ActiveX测试容器在哪儿
    关于databinding的细节
    C#使用StackTrace获取方法被谁调用
    你是怎么走神的?
    怎样让SoapHttpClientProtocol不使用系统默认代理
    List的FindIndex和ForEach
    List的Capacity
    装箱和拆箱
    FileSystem.DeleteDirectory遇到"无法删除 文件:无法读取源文件或磁盘"
    一段关于测试和自定义Attribute的代码
  • 原文地址:https://www.cnblogs.com/daizhj/p/1454871.html
Copyright © 2011-2022 走看看