BaimuTemplate 之 前后台分离
前后台分离有很多种方式,其中在教科书中常见的是area去区分,但是这样主程序会显得很臃肿,下面提供的方法是nop中所使用的,该系列文章基本上就是分解了nop项目,把知识点应用在自己的baimuTemplate中。
1、新建一个mvc项目,取名叫“btp.web”
2、新建一个mvc项目,取名叫“adminitration”,项目路径建在btp.web中
3、修改项目administration名称为“btp.admin”,该步主要是为了名字统一,比较好看一些。
4、修改btp.admin下面所有的命名空间,并修改属性的命名空间

5、修改btp.admin项目属性,修改BIn文件的输出路径
6、在btp.admin根目录新建AdminAreaRegistration,代码如下:
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 { controller = "Home", action = "Index", area = "Admin", id = "" }, new[] { "Btp.Admin.Controllers" } ); } }
7、修改btp.web和btp.admin下面的路由配置,增加namespace


8、写一个视图引擎ThemeableVirtualPathProviderViewEngine :
public abstract class ThemeableVirtualPathProviderViewEngine : VirtualPathProviderViewEngine { #region Fields internal Func<string, string> GetExtensionThunk; private readonly string[] _emptyLocations = null; #endregion #region Ctor protected ThemeableVirtualPathProviderViewEngine() { GetExtensionThunk = new Func<string, string>(VirtualPathUtility.GetExtension); } #endregion #region Utilities protected virtual string GetPath(ControllerContext controllerContext, string[] locations, string[] areaLocations, string locationsPropertyName, string name, string controllerName, string theme, string cacheKeyPrefix, bool useCache, out string[] searchedLocations) { searchedLocations = _emptyLocations; if (string.IsNullOrEmpty(name)) { return string.Empty; } string areaName = GetAreaName(controllerContext.RouteData); //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)) { var newLocations = areaLocations.ToList(); newLocations.Insert(0, "~/Administration/Views/{1}/{0}.cshtml"); newLocations.Insert(0, "~/Administration/Views/Shared/{0}.cshtml"); areaLocations = newLocations.ToArray(); } bool flag = !string.IsNullOrEmpty(areaName); List<ViewLocation> viewLocations = GetViewLocations(locations, flag ? areaLocations : null); if (viewLocations.Count == 0) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Properties cannot be null or empty.", new object[] { locationsPropertyName })); } bool flag2 = IsSpecificPath(name); string key = this.CreateCacheKey(cacheKeyPrefix, name, flag2 ? string.Empty : controllerName, areaName, theme); if (useCache) { var cached = this.ViewLocationCache.GetViewLocation(controllerContext.HttpContext, key); if (cached != null) { return cached; } } if (!flag2) { return this.GetPathFromGeneralName(controllerContext, viewLocations, name, controllerName, areaName, theme, key, ref searchedLocations); } return this.GetPathFromSpecificName(controllerContext, name, key, ref searchedLocations); } protected virtual bool FilePathIsSupported(string virtualPath) { if (this.FileExtensions == null) { return true; } string str = this.GetExtensionThunk(virtualPath).TrimStart(new[] { '.' }); return this.FileExtensions.Contains(str, StringComparer.OrdinalIgnoreCase); } protected virtual string GetPathFromSpecificName(ControllerContext controllerContext, string name, string cacheKey, ref string[] searchedLocations) { string virtualPath = name; if (!this.FilePathIsSupported(name) || !this.FileExists(controllerContext, name)) { virtualPath = string.Empty; searchedLocations = new[] { name }; } this.ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, cacheKey, virtualPath); return virtualPath; } protected virtual string GetPathFromGeneralName(ControllerContext controllerContext, List<ViewLocation> locations, string name, string controllerName, string areaName, string theme, string cacheKey, ref string[] searchedLocations) { string virtualPath = string.Empty; searchedLocations = new string[locations.Count]; for (int i = 0; i < locations.Count; i++) { string str2 = locations[i].Format(name, controllerName, areaName, theme); if (this.FileExists(controllerContext, str2)) { searchedLocations = _emptyLocations; virtualPath = str2; this.ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, cacheKey, virtualPath); return virtualPath; } searchedLocations[i] = str2; } return virtualPath; } protected virtual string CreateCacheKey(string prefix, string name, string controllerName, string areaName, string theme) { return string.Format(CultureInfo.InvariantCulture, ":ViewCacheEntry:{0}:{1}:{2}:{3}:{4}:{5}", new object[] { base.GetType().AssemblyQualifiedName, prefix, name, controllerName, areaName, theme }); } protected virtual List<ViewLocation> GetViewLocations(string[] viewLocationFormats, string[] areaViewLocationFormats) { var list = new List<ViewLocation>(); if (areaViewLocationFormats != null) { list.AddRange(areaViewLocationFormats.Select(str => new AreaAwareViewLocation(str)).Cast<ViewLocation>()); } if (viewLocationFormats != null) { list.AddRange(viewLocationFormats.Select(str2 => new ViewLocation(str2))); } return list; } protected virtual bool IsSpecificPath(string name) { char ch = name[0]; if (ch != '~') { return (ch == '/'); } return true; } protected virtual string GetCurrentTheme() { return "DefaultClean"; } protected virtual string GetAreaName(RouteData routeData) { object obj2; if (routeData.DataTokens.TryGetValue("area", out obj2)) { return (obj2 as string); } return GetAreaName(routeData.Route); } protected virtual string GetAreaName(RouteBase route) { var area = route as IRouteWithArea; if (area != null) { return area.Area; } var route2 = route as Route; if ((route2 != null) && (route2.DataTokens != null)) { return (route2.DataTokens["area"] as string); } return null; } protected virtual ViewEngineResult FindThemeableView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) { string[] strArray; string[] strArray2; if (controllerContext == null) { throw new ArgumentNullException("controllerContext"); } if (string.IsNullOrEmpty(viewName)) { throw new ArgumentException("View name cannot be null or empty.", "viewName"); } var theme = GetCurrentTheme(); string requiredString = controllerContext.RouteData.GetRequiredString("controller"); string str2 = this.GetPath(controllerContext, this.ViewLocationFormats, this.AreaViewLocationFormats, "ViewLocationFormats", viewName, requiredString, theme, "View", useCache, out strArray); string str3 = this.GetPath(controllerContext, this.MasterLocationFormats, this.AreaMasterLocationFormats, "MasterLocationFormats", masterName, requiredString, theme, "Master", useCache, out strArray2); if (!string.IsNullOrEmpty(str2) && (!string.IsNullOrEmpty(str3) || string.IsNullOrEmpty(masterName))) { return new ViewEngineResult(this.CreateView(controllerContext, str2, str3), this); } if (strArray2 == null) { strArray2 = new string[0]; } return new ViewEngineResult(strArray.Union(strArray2)); } protected virtual ViewEngineResult FindThemeablePartialView(ControllerContext controllerContext, string partialViewName, bool useCache) { string[] strArray; if (controllerContext == null) { throw new ArgumentNullException("controllerContext"); } if (string.IsNullOrEmpty(partialViewName)) { throw new ArgumentException("Partial view name cannot be null or empty.", "partialViewName"); } var theme = GetCurrentTheme(); string requiredString = controllerContext.RouteData.GetRequiredString("controller"); string str2 = this.GetPath(controllerContext, this.PartialViewLocationFormats, this.AreaPartialViewLocationFormats, "PartialViewLocationFormats", partialViewName, requiredString, theme, "Partial", useCache, out strArray); if (string.IsNullOrEmpty(str2)) { return new ViewEngineResult(strArray); } return new ViewEngineResult(this.CreatePartialView(controllerContext, str2), this); } protected override bool FileExists(ControllerContext controllerContext, string virtualPath) { return BuildManager.GetObjectFactory(virtualPath, false) != null; } #endregion #region Methods public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) { ViewEngineResult result = FindThemeableView(controllerContext, viewName, masterName, useCache); return result; } public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache) { ViewEngineResult result = FindThemeablePartialView(controllerContext, partialViewName, useCache); return result; } #endregion } public class AreaAwareViewLocation : ViewLocation { public AreaAwareViewLocation(string virtualPathFormatString) : base(virtualPathFormatString) { } public override string Format(string viewName, string controllerName, string areaName, string theme) { return string.Format(CultureInfo.InvariantCulture, _virtualPathFormatString, viewName, controllerName, areaName, theme); } } public class ViewLocation { protected readonly string _virtualPathFormatString; public ViewLocation(string virtualPathFormatString) { _virtualPathFormatString = virtualPathFormatString; } public virtual string Format(string viewName, string controllerName, string areaName, string theme) { return string.Format(CultureInfo.InvariantCulture, _virtualPathFormatString, viewName, controllerName, theme); } }
以及ThemeableRazorViewEngine:
public class ThemeableRazorViewEngine : ThemeableVirtualPathProviderViewEngine { public ThemeableRazorViewEngine() { AreaViewLocationFormats = new[] { //themes "~/Areas/{2}/Themes/{3}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Themes/{3}/Views/Shared/{0}.cshtml", //default "~/Areas/{2}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Views/Shared/{0}.cshtml", }; AreaMasterLocationFormats = new[] { //themes "~/Areas/{2}/Themes/{3}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Themes/{3}/Views/Shared/{0}.cshtml", //default "~/Areas/{2}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Views/Shared/{0}.cshtml", }; AreaPartialViewLocationFormats = new[] { //themes "~/Areas/{2}/Themes/{3}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Themes/{3}/Views/Shared/{0}.cshtml", //default "~/Areas/{2}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Views/Shared/{0}.cshtml" }; ViewLocationFormats = new[] { //themes "~/Themes/{2}/Views/{1}/{0}.cshtml", "~/Themes/{2}/Views/Shared/{0}.cshtml", //default "~/Views/{1}/{0}.cshtml", "~/Views/Shared/{0}.cshtml", //Admin "~/Administration/Views/{1}/{0}.cshtml", "~/Administration/Views/Shared/{0}.cshtml", }; MasterLocationFormats = new[] { //themes "~/Themes/{2}/Views/{1}/{0}.cshtml", "~/Themes/{2}/Views/Shared/{0}.cshtml", //default "~/Views/{1}/{0}.cshtml", "~/Views/Shared/{0}.cshtml" }; PartialViewLocationFormats = new[] { //themes "~/Themes/{2}/Views/{1}/{0}.cshtml", "~/Themes/{2}/Views/Shared/{0}.cshtml", //default "~/Views/{1}/{0}.cshtml", "~/Views/Shared/{0}.cshtml", //Admin "~/Administration/Views/{1}/{0}.cshtml", "~/Administration/Views/Shared/{0}.cshtml", }; FileExtensions = new[] { "cshtml" }; } protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath) { IEnumerable<string> fileExtensions = base.FileExtensions; return new RazorView(controllerContext, partialPath, null, false, fileExtensions); } protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath) { IEnumerable<string> fileExtensions = base.FileExtensions; return new RazorView(controllerContext, viewPath, masterPath, true, fileExtensions); } }
并且在global中启动
//remove all view engines ViewEngines.Engines.Clear(); //except the themeable razor view engine we use ViewEngines.Engines.Add(new ThemeableRazorViewEngine());
9、修改btp.admin的views下面的_ViewStart.cshtml,
@{ Layout = "~/Administration/Views/Shared/_Layout.cshtml"; }
好了,这样就把前后台分离开了。但是发布项目的时候,前后台是在一起的,输入xx/admin就可以进入后台,但是编程的时候,是两个独立的项目

浙公网安备 33010602011771号