【问题标题】:How to override a nopcommerce view file with a view file inside the plugin?如何使用插件内的视图文件覆盖 nopcommerce 视图文件?
【发布时间】:2013-06-23 16:48:08
【问题描述】:

我正在尝试覆盖位于以下位置的 nopcommerce 视图:

Nop.Admin/Views/Category/Tree.cshtml  

使用我在插件文件夹中开发的视图:

Views/Misc/Tree.cshtml

我该怎么做?

【问题讨论】:

    标签: c# asp.net-mvc-4 nopcommerce


    【解决方案1】:

    【讨论】:

    • 我无法使用您的自定义视图引擎方法覆盖现有核心视图。除非我删除/重命名现有的核心视图,否则永远不会使用我的自定义视图。这表明我的自定义视图的优先级低于现有的核心视图。所以我决定删除/重命名我的自定义视图并刷新页面。您可以参考这里的屏幕截图http://imgur.com/AJgSrnt.jpg,它确认我的自定义视图具有最低优先级。
    • 我尝试了主题覆盖方法,但我无法使其工作(我使用给定的示例:~/Themes/MyTheme/Views/WidgetsNivoSlider/Nop.Plugin.Widgets.NivoSlider.Views.Wi‌dgetsNivoSlider.PublicInfo.cshtml
    • @wooncherk 我很接近但不太了解这个线程。请您看看stackoverflow.com/questions/26241961/… 并告诉我我错过了什么?
    • 在渲染之前会覆盖@Html.Partial 吗?你能回答我的post吗?
    【解决方案2】:

    @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 中。

    【讨论】:

    • 耳语者我很接近,但不太了解某些事情。请参考stackoverflow.com/questions/26241961/…
    • 使用 newLocations.Insert(0, "~/Plugins/CustomExtension/Views/Admin/{1}/{0}.cshtml");而不是 newLocations.Insert(0, "~/Administration/CustomExtension/Views/{1}/{0}.cshtml");
    • 我已经成功实现了 Wolf、Woon 和您讨论的方法,但我遇到了一个有趣的问题。长话短说,我的 CustomViewEngine 工作得很好,www.mysite.com 抛出一个错误,基本上是前端 WebController 试图消化管理视图(索引)。但是,当我访问 www.mysite.com/admin 时,一切都正常运行......基本上我的问题是你如何处理并发视图名称?在我的情况下 Nop.Admin/Home/Index.cshtml 和 Nop.Web/Home/Index.cshtml?
    • 这不应该抛出错误。管理是一个区域,这意味着管理视图总是首先得到解决。你是不是弄乱了路由?尝试将index.cshtml 都重命名为index_bak.cshtml。刷新页面,应该会抛出异常。注意正在搜索订单视图。管理员视图应始终位于顶部。
    • 这对 nop.web 视图也有效吗?我试图实现它,但 viewPath 和 masterPath 返回空字符串。有什么问题?
    【解决方案3】:

    Twisted Whisper 有正确的答案,但我想我会分享一个博客文章的链接,该文章更深入地讨论了这个问题(更多地讨论了自定义视图引擎的工作原理以及使用这种技术的其他优点):

    Click here for In Depth Discussion Post

    【讨论】:

    • 我希望我能早点找到你的博文。因为我对 nopCommerce 还很陌生,所以我花了几个小时才找到解决方案。
    • @alex wolf....你的帖子很有帮助,但我还是不明白。如果可以,请查看stackoverflow.com/questions/26241961/… 并让我知道我做错了什么。
    猜你喜欢
    • 1970-01-01
    • 2018-09-18
    • 1970-01-01
    • 2015-06-05
    • 2017-04-01
    • 1970-01-01
    • 2020-05-04
    • 1970-01-01
    • 2012-09-30
    相关资源
    最近更新 更多