NopCommerce的后台分离技术(自定义视图引擎)
本文对NopCommerce的后台分离技术做简单的探讨。NopCommerce通过自定义视图引擎,重写了VirtualPathProviderViewEngine类的CreateView、CreatePartialView、FindView、FindPartialView方法,添加自定义的视图搜索路径来实现后台分离。
说到ASP.NET MVC中的视图引擎(ViewEngine),就不得不说IView和IViewEngine这两个接口,要实现自定义的视图引擎就必须要实现这两个接口:
-
IView接口:IView是对MVC结构中View对象的抽象,此接口只有一个方法:void Render(ViewContext viewContext, TextWriter writer);Render方法将页面HTML写入到Writer中供浏览器显示;
-
IViewEngine接口:IViewEngine接口的职责是寻找View对象,编写自己的视图引擎时可以继承自IViewEngine并重写该类的FindView和FindPartialView方法,这两个方法返回一个ViewEngineResult表示搜索结果。
ASP.NET MVC提供了两个实现了IViewEngine接口的类:VirtualPathProviderViewEngine和WebFormViewEngine。VirtualPathProviderViewEngine类实现了FindView和FindPartialView这两个方法,用于根据指定的路径和格式来搜索页面文件,并且提供了Cache机制来缓存数据(由于使用的是ASP.NET Cache,依赖于HttpContext,所以无法在WebService或WCF项目中使用)。
VirtualPathProviderViewEngine寻找页面的时候,具体从哪些路径下进行寻找其实是根据该类中的这三个属性来决定的:MasterLocationFormats、ViewLocationFormats、PartialViewLocationFormats,修改这三个属性可以给我们的视图引擎分配自定义的搜索路径和文件格式。
对视图引擎的介绍和分析可以参考以下两篇文章:
从零开始学习 ASP.NET MVC 1.0 (五) ViewEngine 深入解析与应用实例
最简单的方法为Mvc程序实现换肤功能
NopCommerce代码分析
NopCommerce定义了自己的试图引擎ThemeableRazorViewEngine,该类的MasterLocationFormats、ViewLocationFormats、PartialViewLocationFormats三个属性指定了寻找视图文件的位置,如下:
ViewLocationFormats = new[] { //themes "~/Themes/{2}/Views/{1}/{0}.cshtml", "~/Themes/{2}/Views/{1}/{0}.vbhtml", "~/Themes/{2}/Views/Shared/{0}.cshtml", "~/Themes/{2}/Views/Shared/{0}.vbhtml", //default "~/Views/{1}/{0}.cshtml", "~/Views/{1}/{0}.vbhtml", "~/Views/Shared/{0}.cshtml", "~/Views/Shared/{0}.vbhtml", //Admin "~/Administration/Views/{1}/{0}.cshtml", "~/Administration/Views/{1}/{0}.vbhtml", "~/Administration/Views/Shared/{0}.cshtml", "~/Administration/Views/Shared/{0}.vbhtml", };
可以看出除了默认的在View目录下搜索视图以外,NopCommerce还会在Theme目录和Administration目录下搜索视图;Theme目录下的视图用于提供主题机制,此处不作深入讨论;Administration目录就是我们的后台项目的目录,这也是为什么Administration这个工程目录要放在Nop.Web这个目录里面的原因。
NopCommerce没有实现自己的IView接口,ThemeableRazorViewEngine类的CreateView/CreatePartialView直接调用了Razor引擎,如下:
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath) { string layoutPath = masterPath; var runViewStartPages = true; IEnumerable<string> fileExtensions = base.FileExtensions; return new RazorView(controllerContext, viewPath, layoutPath, runViewStartPages, fileExtensions); }
ThemeableRazorViewEngine类继承ThemeableBuildManagerViewEngine,ThemeableBuildManagerViewEngine类继承ThemeableVirtualPathProviderViewEngine,ThemeableVirtualPathProviderViewEngine类继承VirtualPathProviderViewEngine,在ThemeableVirtualPathProviderViewEngine类中实现了自定义的搜索视图的方法FindView/FindPartialView,对admin area作了特殊的处理,如下:
//little hack to get nop's admin area to be in /Administration/ instead of /Nop/Admin/ or Areas/Admin/ if (!string.IsNullOrEmpty(areaName) && areaName.Equals("admin", StringComparison.InvariantCultureIgnoreCase)) { //admin area does not support mobile devices if (mobile) { searchedLocations = new string[0]; return string.Empty; } var newLocations = areaLocations.ToList(); newLocations.Insert(0, "~/Administration/Views/{1}/{0}.cshtml"); newLocations.Insert(0, "~/Administration/Views/{1}/{0}.vbhtml"); newLocations.Insert(0, "~/Administration/Views/Shared/{0}.cshtml"); newLocations.Insert(0, "~/Administration/Views/Shared/{0}.vbhtml"); areaLocations = newLocations.ToArray(); }