非常接近,但不能完全覆盖核心视图nopcommerce

我一直在读Wooncherk , Twisted Whisperer和Alex Wolf的一些非常好的post。 他们的文章分别(Wooncherk) , (Twisted Whisperer)和(Alex Wolf)提供了非常丰富的信息,但是我不像其他SO社区那样聪明,也不能把我所缺少的东西拼凑起来。

我正在覆盖管理区域中的核心视图…特别是订单编辑视图。 我看到的行为是它没有点击我的插件中的控制器,但它显示我的自定义视图。 问题是自定义视图在Admin项目中,这真让我感到困惑。 如何拥有自包含的插件,但必须将我的自定义视图安装到核心管理区域?

我想,也许是错误的,会发生的事情是,由于我更高的定义优先级,我的控制器会在搜索路径时首先被击中。

所以遵循这里的指示是我的代码。

CustomViewEngine:


private readonly string[] _emptyLocations = null; public CustomViewEngine() { PartialViewLocationFormats = new[] { "~/Administration/MyExtension/Views/{1}/{0}.cshtml", "~/Administration/MyExtension/Views/Shared/{0}.cshtml" }; ViewLocationFormats = new[] { "~/Administration/MyExtension/Views/{1}/{0}.cshtml", "~/Administration/MyExtension/Views/Shared/{0}.cshtml" }; } protected override 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"); //Insert your custom View locations to the top of the list to be given a higher precedence newLocations.Insert(0, "~/Administration/MyExtension/Views/{1}/{0}.cshtml"); newLocations.Insert(0, "~/Administration/MyExtension/Views/Shared/{0}.cshtml"); areaLocations = newLocations.ToArray(); } bool flag = !string.IsNullOrEmpty(areaName); List 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 = CreateCacheKey(cacheKeyPrefix, name, flag2 ? string.Empty : controllerName, areaName, theme); if (useCache) { var cached = ViewLocationCache.GetViewLocation(controllerContext.HttpContext, key); if (cached != null) { return cached; } } if (!flag2) { return GetPathFromGeneralName(controllerContext, viewLocations, name, controllerName, areaName, theme, key, ref searchedLocations); } return GetPathFromSpecificName(controllerContext, name, key, ref searchedLocations); } 

路由提供者请参阅注释 尝试覆盖核心URL~ / Admin / Order / Edit / 1


 public void RegisterRoutes(RouteCollection routes) { ViewEngines.Engines.Insert(0, new CustomViewEngine()); //the articles above did NOT mention adding a path but it seemed like I needed to in order for my override path to be included??? routes.MapRoute("Plugin...OrderDetailsOverride", "Order/Edit/{id}", new { controller = "MyOrder", action = "Edit" }, new { id = @"\d+" }, new[] { "MyPlugin.Controllers" } ); } public int Priority { get { return 1; } } 

我得到了一个404错误并仔细阅读了Twisted Whisperer他(我认为他)说:

例如,如果要覆盖Nop.Admin / Views / Category / Tree.cshtml,请将自定义Tree.cshtml放在Nop.Admin / CustomExtension / Views / Category / Tree.cshtml中

好吧,如果我按字面意思解释我会在CORE ADMIN项目中执行此操作:

在此处输入图像描述

我显然做到了这一点,它起作用了……有点儿。

总而言之,我的问题/问题是:

  1. 插件中的我的订单覆盖控制器没有被击中….(对使用ActionFilters不感兴趣,因为他们没有给我我需要的东西……我不认为)。

  2. 我的插件中的视图没有被点击,但添加到管理项目的视图被点击了吗?

  3. 与2.有些相关如果两个是正确的,那么这是一个可行的插件解决方案? 对于生产推送,更新等,我可能不得不触及NopCommerce核心项目….那么为什么还要插入一个插件呢?

现在NOP人和SO社区都比我更聪明,所以我确定我不理解。

如果我正确地阅读了您的问题,那么您正在创建一个插件并尝试在此插件中执行所有测试,而不会触及核心管理文件。 然后你必须将所有这些文件放在你的插件项目而不是Nop.Admin中

从它的外观来看,您将覆盖后端的ControllerView (管理区域)。 您引用的SOpost我的答案仅适用于覆盖管理员视图 ,而不是控制器 。 管理区域中的覆盖控制器与覆盖视图不同,如果您要覆盖前端的控制器 (假设涉及SEO友好URL),则更加不同。

覆盖Controller本质上是要求ASP.NET MVC使用您的自定义Controller来代替原始Controller来处理请求。 请求通过路由指向控制器。 因此,覆盖Controller只是简单地操作路由以将请求定向到自定义控制器。

ASP.NET MVC保留了一个包含Routes的通用查找表,称为RouteTable.Routes 。 路由包含数据

  1. url格式
  2. 哪个Controller将传入的请求转发给

每次有传入请求时,ASP.NET MVC将从上到下搜索RouteTable.Routes ,以查找URL模式与请求的URL匹配的路由。 第一个匹配路由将用于将请求定向到匹配路由的Controller 。 表中可能有几条匹配的路线,但只会使用第一条路线。 因此,我们可以说表格顶部的路线具有最高优先级。 因此,覆盖现有Controller的关键是确保指向自定义Controller的路由早于指向原始Controller的路由注册

在nopCommerce中,您无需直接操作RouteTable.Routes查找表。 通常,您只需在实现IRouteProvider接口的类的RegisterRoutes方法中注册自定义Controller路由,其优先级高于原始Controller路由(不适用于SEO友好URL区域路由)。 优先级越高,路由注册越早,因此它将在查找表中定位得越高。 但是,nopCommerce的后端实际上是一个名为Admin的ASP.NET MVC区域。 这个事实使得以常规方式覆盖路线变得棘手。 这是因为,在global.asax中

 //global.asax protected void Application_Start() { //.... Omitted for brevity //Registering some regular mvc stuff //The two lines below populate the RouteTable.Routes AreaRegistration.RegisterAllAreas(); //add Area routes into the lookup table first such as the "Admin" area RegisterRoutes(RouteTable.Routes); //followed by adding routes of classes implementing **IRouteProvider** //.... Omitted for brevity } 

如上所示,区域路径始终首先注册,因此具有最高优先级。 因此,在IRouteProvider中 ,无论您设置优先级有多高,它仍然会低于区域路径。 因此,您必须直接操作RouteTable.Routes 。 在您的IRouteProvider中

 public void RegisterRoutes(RouteCollection routes) { ViewEngines.Engines.Insert(0, new CustomViewEngine()); var route = routes.MapRoute("Plugin...OrderDetailsOverride", "Admin/Order/Edit/{id}", new { controller = "MyOrder", action = "Edit" area = "Admin" }, //notice 'area="Admin"' is added new { id = @"\d+" }, new[] { "MyPlugin.Controllers" } ); routes.remove(route); //remove your route from the RouteTable.Routes routes.insert(0, route); //only to add it back again to the top of RouteTable.Routes, above all the routes that have been registered earlier } public int Priority { get { return 1; } } 

这是为了覆盖Controller 。 现在要重写View 。 轻微调整CustomViewEngine (确保您的CustomViewEngine在您的插件中,而不是在Nop.Admin中)

 //Insert your custom View locations to the top of the list to be given a higher precedence newLocations.Insert(0, "~/Plugins/MyPlugin/Views/Admin/{1}/{0}.cshtml"); newLocations.Insert(0, "~/Plugins/MyPlugin/Views/Admin/Shared/{0}.cshtml"); 

您实际上可以删除CustomViewEngine的构造函数 。 如果GetPath方法中有上面两行,则GetPath

最重要的是让控制器命中,其他东西需要一些调整。

  1. 路由未正确覆盖,请参阅http://www.nopcommerce.com/boards/t/27039/plugin-override-admin-route.aspx

  2. 由于路径设置为自定义视图位置,因此使用admin项目中的视图: 〜/ Administration / MyExtension / Views 。 NopCommerce不知道插件中嵌入了哪些视图。

  3. 对于基于插件的解决方案,请确保CustomViewEngineRouteProvider和视图位于插件中。 确保将视图复制到输出目录。 将插件中视图的输出文件夹注册为自定义视图位置,例如〜/ Plugins / MyPlugin / Views / Admin