ASP.NET MVC 重写RazorViewEngine完毕多大旨切换

    在ASP.NET
MVC中来促成大旨的切换一般有二种方法,一种是通过切换皮肤的css和js引用,一种就是经过重写视图引擎。通过重写视图引擎的艺术更是灵敏,因为我不光可以在不一样宗旨上边布局和体裁不一样,还足以让差别的大旨上边展现的数量条目不一致,就是说可以在好几主旨上面添加一下本性化的东西。

   
本篇作者将由此重写视图引擎的格局来进显示身说法,在那之前,笔者假若你曾经怀有了MVC的一部分基础,系统登录后是暗许大旨,当我们点击切换宗旨之后,左侧菜单栏的布局变了,右边内容的样式也变了,而地址栏是不变的。界面UI用的metronic,尽管官网是收费的,不过在天朝,总是可以找到免费的。metronic是依据bootstrap的UI框架,官网地址:http://keenthemes.com/preview/metronic/

    大家先来看下效果:

图片 1

图片 2

   
在那边,小编使用了分区域、分模块(按独立的事体效能区划)的章程,1个模块就是壹个单身的dll,在此处Secom.Emx.Admin和Secom.Emx.History就是八个独立的模块,并各自创制了区域Admin和History,当然你能够在单身模块上边成立八个区域。

 图片 3图片 4

   
你会意识Secom.Emx.Admin模型上边的Areas目录和Secom.Emx.WebApp中的目录是一模一样的,其实小编早期不想在模块项目中增进其它的View,可是为了方便独立布署如故加了。右键单击项目Secom.Emx.Admin,接纳“属性”——“生成事件”添加如下代码:

xcopy /e/r/y $(ProjectDir)Areas\Admin\Views $(SolutionDir)Secom.Emx.WebApp\Areas\Admin\Views

   
那命令很粗略,其实就是当编译项目Secom.Emx.Admin的时候,将项目中的Views复制到Secom.Emx.WebApp项目标指定目录下。

图片 5

   
区域布局文件我放置到了Secom.Emx.WebApp中,其实您一点一滴可以单独放置到贰个类库项目中,因为登记区域路由的后,项目最后会招来bin目录上面所有继续了AreaRegistration类的,然后让WebApp引用那个类库项目,Secom.Emx.WebApp项目添加Secom.Emx.Admin、Secom.Emx.History的引用。

图片 6

    AdminAreaRegistration代码如下:

using System.Web.Mvc;

namespace Secom.Emx.WebApp
{
    public class AdminAreaRegistration : AreaRegistration 
    {
        public override string AreaName 
        {
            get 
            {
                return "Admin";
            }
        }

        public override void RegisterArea(AreaRegistrationContext context) 
        {
            context.MapRoute(
                "Admin_default",
                "Admin/{controller}/{action}/{id}",
                new { action = "Index", id = UrlParameter.Optional },
                namespaces:new string[1] { "Secom.Emx.Admin.Areas.Admin.Controllers" }
            );
        }
    }
}

    注意命名空间和前面添加的
namespaces:new string[1] {
“Secom.Emx.Admin.Areas.Admin.Controllers”
},那些命名空间就是独自模块Secom.Emx.Admin下边的控制器所在的命名空间。HistoryAreaRegistration代码如下:

图片 7图片 8

using System.Web.Mvc;

namespace Secom.Emx.WebApp
{
    public class HistoryAreaRegistration : AreaRegistration 
    {
        public override string AreaName 
        {
            get 
            {
                return "History";
            }
        }

        public override void RegisterArea(AreaRegistrationContext context) 
        {
            context.MapRoute(
                "History_default",
                "History/{controller}/{action}/{id}",
                new { action = "Index", id = UrlParameter.Optional },
                namespaces:new string[1] { "Secom.Emx.History.Areas.History.Controllers" }
            );
        }
    }
}

View Code

    大家先看下RazorViewEngine的本来构造函数如下:

图片 9图片 10

    public RazorViewEngine(IViewPageActivator viewPageActivator)  
        : base(viewPageActivator)  
    {  
        AreaViewLocationFormats = new[]  
        {  
            "~/Areas/{2}/Views/{1}/{0}.cshtml",  
            "~/Areas/{2}/Views/{1}/{0}.vbhtml",  
            "~/Areas/{2}/Views/Shared/{0}.cshtml",  
            "~/Areas/{2}/Views/Shared/{0}.vbhtml"  
        };  
        AreaMasterLocationFormats = new[]  
        {  
            "~/Areas/{2}/Views/{1}/{0}.cshtml",  
            "~/Areas/{2}/Views/{1}/{0}.vbhtml",  
            "~/Areas/{2}/Views/Shared/{0}.cshtml",  
            "~/Areas/{2}/Views/Shared/{0}.vbhtml"  
        };  
        AreaPartialViewLocationFormats = new[]  
        {  
            "~/Areas/{2}/Views/{1}/{0}.cshtml",  
            "~/Areas/{2}/Views/{1}/{0}.vbhtml",  
            "~/Areas/{2}/Views/Shared/{0}.cshtml",  
            "~/Areas/{2}/Views/Shared/{0}.vbhtml"  
        };  

        ViewLocationFormats = new[]  
        {  
            "~/Views/{1}/{0}.cshtml",  
            "~/Views/{1}/{0}.vbhtml",  
            "~/Views/Shared/{0}.cshtml",  
            "~/Views/Shared/{0}.vbhtml"  
        };  
        MasterLocationFormats = new[]  
        {  
            "~/Views/{1}/{0}.cshtml",  
            "~/Views/{1}/{0}.vbhtml",  
            "~/Views/Shared/{0}.cshtml",  
            "~/Views/Shared/{0}.vbhtml"  
        };  
        PartialViewLocationFormats = new[]  
        {  
            "~/Views/{1}/{0}.cshtml",  
            "~/Views/{1}/{0}.vbhtml",  
            "~/Views/Shared/{0}.cshtml",  
            "~/Views/Shared/{0}.vbhtml"  
        };  

        FileExtensions = new[]  
        {  
            "cshtml",  
            "vbhtml",  
        };  
    }  

View Code

   
然后新建CustomRazorViewEngine继承自RazorViewEngine,对View的路由规则举行了重写,既然可以重写路由规则,那表示,你能够私行定义规则,然后遵守自个儿定义的平整就可以了。需求小心的是,要小心路由数组中的顺序,查找视图时,是循途守辙前后相继依次查找的,当找到了视图就立马回去,不会再去匹配后边的路由规则。为了升高路由查找功能,我这里删除了富有vbhtml的路由规则,因为本人所有项目中都使用C#语言。

图片 11图片 12

using System.Web.Mvc;

namespace Secom.Emx.WebApp.Helper
{
    public class CustomRazorViewEngine : RazorViewEngine
    {
        public CustomRazorViewEngine(string theme)
        {
            if (!string.IsNullOrEmpty(theme))
            {
                AreaViewLocationFormats = new[]
                {
                       //themes
                       "~/themes/"+theme+"/views/Areas/{2}/{1}/{0}.cshtml",
                      "~/themes/"+theme+"/Shared/{0}.cshtml"

        "~/Areas/{2}/Views/{1}/{0}.cshtml",
        "~/Areas/{2}/Views/Shared/{0}.cshtml"
    };
                AreaMasterLocationFormats = new[]
                {
                             //themes
              "~/themes/"+theme+"/views/Areas/{2}/{1}/{0}.cshtml",
              "~/themes/"+theme+"/views/Areas/{2}/Shared/{0}.cshtml",
              "~/themes/"+theme+"/views/Shared/{0}.cshtml",

        "~/Areas/{2}/Views/{1}/{0}.cshtml",
        "~/Areas/{2}/Views/Shared/{0}.cshtml"
    };
                AreaPartialViewLocationFormats = new[]
                {
                            //themes
         "~/themes/"+theme+"/views/Shared/{0}.cshtml",

        "~/Areas/{2}/Views/{1}/{0}.cshtml",
        "~/Areas/{2}/Views/Shared/{0}.cshtml"
    };

                ViewLocationFormats = new[]
                {
                            //themes
          "~/themes/"+theme+"/views/{1}/{0}.cshtml",

        "~/Views/{1}/{0}.cshtml",
        "~/Views/Shared/{0}.cshtml"
    };
                MasterLocationFormats = new[]
                {
                            //themes
         "~/themes/"+theme+"/views/Shared/{0}.cshtml",

        "~/Views/{1}/{0}.cshtml",
        "~/Views/Shared/{0}.cshtml"
    };
                PartialViewLocationFormats = new[]
                {
                            //themes
        "~/themes/"+theme+"/views/Shared/{0}.cshtml",

        "~/Views/{1}/{0}.cshtml",
        "~/Views/Shared/{0}.cshtml"
    };

                FileExtensions = new[]{"cshtml"};
            }

        }
    }
}

View Code

图片 13

   
重写后,我们的路由规则将是如此的:当没有选用大旨的场所下,沿用原来的路由规则,如若选拔了主旨,则采取重写后的路由规则。

新的路由规则:在挑选了核心的情形下,优先查找thems/核心名称/views/Areas/区域名称/控制器名称/视图名称.cshtml,假诺找不到再根据暗许的路由规则去搜寻,也等于Areas/区域名称/Views/控制器名称/视图名称.cshtml。

可以看看大家摸索模板页的办法也被涂改了,所以对于部分通用的,只要换模板页就能够了,不要求加上view界面,因为指定主旨上面找不到view会去暗许主旨上边找,而view界面会引用模板页的,对于部分个性化的事物,再去指定的主旨上边添加新的view,不知晓小编如此表述你有知情没,感觉相比饶,反正就是您可以根据你本人的条条框框去找视图,而不是asp.net
mvc暗中认同的规则。

 图片 14

    切换宗旨View代码:

                <div class="btn-group">
                    <button type="button" class="btn btn-circle btn-outline red dropdown-toggle" data-toggle="dropdown">
                        <i class="fa fa-plus"></i>&nbsp;
                        切换主题&nbsp;&nbsp;
                        <i class="fa fa-angle-down"></i>
                    </button>
                    <ul class="dropdown-menu" role="menu">
                        <li>
                            <a href="javascript:setTheme('default')">
                                <i class="icon-docs"></i> 默认主题
                            </a>
                        </li>
                        <li>
                            <a href="javascript:setTheme('Blue')">
                                <i class="icon-tag"></i> 蓝色主题
                            </a>
                        </li>
                    </ul>
                </div>
        <script type="text/javascript">
           function setTheme(themeName)
            {
               window.location.href = "/Home/SetTheme?themeName=" + themeName + "&href=" + window.location.href;
            }
        </script>

   
当用户登录成功的时候,从Cookie中读取所选大旨消息,当Cookie中尚无读取到大旨记录时,则从Web.config配置文件中读取配置的大旨名称,假使都尚未读取到,则表明是暗中认可宗旨,沿用原有的视图引擎规则。在后台管理界面,每一遍采取了主旨,小编都将主题名称存储到Cookie中,暗中认同保存一年,那样当下次再登录的时候,就可以记住所选的核心音讯了。

using System;
using System.Web.Mvc;
using Secom.Emx.WebApp.Helper;
using System.Web;
using Secom.Emx.Common.Controllers;

namespace Secom.Emx.WebApp.Controllers
{
    public class HomeController : BaseController
    {
        string themeCookieName = "Theme";
        public ActionResult Index()
        {
            ViewData["Menu"] = GetMenus();
            return View();
        }
        public ActionResult SetTheme(string themeName,string href)
        {
            if (!string.IsNullOrEmpty(themeName))
            {
                Response.Cookies.Set(new HttpCookie(themeCookieName, themeName) { Expires = DateTime.Now.AddYears(1) });
            }
            else
            {
                themeName = Request.Cookies[themeCookieName].Value ?? "".Trim();
            }
            Utils.ResetRazorViewEngine(themeName);
            return string.IsNullOrEmpty(href)? Redirect("~/Home/Index"):Redirect(href);
        }
        public ActionResult Login()
        {
            string themeName = Request.Cookies[themeCookieName].Value ?? "".Trim();
            if (!string.IsNullOrEmpty(themeName))
            {
                Utils.ResetRazorViewEngine(themeName);
            }
            return View();
        }
    }
}

    Utils类:

图片 15图片 16

using System.Configuration;
using System.Web.Mvc;

namespace Secom.Emx.WebApp.Helper
{
    public class Utils
    {
        private static string _themeName;

        public static string ThemeName
        {
            get
            {
                if (!string.IsNullOrEmpty(_themeName))
                {
                    return _themeName;
                }
                //模板风格
                _themeName =string.IsNullOrEmpty(ConfigurationManager.AppSettings["Theme"])? "" : ConfigurationManager.AppSettings["Theme"];
                return _themeName;
            }
        }
        public static void ResetRazorViewEngine(string themeName)
        {
            themeName = string.IsNullOrEmpty(themeName) ? Utils.ThemeName : themeName;
            if (!string.IsNullOrEmpty(themeName))
            {
                ViewEngines.Engines.Clear();
                ViewEngines.Engines.Add(new CustomRazorViewEngine(themeName));
            }
        }
    }
}

View Code

    
已毕形式实际上是太简单,简单得本人不明白哪些发挥才好,我如故记下来,方便有必要的人方可查看,希望得以帮到你们。由于种类引入了高大的种种相关文件以致文件相比大,网速原因不可能上传源码还望见谅!