EPiServer - How to create gui plugins using MVC

Introduction

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.

MyPluginController.cs

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

namespace Alloy.AdminTools.MyPlugin
{
    [GuiPlugIn(
        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

ViewModel.cs

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

Nothing special, just one string property :)

Index.cshtml

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

<p>@Model.Text</p>

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.

CustomRouteInitialization.cs

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

namespace Alloy.AdminTools.MyPlugin.Initialization
{
    [InitializableModule]
    public class CustomRouteInitialization : IInitializableModule
    {
        public void Initialize(InitializationEngine context)
        {
            RouteTable.Routes.MapRoute(
                null,
                "custom-plugins/my-plugin",
                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