GPG*_*GVM 4 c# nopcommerce asp.net-mvc-4
我一直在读Wooncherk,Twisted Whisperer和Alex Wolf的一些非常好的帖子.他们的文章分别(Wooncherk),(Twisted Whisperer)和(Alex Wolf)提供了非常丰富的信息,但是我不像其他SO社区那样聪明,也不能把我所缺少的东西拼凑起来.
我正在覆盖管理区域中的核心视图...特别是订单编辑视图.我看到的行为,它并不打控制器我的插件,但它DOES显示我的自定义视图.问题是自定义视图在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<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 = 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);
}
Run Code Online (Sandbox Code Playgroud)
路由提供者请参阅注释 尝试覆盖核心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;
}
}
Run Code Online (Sandbox Code Playgroud)
我得到了404错误并仔细阅读了Twisted Whisperer他(我认为他)说:
例如,如果您要覆盖Nop.Admin/Views/Category/Tree.cshtml,请将自定义Tree.cshtml放在Nop.Admin/CustomExtension/Views/Category/Tree.cshtml中
好吧,如果我按字面意思解释我会在CORE ADMIN项目中执行此操作:

我显然做到了这一点,它起作用了......有点儿.
总而言之,我的问题是:
插件中的我的订单覆盖控制器没有被击中....(对使用ActionFilters不感兴趣,因为他们没有给我我需要的东西......我不认为).
我的插件中的视图没有被点击但添加到管理项目的视图被点击了吗?
与2.有些相关如果两个是正确的那么这是一个可行的插件解决方案?对于生产推送,更新等,我可能不得不触及NopCommerce核心项目....那么为什么要打扰插件呢?
现在NOP人和SO社区都比我更聪明,所以我确定我不理解.
如果我正确地阅读了您的问题,那么您正在创建一个插件并尝试在此插件中执行所有测试,而无需触及核心管理文件.然后你必须将所有这些文件放在你的插件项目中而不是Nop.Admin中
从它的外观来看,您将覆盖控制器和后端视图(管理区域).您引用的SO帖子我的答案仅适用于覆盖管理员视图,而不是控制器.管理区域中的覆盖控制器与覆盖视图不同,如果您覆盖前端的控制器(假设涉及SEO友好URL),则更加不同.
覆盖Controller本质上要求ASP.NET MVC使用您的自定义Controller来代替原始Controller来处理请求.请求通过路由指向控制器.因此,覆盖Controller只是简单地操作路由以将请求定向到自定义控制器.
ASP.NET MVC保留了一个包含Routes的通用查找表,称为RouteTable.Routes.路线包含的数据
每次有传入请求时,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
}
Run Code Online (Sandbox Code Playgroud)
如您所见,区域路径始终首先注册,因此具有最高优先级.因此,在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;
}
}
Run Code Online (Sandbox Code Playgroud)
这是为了覆盖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");
Run Code Online (Sandbox Code Playgroud)
您实际上可以删除CustomViewEngine的构造函数.如果在GetPath方法中有上面两行,则不需要构造函数.