EPiServer - How to create gui plugins using MVC


EPiServer CMS Visual Extension allows developers to create GUI Plugins based on WebForms. Unfortunately, there's no MVC support.

I also don't like the idea of having all controllers inside the controllers folder, all views inside the views folders, etc. I prefer more modular approach.

This is how my project structure looks like:

In this blog post, I'll be using Alloy project and EPiServer CMS version 9.6.


using System.Web.Mvc;
using Alloy.AdminTools.MyPlugin.ViewModels;
using EPiServer.PlugIn;

namespace Alloy.AdminTools.MyPlugin
        Area = PlugInArea.AdminMenu,
        Url = "/custom-plugins/my-plugin",
        DisplayName = "My Plugin")]
    [Authorize(Roles = "CmsAdmins")]
    public class MyPluginController : Controller
        public ActionResult Index()
            var model = new MyViewModel { Text = "Lorem Ipsum Dolor" };
            return View("~/AdminTools/MyPlugin/Views/Index.cshtml", model);

You should decorate controllers with Authorize attribute because users can skip the admin interface and access it directly by visiting yourdomain/custom-plugins/my-plugin

Since the view is stored at custom location, we need to provide the full path when returning a view: ~/AdminTools/MyPlugin/Views/Index.cshtml


namespace Alloy.AdminTools.MyPlugin.ViewModels
    public class MyViewModel
        public string Text { get; set; } 

Nothing special, just one string property :)


@inherits System.Web.Mvc.WebViewPage<Alloy.AdminTools.MyPlugin.ViewModels.MyViewModel>
    Layout = null;


Since the view is stored at the non-standard location, it has to inherit System.Web.Mvc.WebViewPage<T>

Other solutions would be to c/p web.config file from standard Views folders into the custom one, or the create your own view engine, but I prefer this approach.


using System.Web.Mvc;
using System.Web.Routing;
using EPiServer.Framework;
using EPiServer.Framework.Initialization;

namespace Alloy.AdminTools.MyPlugin.Initialization
    public class CustomRouteInitialization : IInitializableModule
        public void Initialize(InitializationEngine context)
                new { controller = "MyPlugin", action = "Index" });

        public void Uninitialize(InitializationEngine context)

When we created MyPluginController, we had to specify the Url for GuiPlugIn attribute.

There are three ways to register a custom route: initialization module, attribute routing, global.asax.cs

I prefer to use attribute routing, but if my plugin will be used in many other projects (nuget package), and I'm not sure if attribute routing is enabled, then InitializableModule is a safe bet.

Admin mode

And this is how our GUI plugin looks in action :)

comments powered by Disqus