博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Asp.net MVC 示例项目"Suteki.Shop"分析之---ViewData
阅读量:6415 次
发布时间:2019-06-23

本文共 4930 字,大约阅读时间需要 16 分钟。

    使用强类型的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 { 
get
set
; }
        
public
 
string
 ErrorMessage { 
get
set
; }
        
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...”开头),下面就是其代码。   
 
ContractedBlock.gif
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 
==
 
null
return
 
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不为空)进行“误覆盖”吧。
    
    
         好了,今天的内容就先到这里了。
    
本文转自 daizhenjun 51CTO博客,原文链接:http://blog.51cto.com/daizhj/160560,如需转载请自行联系原作者
你可能感兴趣的文章
linux简单命令---网络编程
查看>>
ajax基础------备忘
查看>>
kafka入门学习---1 启动kakfa
查看>>
关于Android菜单上的记录
查看>>
黄聪:利用ImageMagicK给图片加水印
查看>>
由lwip的mbox中netbuf传递看指针的指针
查看>>
Session: 防止用户多次登陆
查看>>
2014年 生活大爆炸版石头剪刀布
查看>>
Cocos2d-x开发---关于内存检测
查看>>
git shell 命令
查看>>
Revit插件获取数据Bug的解决1
查看>>
如何将matlab画出的图片保存为要求精度
查看>>
淘宝实习面试经历分享
查看>>
帮Customer Architecture写的小脚本
查看>>
Calling a Batch File/EXE from an SQR
查看>>
Message Box
查看>>
坐标轴的旋转及绕某一点旋转后坐标值求解
查看>>
KVO 简单使用
查看>>
如何在Linux终端里用Shell和C输出带颜色的文字
查看>>
REST framework
查看>>