World is now on Opti ID! Learn more


Feb 20, 2014
  3078
(0 votes)

Upgrade to EPiServer Commerce 7.5 : Part 2– MVC Areas Support For EPiServer 7 & above

In our company, we have a cms project framework that built on top of EPiServer CMS using asp.net MVC 4. This acts as a starting project for many of our EPiServer CMS projects consisting a lot included features, with many template blocks. However, when building Commerce or Relate project on top of our CMS project, we always wanted to separate the code base so that these pages, blocks and all the components are not in the same place as the CMS components. Therefore, implementing MVC Areas was kind of the best solution for this. This however is not yet supported on EPiServer 7  & Above.
Nevertheless, as a saying “There is always a way”, one of our senior team member  came up with the solution using a custom view engine. We saw on the forum mentioning that it may be an over-killed idea, but when actually implement it, it rather quite straightforward. It gives you a lot more flexibility in handling your project structure.


Here is the structure that we wanted:

clip_image001

Here is the magic bit of code that we used on our custom View engine to achieve the above:

public class NitecoViewEngine : RazorViewEngine
    {
        public NitecoViewEngine()
        {
            ViewLocationFormats = new[]
                                      { 
                                          "~/Areas/%1/Views/{1}/{0}.cshtml",
                                          "~/Areas/%1/Views/{1}/{0}.vbhtml",
                                           "~/Areas/%1/Views/" + Constants.ViewPath.PaymentMethodsFolder +  "/{1}/{0}.cshtml",
                                          "~/Areas/%1/Views/" + Constants.ViewPath.PaymentMethodsFolder +  "/{1}/{0}.vbhtml",
                                          "~/Areas/%1/Views/Shared/{0}.cshtml",
                                          "~/Areas/%1/Views/Shared/{0}.vbhtml",
                                          "~/Areas/%1/Views/{1}/{0}.cshtml",
                                          "~/Areas/%1/Views/{1}/{0}.vbhtml",
                                          "~/Areas/%1/Views/Shared/{0}.cshtml",
                                          "~/Areas/%1/Views/Shared/{0}.vbhtml"
                                      };
 
            MasterLocationFormats = new[]
                                        { 
                                            "~/Areas/%1/Views/{1}/{0}.cshtml",
                                            "~/Areas/%1/Views/{1}/{0}.vbhtml",
                                            "~/Areas/%1/Views/Shared/{0}.cshtml",
                                            "~/Areas/%1/Views/Shared/{0}.vbhtml",
                                            "~/Areas/%1/Views/{1}/{0}.cshtml",
                                            "~/Areas/%1/Views/{1}/{0}.vbhtml",
                                            "~/Areas/%1/Views/Shared/{0}.cshtml",
                                            "~/Areas/%1/Views/Shared/{0}.vbhtml"
                                        };
 
            PartialViewLocationFormats = new[]
                                             { 
                                                 "~/Views/Shared/" + Constants.ViewPath.BlockFolder + "/{0}.cshtml",
                                                 "~/Views/Shared/" + Constants.ViewPath.BlockFolder + "/{0}.vbhtml",
                                                 "~/Views/Shared/" + Constants.ViewPath.PaymentMethodsFolder + "/{0}.cshtml",
                                                 "~/Views/Shared/" + Constants.ViewPath.PaymentMethodsFolder + "/{0}.vbhtml",
                                                 "~/Views/Shared/" + Constants.ViewPath.PagePartialsFolder + "/{0}.cshtml",
                                                 "~/Views/Shared/" + Constants.ViewPath.PagePartialsFolder + "/{0}.vbhtml",
                                                 "~/Views/Shared//{0}.cshtml",                                             
                                                 "~/Areas/%1/Views/{1}/{0}.cshtml",
                                                 "~/Areas/%1/Views/{1}/{0}.vbhtml",
                                                 "~/Areas/%1/Views/Shared/{0}.cshtml",
                                                 "~/Areas/%1/Views/Shared/{0}.vbhtml",
                                                 "~/Areas/%1/Views/{1}/{0}.cshtml",
                                                 "~/Areas/%1/Views/{1}/{0}.vbhtml",
                                                 "~/Areas/%1/Views/Shared/{0}.cshtml",
                                                 "~/Areas/%1/Views/Shared/{0}.vbhtml",
                                                 "~/Areas/%1/Views/Shared/" + Constants.ViewPath.BlockFolder + "/{0}.cshtml",
                                                 "~/Areas/%1/Views/Shared/" + Constants.ViewPath.BlockFolder + "/{0}.vbhtml",
                                                 "~/Areas/%1/Views/Shared/" + Constants.ViewPath.PaymentMethodsFolder + "/{0}.cshtml",
                                                 "~/Areas/%1/Views/Shared/" + Constants.ViewPath.PaymentMethodsFolder + "/{0}.vbhtml",
                                                 "~/Areas/%1/Views/Shared/" + Constants.ViewPath.PagePartialsFolder + "/{0}.cshtml",
                                                 "~/Areas/%1/Views/Shared/" + Constants.ViewPath.PagePartialsFolder + "/{0}.vbhtml",
                                                        "~/Views/Shared/DisplayTemplates/{0}.cshtml",
                                                "~/Views/Shared/DisplayTemplates/{0}.vbhtml",
                                                "~/Views/Shared/DisplayTemplates/{1}/{0}.cshtml",
                                                 "~/Views/Shared/DisplayTemplates/{1}/{0}.vbhtml"
 
                                             };
        }
 
        protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
        {
            var areaName = this.GetAreaFromNameSpace(controllerContext);
            return base.CreatePartialView(controllerContext, partialPath.Replace("%1", areaName));
        }
 
        protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
        {
            var areaName = this.GetAreaFromNameSpace(controllerContext);
            return base.CreateView(controllerContext, viewPath.Replace("%1", areaName), masterPath.Replace("%1", areaName));
        }
 
        protected override bool FileExists(ControllerContext controllerContext, string virtualPath)
        {
            var areaName = this.GetAreaFromNameSpace(controllerContext);
 
            if (!string.IsNullOrEmpty(areaName))
            {
                return base.FileExists(controllerContext, virtualPath.Replace("%1", areaName));
            }
 
            return base.FileExists(controllerContext, virtualPath);
        }
 
        private string GetAreaFromNameSpace(ControllerContext controllerContext)
        {
            if (controllerContext.Controller != null)
            {
                var nameSpace = controllerContext.Controller.GetType().Namespace ?? string.Empty;
                var namespaceSegments = nameSpace.Split('.');
                if (namespaceSegments.Length >= 2)
                {
                    for (var i =0; i < namespaceSegments.Length; i++)
                    {
                        if ((namespaceSegments[i] == "Controllers") && i > 0)
                        {
                            return namespaceSegments[i-1];
                        }
                    }
                }
            }
 
            return null;
        }
    }



You then need to register this view engine on initialize module , as below:

[ModuleDependency(typeof (InitializationModule))]
    public class CustomizedRenderingInitialization : IInitializableModule
    {
        public void Initialize(InitializationEngine context)
        {            
            ViewEngines.Engines.Insert(0, new NitecoViewEngine());          
        }
    }
}

Now you could add any part of the project that you want to separate from the other areas, like how we did we our EPiServer Commerce Project as above.Just need to make sure that you keep the correct consistent naming for all the namespaces within the areas. This works for both EPiServer 7 & EPiServer 7.5 as we have examined.

Happy coding , stay tune for the next part.

Feb 20, 2014

Comments

Please login to comment.
Latest blogs
Make Global Assets Site- and Language-Aware at Indexing Time

I had a support case the other day with a question around search on global assets on a multisite. This is the result of that investigation. This co...

dada | Jun 26, 2025

The remote server returned an error: (400) Bad Request – when configuring Azure Storage for an older Optimizely CMS site

How to fix a strange issue that occurred when I moved editor-uploaded files for some old Optimizely CMS 11 solutions to Azure Storage.

Tomas Hensrud Gulla | Jun 26, 2025 |

Enable Opal AI for your Optimizely products

Learn how to enable Opal AI, and meet your infinite workforce.

Tomas Hensrud Gulla | Jun 25, 2025 |

Deploying to Optimizely Frontend Hosting: A Practical Guide

Optimizely Frontend Hosting is a cloud-based solution for deploying headless frontend applications - currently supporting only Next.js projects. It...

Szymon Uryga | Jun 25, 2025

World on Opti ID

We're excited to announce that world.optimizely.com is now integrated with Opti ID! What does this mean for you? New Users:  You can now log in wit...

Patrick Lam | Jun 22, 2025

Avoid Scandinavian Letters in File Names in Optimizely CMS

Discover how Scandinavian letters in file names can break media in Optimizely CMS—and learn a simple code fix to automatically sanitize uploads for...

Henning Sjørbotten | Jun 19, 2025 |