Where to register custom view engine in Nop 4.0?

2 years ago
Hi,

Normally I would register a custom view engine in the
RegisterRoutes
class like this:
System.Web.Mvc.ViewEngines.Engines.Insert(0,new MyViewEngine());


But because of the new .NET Core architecture, this isn't possible anymore.

To add a new view engine in .NET Core I found the following snippet, which has to be in the
Startup.cs
file:


        public void ConfigureServices(IServiceCollection services)  
        {  
            //register the MyViewLocationExpander into ViewLocationExpanders  
            services.Configure<RazorViewEngineOptions>(o => {  
                o.ViewLocationExpanders.Add(new MyViewLocationExpander());  
            });  
  
            // Add framework services.  
            services.AddMvc();  
        }  


Because I want to add the view engine inside my Plugin, I tried to get the
IServiceCollection
inside my
RegisterRoutes
class. Unfortunately, this is not working (
IServiceCollection
is null).

Can anyone tell me where and how I can add the view engine?

Thanks for your help.
2 years ago
I also want to do this so I can add ProtoBuf media formatters for my API

Any help?
2 years ago
I wonder if the IVewLocationExpander interface might be the place to look.  But I don't see anywhere in their code where we can inject our own expander.  They've hard coded to ThemableViewLocationExpander
2 years ago
Here's what I use to override the OpcShippingMethods view -

NopStartup.cs (Nop engine finds all classes implementing INopStartup and executes them on startup)


using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Nop.Core.Infrastructure;
using Microsoft.AspNetCore.Mvc.Razor;

namespace Nop.Plugin.Shipping.CustomRate
{

    public class NopStartup : INopStartup
    {

        public void ConfigureServices(IServiceCollection services, IConfigurationRoot configuration)
        {
            services.Configure<RazorViewEngineOptions>(options =>
            {
                options.ViewLocationExpanders.Add(new ViewLocationExpander());
            });
        }

        public void Configure(IApplicationBuilder application)
        {
        }

        public int Order
        {
            get { return 1001; } //add after nopcommerce is done
        }

    }
}




ViewLocationExpander.cs



using Microsoft.AspNetCore.Mvc.Razor;
using System.Collections.Generic;
using System.Linq;

namespace Nop.Plugin.Shipping.CustomRate
{

    public class ViewLocationExpander : IViewLocationExpander
    {

        public void PopulateValues(ViewLocationExpanderContext context)
        {
        }

        public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
        {

            if (context.AreaName == null && context.ControllerName == "Checkout" && context.ViewName == "OpcShippingMethods")
            {
                viewLocations = new string[] { $"/Plugins/Shipping.CustomRate/Views/{{0}}.cshtml" }.Concat(viewLocations);
            }

            return viewLocations;

        }
    }
}


2 years ago
Thanks, this was helpful.

One question, can you help me understand why the use of interpolated strings here:
timmit wrote:
viewLocations = new string[] { $"/Plugins/Shipping.CustomRate/Views/{{0}}.cshtml" }.Concat(viewLocations);


As apposed to this?

viewLocations = new string[] { "/Plugins/Shipping.CustomRate/Views/{0}.cshtml" }.Concat(viewLocations);
2 years ago
That is feature of core

It's working same as string.Format("hello my name is {0}", "Name")

In Core you can use as
$"hello my name is {{Name}}"
2 years ago
rajupaladiya wrote:
That is feature of core


Not at all, it's feature of C# 6.0
2 years ago
Thanks for the response but let me try to be more clear here.

My question was not to have explained the interpolated strings syntax introduced in C# 6.0, but rather why was it being used in the context of this example. There is no value to inject a hard coded string into another hard coded string, regardless of the syntax.

Doing this:
$"/Plugins/Shipping.CustomRate/Views/{{0}}.cshtml"


Is the same as doing this:
string.format("/Plugins/Shipping.CustomRate/Views/{0}.cshtml","0")


But why would you want to, when you can simply just have this:
"/Plugins/Shipping.CustomRate/Views/{0}.cshtml"


I think it was just a case of copy paste from the ThemeableViewLocationExpander class, where they have:
$"/Themes/{theme}/Views/{{1}}/{{0}}.cshtml"

In that case the variable theme was injected into the string, therefore, the curly brackets for the 1 and the 0 needed to be escaped.
If the entire string is hard coded, we do not need to use interpolated strings (the $ prefix) and therefore, no need to escape the curly braces.
2 years ago
You're right, I think I may have accidentally left that in there by mistake.