制作blog系统或者通用cms系统的时候,我们经常会用到Theme功能。asp.net mvc中的一种实现方式,是继承实现RazorViewEngine即可。
这是在GitHub中找到的一个示例:https://github.com/benedict-chan/ThemedViewEngines
结构如下图:
实现的核心代码ThemedRazorViewEngine.cs:
using System; using System.Web.Mvc; namespace ThemedViewEngines { public class ThemedRazorViewEngine : RazorViewEngine { private readonly IThemeSelectorService _themeSelectorService; public string DefaultMasterName { get; set; } public ThemedRazorViewEngine(IThemeSelectorService themeSelectorService) : base() { DefaultMasterName = "_Layout"; this._themeSelectorService = themeSelectorService; 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", "~/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", "~/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", "~/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", "~/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", "~/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", "~/Views/{1}/{0}.cshtml", "~/Views/{1}/{0}.vbhtml", "~/Views/Shared/{0}.cshtml", "~/Views/Shared/{0}.vbhtml" }; FileExtensions = new[] { "cshtml", "vbhtml", }; } protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath) { string replacedPartialPath = GetThemedPath(partialPath); return base.CreatePartialView(controllerContext, replacedPartialPath); } protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath) { string replacedViewPath = GetThemedPath(viewPath); string replacedMasterPath = GetThemedPath(masterPath); return base.CreateView(controllerContext, replacedViewPath, replacedMasterPath); } protected override bool FileExists(ControllerContext controllerContext, string virtualPath) { string replacedVirtualPath = GetThemedPath(virtualPath); return base.FileExists(controllerContext, replacedVirtualPath); } public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) { var themeName = this._themeSelectorService.GetThemeName(); if (!string.IsNullOrEmpty(themeName) && string.IsNullOrEmpty(masterName)) { //In case if we have a theme, and the request view is not found in the theme folder (i.e. we will use the default view), // we will not be able to locate the theme's master page via _ViewStart (as the view is now in the default "theme" tree ) //Therefore we have to manually locate the Master page name here masterName = DefaultMasterName; } return base.FindView(controllerContext, viewName, masterName, false); } private string GetThemedPath(string originalPath) { var replacedPath = originalPath; var themeName = this._themeSelectorService.GetThemeName(); if (!string.IsNullOrEmpty(themeName)) { string replaceText = string.Format("Themes/{0}", themeName); replacedPath = originalPath.Replace("#@", replaceText); } return replacedPath; } } }
ConfigThemeService.cs的代码
1 namespace ThemedViewEngines 2 { 3 public class ConfigThemeService : IThemeSelectorService 4 { 5 public string GetThemeName() 6 { 7 return ConfigurationManager.AppSettings["ThemeName"] ?? string.Empty; 8 } 9 public void SetThemeName(string themeName) 10 { 11 throw new NotSupportedException(); 12 } 13 14 } 15 }
IThemeSelectorService.cs的代码:
1 namespace ThemedViewEngines 2 { 3 public interface IThemeSelectorService 4 { 5 /// <summary> 6 /// 获取Theme名称 7 /// </summary> 8 /// <returns></returns> 9 string GetThemeName(); 10 /// <summary> 11 /// 设置主题名称 12 /// </summary> 13 /// <param name="themeName"></param> 14 void SetThemeName(string themeName); 15 } 16 }
CookieThemeService.cs的代码
1 using System; 2 using System.Web; 3 4 namespace ThemedViewEngines 5 { 6 public class CookieThemeService : IThemeSelectorService 7 { 8 public string GetThemeName() 9 { 10 var cookie = HttpContext.Current.Request.Cookies["ThemeName"]; 11 if (cookie != null) 12 return cookie.Value; 13 return string.Empty; 14 } 15 16 public void SetThemeName(string themeName) 17 { 18 throw new System.NotImplementedException(); 19 } 20 } 21 }
调用方式:
1、新建mvc项目
2、根据上图中的示例建立Themes文件夹,Themes下面新建blue和red文件夹,然后分别把Views下的文件复制到blue和red中(主要是web.config一定要复制过去,不然没有智能提示)
3、添加引用ThemedViewEngines类库
4、在global文件的Application_Start方法下添加:
1 ViewEngines.Engines.Clear(); 2 //用 Web.config 配置 theme 的写法 3 ViewEngines.Engines.Add(new ThemedRazorViewEngine(new ConfigThemeService())); 4 //用cookie配置theme的写法 5 //ViewEngines.Engines.Add(new ThemedRazorViewEngine(new CookieThemeService()));
5、在Web.config的appSettings节点下添加:
<!--Theme配置--> <add key="ThemeName" value="blue" /> <!--Theme配置 end-->
6、运行项目即可。
Demo下载