zoukankan      html  css  js  c++  java
  • ASP.NET MVC 下打造轻量级的 Theme 机制

    上一篇文章[剖析 NopCommerce 的 Theme 机制]介绍了Nop实现Theme的实现原理。但由于Nop要为Admin和Mobile做特殊处理,因此写了太多的其它东西。因此我们决定自己写一个Theme的ViewEngine,仅仅用来实现皮肤功能。

    需求分析

    考虑到Demo程序,为简单起见,我们将Theme放到Url中,格式:

    {Controller}/{Action}?Theme={Theme},当然你完全可以从Cookie或者数据库中去读取用户设置的Theme信息。

    其次,Theme文件夹的组织结构,就采用NopCommerce的这种文件夹结构吧。

    Themes/{Theme}/Views/…

     

    新建站点

    首先新建一个MVC 4 的默认站点 ThemeDemo,用默认的Internet 模版吧。

    实现ThemeViewEngine

    自定义Theme的ViewEngine,并从RazorViewEngine继承。在构造函数中设置View的路径模版:

    View Code

    PS:我是从RazorViewEngine源码里面拷贝出默认的View路径模版,然后加上Themes的View路径模版。

    实现接口:IViewEngine的方法 FindView 和 FindPartialView

    通过反编译VirtualPathProviderViewEngine,发现FindView和FindPartialView的2个方法均会访问 GetPath方法,而GetPath方法的作用是根据Controller和Action,返回View的实际路径。理论上讲,只要重写GetPath,并根据Theme生成新的View路径。 但由于GetPath是内部方法,我们无法重写,于是我们不得不重写FindView和FindPartialView 2个方法。这些工作其实也不难,就是Ctrl+Cà Ctrl+V,我相信大家都很熟练这们技术了,也就略去不讲。下面重点介绍下自定义GetPath的具体实现:

    View Code
    • 读取当前的Theme,可根据实际需求自定义,这里是从QueryString或者Form中读取的
    protected virtual string GetCurrentTheme(ControllerContext controllerContext)
    {
        var theme = controllerContext.RequestContext.HttpContext.Request["Theme"];
        return theme;
    }
    • 读取Area,调用方法GetAreaName,拷贝自VirtualPathProviderViewEngine
    View Code
    • 获取ViewLocation的相关信息,该类是用来根据参数,从View路径模版生成实际的View路径。自定义如下2个类,参考VirtualPathProviderViewEngine,Format方法增加Theme参数
    View Code
    • 先从缓存中读取View的实际路径,如果不存在,则通过方法GetPathFromGeneralName 获取View的实际路径信息 
    View Code

    该方法会将参数Theme、Controller和Action等传入上文提到的View路径模版,生成实际的路径,如果文件不存在,继续尝试下一个View路径模版。直到找到View存在的实际路径。然后缓存起来,提高效率。 

    • 最后将ThemeViewEngine注入到MVC中
    //remove all view engines
    ViewEngines.Engines.Clear();
    //except the themeable razor view engine we use
    ViewEngines.Engines.Add(new ThemeViewEngine());

    创建Theme

    首先新建一个Theme取名叫Black吧。将背景色设置为黑色。

    Web.Config 是从Views文件夹下面拷贝过来的。将默认的_Layout.cshtml按照文件夹的结构拷贝过来,并修改如下样式:

    <body style="background-color: black; color: white;">

    PS:如果不拷贝Web.Config,View里面没有智能提示。

    测试

    到这里,我已经有点激动了,Theme功能马上就要实现了。显然大部分代码都是从微软的代码哪里拷贝的,自定义的几行代码绝对有信心,但做集成测试还是必不可少。至少要看到Theme的效果吧。 

    运行项目,Ctrl+F5

    键入Theme参数:

     

    悲剧发生了,没有预期的效果。各种Debug,自定义代码均能够正常工作,说明自定义ViewEngine正常。通过Debug NopCommerce的ViewEngine对比发现:Nop每次请求,自定义的ViewEngine都会调用FindView去查找MasterPage的路径。而我们自定义的ThemeViewEngine不会通过FindView去查找MasterPage的路径。故读取MasterPage还是从原来的路径读取。我们自定义的ThemeViewEngine只对View和Partial View有效,对于MasterPage无效。问题终于找到,接下来该如何解决呢?难道要我们放弃对于MasterPage的支持吗?显然对于挑剔的我是无法接受的。

    既然NopCommerce实现了整个功能,肯定还有什么机关我们没有触碰到。通过查找Nop的源码发现了抽象类:WebViewPage,通过Reshareper发现该类“未被”任何类继承。但发现所有的View都继承自该类。该类重写了基类的Layout属性,而这里是通过ViewEngine重新获取MasterPage文件路径的。

    View Code

    我们依葫芦画瓢也写一个WebViewPage。然后在Web.Config做如下配置:

    复制代码
    <system.web.webPages.razor>
        <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <pages pageBaseType="ThemeDemo.Mvc.WebViewPage">
          <namespaces>
            <add namespace="System.Web.Mvc" />
            <add namespace="System.Web.Mvc.Ajax" />
            <add namespace="System.Web.Mvc.Html" />
            <add namespace="System.Web.Optimization"/>
            <add namespace="System.Web.Routing" />
          </namespaces>
        </pages>
      </system.web.webPages.razor>
    复制代码

    (PS:记得在Theme下的Web.Config中也要做同样的修改)

    再次调试:

    黑色的背景白色的字,终于出现了。什么这也太丑了吧….

    后记

    要实现一个好的皮肤机制,除了解决皮肤文件的定位之外,还有很多工作要做。比如要对页面布局有一个精细地设计,对兼容性、扩展性、复用性都有一个全面的考虑。

    文中示例源码下载地址:https://files.cnblogs.com/coolite/ThemeDemo.zip

    Coding change lives
    分类: MVC
    标签: MVCASP.NETThemeViewEngineCustom
  • 相关阅读:
    随机森林算法参数调优
    BAYES和朴素BAYES
    阿里云 金融接口 token PHP
    PHP mysql 按时间分组 表格table 跨度 rowspan
    MySql按周,按月,按日分组统计数据
    PHP 获取今日、昨日、本周、上周、本月的等等常用的起始时间戳和结束时间戳的时间处理类
    thinkphp5 tp5 会话控制 session 登录 退出 检查检验登录 判断是否应该跳转到上次url
    微信 模板消息
    php 腾讯 地图 api 计算 坐标 两点 距离 微信 网页 WebService API
    php添加http头禁止浏览器缓存
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2839657.html
Copyright © 2011-2022 走看看