Register Shopping cart (0)
You have no items in your shopping cart.
Free nopCommerce Hosting

3 Ways to Display Views in Your nopCommerce Plugins (Embedded Resource, Theme Override and Custom View Engine)

There has been numerous questions posted on nopCommerce forums and StackOverflow about how to make nopCommerce plugins' Views text-editeable as CSHTML files. This is because the most widely known method of displaying Views in nopCommerce is to mark the .CSHTML files as Embedded Resource, which essentially makes the Views behave like binary files (such as DLLs), which in turn makes the Views uneditable in text editors. In fact, you can't even find the CSHTML files on the compiled plugins folder!

For example, the figure below is how a compiled nopCommerce plugin looks like. You notice that there's no .CSHTML that you can edit. Why is this a bad thing? Because if you are developing an nopCommerce plugin for your clients, that means there is no easy way they can edit how the plugin renders on their shop.

Typical nopCommerce plugin files

How can we go about solving this limitation? Read on to learn!

The Original Method - "Embedded Resource"

This is the method that's most widely known by nopCommerce developers, because the official tutorials have been using this method. This method goes by making the .CSHTML file an embedded resource (shown below), and then referece it in code by its Fully-qualified Name like how we would refer to a C# Class.

nopCommerce Plugin - Marking a View as an Embedded Resource

The fully-qualified name for a View file that's been marked as Embedded Resource would be:

{default_namespace}.{view_folder_name}.{nested_sub_folder_name_if_any}.{view_name_without_cshtml_extension}

For example, the default "DiscountRules.BillingCountry" returns its "Configure" View by using the following code:

Fully-qualified Name for Views marked as Embedded Resource

The Better Method - "Theme Override"

The "Embedded Resource" method is very inflexible because you cannot edit the Views as you wish. But wait! You actually can! You can override the View in your nopCommerce Theme, and the good news is: it's very easy to do so!

Firstly, create a folder under your theme's Views folder, and name it CONTROLLER_NAME (without the trailing 'Controller'). Taking the original NivoSlider plugin as example, the folder name would be WidgetsNivoSlider because the Controller name is WidgetsNivoSliderController. Then, copy the View you want to override to your theme, and name it using the fully-qualified name (with CSHTML extension). So eventually you have a setup as follow:

The "Theme Override" method of display nopCommerce plugin views

The Advanced Method - "Custom View Engine"

The "Theme Overridge" method is a major improvement over the "Embedded Resource" method, but it does have its own downside. Because the Views is located under the Themes folder, it means that on deployment your clients have to perform 2 operations for their plugin to run: first copying the necessary plugin files to the Plugins folder, then the necessary View files to the Themes folder.

To simplify the deployment process, we can employ the third method of specifying Views for plugins, the "Custom View Engine" method. If you are familiar enough with ASP.Net MVC, you know that Razor is just an extension of the view engine architecture employed by ASP.Net MVC. In other words, we can create any other view engines just like how Microsoft created Razor!

We are, of course, not going to write a completely new view engine. But we can make use of ASP.Net MVC's extensible architecture by entending the Razor view engine to search for custom paths for Views! In fact, that's essentially how nopCommerce theming system works! I am not going to go into this part as I believe it deserve an entire blog post on its own. If you are interested, you can look at the source code, starting from Nop.Web.Framework.Themes.ThemeableVirtualPathProviderViewEngine.cs and navigate from there!

Without further ado, let's just jump into the code! Let's create a folder named ViewEngines directly under your plugin, and add a new class CustomViewEngine.cs to the folder.

Creating custom view engine in nopCommerce plugin

Then, add the following code to CustomViewEngine.cs. Make sure you replace panoRazzi.ExpressCheckout with your own namespace.

CustomViewEngine code

What this code does is that it adds additional locations for the ViewEngine to search for Views. The placeholder {0} will be replaced by your Controller's Action name.

But we are not done yet! With the new ViewEngine in place, we need to register it such that nopCommerce can pick it up! We want the new ViewEngine to be registered on Application_Start, and there are 1 class that gets called on Application_Start and is frequently used by plugins - RouteProvider.cs. Let'sadd the highlighted code to RouteProvider.cs:

Registering CustomViewEngine in RouteProvider.cs

This is actually a little hacky, but I think it doesn't matter much. Use it at your own risk though!

By the way, after adding this line of code, it means that nopCommerce will be able to pick up your CustomViewEngine as another way to render .CSHTML Views, and it'll actually search for Views in the path specified in your CustomViewEngine (together with the other paths that originally work in nopCommerce; more on this later)!

With the CustomViewEngine in place, you can now include Views in your plugins (mark it as Content instead of Embedded Resource) as shown below. Please note the web.config have to be present in the plugin's Views folder. You need to copy the same file from ~/Views folder.

Views folder of a plugin, with the CSHTML marked as Content instead of Embedded Resource

Now, in your plugin's Controller, you can use the normal way of returning Views in the Actions (no need for the fully-qualified name), such as:

Returning Views from your plugin's Action

Bonus: "Theme Override" On Top of "Custom View Engines"

Now you may ask: does "Theme Override" still work when we implement "Custom View Engines"? The answer is YES, using the same way you override "Embedded Resource" Views (only with a different View name)! Why would we want to do this? Because we want to supply our clients with default, viewable and editable set of CSHTML Views; while still allowing them to quickly copy and paste the default Views into the Themes folder and override the rendering.

Explaining using the figure below, our plugin has a default implementation of Display.cshtml (left part of the figure). If at any time the customers want to customize the rendering of Display.cshtml, they can simply copy Display.cshtml (bottom part of the figure) into ~/Themes/THEME_NAME/Views/ExpressCheckout (right part of the figure).

Using "Theme Override" with "Custom View Engine"

On the other hand, they wouldn't be able to know how the default Display.cshtml implementation is like if the View is rendered using the "Embedded Resource" method. "Theme Override" is definitely powerful when implemented together with "Custom View Engines"!

Conclusion

With a little bit of hack, we can actually implement a very powerful View-rendering mechanism for plugins, thank to the comprehensive theming architecture of nopCommerce (which is built on top of the extensible View Engine architecture of ASP.Net MVC).

If you have any question about nopCommerce theming architecture or plugin View-rendering mechanism, please feel free to leave your comments below! I'll also hopefully be able to do a lower-level analysis of nopCommerce theming architecture in the near future!

Tags

Hello, welcome to pro nopCommerce!

I am Woon Cherk, an nop mvp; and this blog is the place where I share my experiences developing nopCommerce themes and nopCommerce plugins. I also give out free nopCommerce plugins and free nopCommerce themes from time to time, make sure you subscribe to our e-mail newsletter to get updates and freebies! Click here to read more about me.