【发布时间】:2013-06-23 16:48:08
【问题描述】:
我正在尝试覆盖位于以下位置的 nopcommerce 视图:
Nop.Admin/Views/Category/Tree.cshtml
使用我在插件文件夹中开发的视图:
Views/Misc/Tree.cshtml
我该怎么做?
【问题讨论】:
标签: c# asp.net-mvc-4 nopcommerce
我正在尝试覆盖位于以下位置的 nopcommerce 视图:
Nop.Admin/Views/Category/Tree.cshtml
使用我在插件文件夹中开发的视图:
Views/Misc/Tree.cshtml
我该怎么做?
【问题讨论】:
标签: c# asp.net-mvc-4 nopcommerce
【讨论】:
http://imgur.com/AJgSrnt.jpg,它确认我的自定义视图具有最低优先级。
~/Themes/MyTheme/Views/WidgetsNivoSlider/Nop.Plugin.Widgets.NivoSlider.Views.WidgetsNivoSlider.PublicInfo.cshtml)
@Html.Partial 吗?你能回答我的post吗?
@wooncherk 的自定义视图引擎非常适合让我们的视图在未来被轻松覆盖。然而,在覆盖现有核心视图时它还不够,因为 nopCommerce 将管理视图放在首位,而不是我们的自定义视图。这可以在Nop.Web.Framework.Themes.ThemeableVirtualPathProviderViewEngine.cs 的虚方法GetPath() 中看到。对于那些想知道的人,ThemeableVirtualPathProviderViewEngine 是由ThemeableRazorViewEngine 继承的类,而后者又由@wooncherk 的CustomViewEngine 类继承。
参考上面ThemeableVirtualPathProviderViewEngine 上的屏幕截图,如箭头所示,这两行确认管理视图总是比我们的自定义视图具有更高的优先级
我设法扩展了@wooncherk 的自定义视图引擎方法,以适应覆盖现有的管理核心视图。这涉及覆盖虚拟方法GetPath() 并将其复制到CustomViewEngine 类中。此时删除两个 culprit 行甚至整个 little hack 代码块似乎是合乎逻辑的,但不要这样做,它会导致异常
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[Nop.Admin.Models.Cms.RenderWidgetModel]', but this dictionary requires a model item of type 'System.Collections.Generic.List`1[Nop.Web.Models.Cms.RenderWidgetModel]'.
新的CustomViewEngine 如下:
public class CustomViewEngine: ThemeableRazorViewEngine {
private readonly string[] _emptyLocations = null;
public CustomViewEngine() {
PartialViewLocationFormats = new[] {
"~/Administration/CustomExtension/Views/{1}/{0}.cshtml",
"~/Administration/CustomExtension/Views/Shared/{0}.cshtml"
};
ViewLocationFormats = new[] {
"~/Administration/CustomExtension/Views/{1}/{0}.cshtml",
"~/Administration/CustomExtension/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/CustomExtension/Views/{1}/{0}.cshtml");
newLocations.Insert(0, "~/Administration/CustomExtension/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);
}
}
请注意,罪魁祸首行下方添加了两行,以赋予我们的自定义视图更高的优先级。
最后,我们需要修改RouteProvider.cs
public class RouteProvider : IRouteProvider {
public void RegisterRoutes(RouteCollection routes) {
//Insert our CustomViewEngine into the top of the System.Web.Mvc.ViewEngines.Engines Collection to be given a higher precedence
System.Web.Mvc.ViewEngines.Engines.Insert(0, new CustomViewEngine());
}
public int Priority {
get {
return 1;
}
}
}
就是这样。现在将您的自定义视图/部分视图放入视图位置,在这种情况下,它们是
~/Administration/CustomExtension/Views/{1}/{0}.cshtml
~/Administration/CustomExtension/Views/Shared/{0}.cshtml
其中 {1} 是您要覆盖的控制器的名称,而 {0} 是您要覆盖的视图/部分视图的名称。
例如,如果您要覆盖Nop.Admin/Views/Category/Tree.cshtml,请将您的自定义Tree.cshtml 放在Nop.Admin/CustomExtension/Views/Category/Tree.cshtml 中。
【讨论】:
index.cshtml 都重命名为index_bak.cshtml。刷新页面,应该会抛出异常。注意正在搜索订单视图。管理员视图应始终位于顶部。
Twisted Whisper 有正确的答案,但我想我会分享一个博客文章的链接,该文章更深入地讨论了这个问题(更多地讨论了自定义视图引擎的工作原理以及使用这种技术的其他优点):
【讨论】: