使用强类型的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;
        }
}

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

public Product Product { get; set; }
        public IEnumerable<Product> Products { get; set; }

public IEnumerable<Role> Roles { get; set; }

public User User { get; set; }
        public IEnumerable<User> Users { get; set; }

public Basket Basket { get; set; }

public Order Order { get; set; }
        public PagedList<Order> Orders { get; set; }
        public OrderSearchCriteria OrderSearchCriteria { get; set; }

public IEnumerable<Country> Countries { get; set; }
        public Country Country { get; set; }

public IEnumerable<CardType> CardTypes { get; set; }

public Postage Postage { get; set; }
        public IEnumerable<Postage> Postages { get; set; }

public PostageResult PostageResult { get; set; }

public Card Card { get; set; }

public IEnumerable<StockItem> StockItems { get; set; }

public IEnumerable<Content> Contents { get; set; }

public IEnumerable<OrderStatus> OrderStatuses { get; set; }

// attempt at a fluent interface

public ShopViewData WithCategory(Category category)
        {
            this.Category = category;
            return this;
        }

public ShopViewData WithCategories(IEnumerable<Category> categories)
        {
            this.Categories = categories;
            return this;
        }

public ShopViewData WithProduct(Product product)
        {
            this.Product = product;
            return this;
        }

public ShopViewData WithProducts(IEnumerable<Product> products)
        {
            this.Products = products;
            return this;
        }

public ShopViewData WithRoles(IEnumerable<Role> roles)
        {
            this.Roles = roles;
            return this;
        }

public ShopViewData WithUser(User user)
        {
            this.User = user;
            return this;
        }

public ShopViewData WithUsers(IEnumerable<User> users)
        {
            this.Users = users;
            return this;
        }

public ShopViewData WithBasket(Basket basket)
        {
            this.Basket = basket;
            return this;
        }

public ShopViewData WithOrders(PagedList<Order> orders)
        {
            this.Orders = orders;
            return this;
        }

public ShopViewData WithOrder(Order order)
        {
            this.Order = order;
            return this;
        }

public ShopViewData WithOrderSearchCriteria(OrderSearchCriteria orderSearchCriteria)
        {
            this.OrderSearchCriteria = orderSearchCriteria;
            return this;
        }

public ShopViewData WithCountries(IEnumerable<Country> countries)
        {
            this.Countries = countries;
            return this;
        }

public ShopViewData WithCountry(Country country)
        {
            this.Country = country;
            return this;
        }

public ShopViewData WithCardTypes(IEnumerable<CardType> cardTypes)
        {
            this.CardTypes = cardTypes;
            return this;
        }

public ShopViewData WithPostage(Postage postage)
        {
            this.Postage = postage;
            return this;
        }

public ShopViewData WithPostages(IEnumerable<Postage> postages)
        {
            this.Postages = postages;
            return this;
        }

public ShopViewData WithTotalPostage(PostageResult postageResult)
        {
            this.PostageResult = postageResult;
            return this;
        }

public ShopViewData WithCard(Card card)
        {
            this.Card = card;
            return this;
        }

public ShopViewData WithStockItems(IEnumerable<StockItem> stockItems)
        {
            this.StockItems = stockItems;
            return this;
        }

public ShopViewData WithContents(IEnumerable<Content> contents)
        {
            this.Contents = contents;
            return this;
        }

public ShopViewData WithOrderStatuses(IEnumerable<OrderStatus> orderStatuses)
        {
            this.OrderStatuses = orderStatuses;
            return this;
        }
}

    
         为了便于使用,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不为空)进行“误覆盖”吧。
   
   
         好了,今天的内容就先到这里了。
    
      
    
    
   
    
    
    
   

转载于:https://blog.51cto.com/daizhj/160560

Asp.net MVC 示例项目Suteki.Shop分析之---ViewData相关推荐

  1. Asp.net MVC 示例项目Suteki.Shop分析之---结束篇

    到今天,这个系列的文章就要先告一段落了.其中我用了10篇文章也没有穷尽该项目的设计思想,只能从中捡了一些我感兴趣的东西进行了分析和说明,正所谓兴趣是最大的动力.当然限于本人水平有限,难免有一些认识上的 ...

  2. Asp.net MVC 示例项目Suteki.Shop分析之---Model和Service

    老戴的文章,自己去看吧 http://www.cnblogs.com/daizhj/archive/2009/05/31/1455867.html 转载于:https://www.cnblogs.co ...

  3. 图文详解远程部署ASP.NET MVC 5项目

    图文详解远程部署ASP.NET MVC 5项目 原文:图文详解远程部署ASP.NET MVC 5项目 话外篇: 由于感觉自己的机器比较慢,配置不好,所以最近想把之前的项目部署到实验室的服务器上,但是由 ...

  4. 使用Visual Studio 2015 开发ASP.NET MVC 5 项目部署到Mono/Jexus

    最新的Mono 4.4已经支持运行asp.net mvc5项目,有的同学听了这句话就兴高采烈的拿起Visual Studio 2015创建了一个mvc 5的项目,然后部署到Mono上,浏览下发现一堆错 ...

  5. angular2+typescript在asp.net MVC Web项目上的实现

    网上现在还没有关于angular2+typescript在asp.net mvc web项目上的实现的系统介绍,这里我也只是探索到了一个简单的方式,还有很多问题没能解决.但是能有个好的开头也值得记录一 ...

  6. 利用Powershell自动部署asp.net mvc网站项目 (一)

    这一篇中我们会写一些关于自动化部署的代码.我们会使用 Powershell 书写这类代码. 你将发现这篇文章中涉及的东西非常具体,有的要求甚至相当苛刻且可能不具有通用性.这是因为部署从来都是跟环境打交 ...

  7. ASP.NET MVC 开源项目 收集

    Oxite NerdDinner MvcStore Suteki.Shop(http://code.google.com/p/sutekishop/downloads/list)(DEMO:http: ...

  8. Unity huatuo示例项目源码分析与启发

    上一节我们安装huatuo的开发环境,然后运行示例项目,体验了huatuo做热更新,这节课我们来分析示例项目的源码,掌握huatuo做热更新的主要的步骤,让你自己的项目很好的基于huatuo来组织热更 ...

  9. 一个非常简单的 ASP.NET MVC 示例:长轮询(又叫:反向 AJAX,英文名:Comet)实现...

    关于 长轮询(又叫:反向 AJAX,英文名:Comet)的介绍,请查看:反向Ajax,第1部分:Comet介绍 下面是代码实现: UI: <p><input type="b ...

最新文章

  1. GPT-2的大规模部署:AI Dungeon 2 如何支撑百万级用户
  2. Jamie and Tree[CF916E]
  3. 里约奥运会的五项技术创新
  4. 机器学习—数据挖掘之灰色预测算法
  5. 孪生网络keras实现minist
  6. 16.3.22-24(这几天借鉴了别人写的代码的整合,但是是beat的)
  7. 《神奇的数学》读后感_奇妙的数学王国读后感10篇
  8. 如何实现Spark SQL 字段血缘?
  9. 好用的在线工具,提高你的办公工作效率
  10. 面试官:Java8 lambda 表达式 forEach 如何提前终止?
  11. 【2017今日头条】头条校招(JAVA)
  12. Matlab图像分割---使用dice相似系数方法进行图像分割精度验证
  13. net.sf.json.JSONException: Unterminated string at character 1801
  14. [bzoj3073]Journeys
  15. Javascript 16进制转有符号的10进制整数
  16. 对百草味企业网站的诊断评价
  17. 一步步学习微软InfoPath2010和SP2010--第一章节--介绍InfoPath2010
  18. 安卓开发培训!一次违反常规的安卓大厂面试经历,实战解析
  19. html+css+javascript代码编程规范之CSS
  20. [转]使用Word的“邮件合并”功能制作新年周历

热门文章

  1. 【暑假训练 7.10】 codevs 2492 上帝造题的七分钟2
  2. 【Mood 16 】史上最全github使用方法:github入门到精通
  3. Qt中基类widget的各个事件函数中包含了ignore()的调用
  4. c语言指针详解(概念示例)
  5. VC/MFC 进程间通信方法总结
  6. c++清空串口缓冲区
  7. swift5表情键盘项目封装
  8. 深度学习(Deep Learning):循环神经网络一(RNN)
  9. php 赋予最高权限,为PHP执行赋予root权限(一)
  10. 调用系统相机和相册,并且裁剪成圆形图片(解决6.0,7.0,8.0版本问题)