How to override a nopcommerce view file with a view file inside the plugin?

北慕城南 提交于 2019-12-23 12:45:00

问题


I am trying to override the nopcommerce View that is located in:

Nop.Admin/Views/Category/Tree.cshtml  

with a view that I have developed in my plugin folder:

Views/Misc/Tree.cshtml

How can I do it?


回答1:


Try this detailed article I've written: 3 Ways to Display Views in Your nopCommerce Plugins (Embedded Resource, Theme Override and Custom View Engine)




回答2:


@wooncherk's Custom View Engine is excellent in preparing our Views to be overriden with ease in the future. However it falls short when it comes to overriding existing core Views because nopCommerce gives Administration Views top priority than our custom Views. This can be seen in the virtual method GetPath() of Nop.Web.Framework.Themes.ThemeableVirtualPathProviderViewEngine.cs. For those who is wondering, ThemeableVirtualPathProviderViewEngine is the class inherited by ThemeableRazorViewEngine which in turn inherited by @wooncherk's CustomViewEngine class.

Referring to the screenshot above on ThemeableVirtualPathProviderViewEngine, as pointed out by the arrows, the two lines confirmed that Administration Views are always given higher precedence than our custom Views

I managed to extend @wooncherk's Custom View Engine method to also cater for overriding existing Administration core Views. This involves overriding and copying over the virtual method GetPath() into the CustomViewEngine class. At this point it seems logical to remove the two culprit lines or even the entire little hack code block, but don't, it will result in an exception

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]'.

The new CustomViewEngine will be as follows:

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);
    }
}

Note that two lines are added below the culprit lines to give our custom Views higher precedence.


Finally, we need to modify the 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;
        }
    }
}

That's about it. Now place your custom Views/Partial Views into the View Locations, in this case they are

~/Administration/CustomExtension/Views/{1}/{0}.cshtml
~/Administration/CustomExtension/Views/Shared/{0}.cshtml

whereby {1} is the name of the Controller you are overriding and {0} is the name of the View/Partial View you are overrding.

For example, if you are overrding Nop.Admin/Views/Category/Tree.cshtml, place your custom Tree.cshtml in Nop.Admin/CustomExtension/Views/Category/Tree.cshtml.




回答3:


Twisted Whisper has the correct answer but I thought I would share a link to a blog post that discusses this more in depth (talks more about how the custom view engine works and other advantages of using this technique) seen here:

Click here for In Depth Discussion Post



来源:https://stackoverflow.com/questions/17321898/how-to-override-a-nopcommerce-view-file-with-a-view-file-inside-the-plugin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!