Hooking up to the EPiServer QuickNavigator

I’ve seen many projects in EPiServer CMS 5 and 6 where the developers has extended the Context Menu. Menu options such as enabling developer modes or shortcuts to certain tools are some of the most popular extensions.

ContextMenu

In EPiServer 7 CMS, the Context Menu has been replaced with the QuickNavigator. But unfortunately it was not compatible with the Context Menu extensions and it was quite hard coded.

QuickNavigator original

With the Release with EPiServer CMS 7.5, things started to brighten up again! Now you can register your own QuickNavigatorItemProvider.
The biggest difference is that instead of only rendering the options “Edit Mode” and “Dashboard”, the QuickNavigator now iterates through all implementations of the interface IQuickNavigatorItemProvider that is registered in EPiServer’s IoC Container.

QuickNavigator

I’ve taken a look at how to use this to implement one of the missing QuickNavigator options, the Logout button. This option will not only log you out. It will also redirect you to the page you previously watched.

The code can be seen below and also be found on GitHub.

Cut to the code!

First of all I needed to create my own implementation of the IQuickNavigatorItemProvider.

This part is quite similar to when extending the EPiServer Online Center top navigation.

Basically I copied the original implementation but changed which items I wanted to provide.

[ServiceConfiguration(typeof(IQuickNavigatorItemProvider))]
public class LogoutQuickNavigatorItemProvider: IQuickNavigatorItemProvider
{
    private readonly IContentLoader contentLoader;

    public int SortOrder
    {
        get
        {
            return 10;
        }
    }

    public LogoutQuickNavigatorItemProvider(IContentLoader contentLoader)
    {
        this.contentLoader = contentLoader;
    }

    public IDictionary<string, QuickNavigatorMenuItem> GetMenuItems(ContentReference currentContent)
    {
        var urlBuilder = new UrlBuilder("/logout");
        if (this.IsPageData(currentContent))
        {
            var urlResolver = ServiceLocator.Current.GetInstance();
            string url = urlResolver.GetUrl(currentContent);

            urlBuilder.QueryCollection.Add("ReturnUrl", url);
        }

        return new Dictionary<string, QuickNavigatorMenuItem> {
            {
                "customlogout",
                new QuickNavigatorMenuItem("/shell/cms/menu/logout", urlBuilder.ToString(), null, "true", null)
            }
        };
    }

    private bool IsPageData(ContentReference currentContentLink)
    {
        return this.contentLoader.Get(currentContentLink) is PageData;
    }
}

By using the ServiceConfigurationAttribute, I will inject my implementation of IQuickNavigatorItemProvider into the IoC container.
I’m also reusing the xpath /shell/cms/menu/logout that is the xpath for the term “Log out” used in Online Center.

The bonus!

Here, I could just as easily redirect the user to EPiServer’s built-in logout page on /util/login.aspx. But instead of a message that informs the visitor about being logged out, I’d rather redirect the user back to the previous page.

One idea was to create a custom path that performs the signout and redirects my user.

But since I feel EPiServer knows what is needed for most circumstances to logout a user better than me, I’d rather reuse their functionality.

To have this implementation as lightweight as possible I created a custom Route, that takes the visitor to Logout.aspx but with a little twist.
It loads the ordinary Logout.aspx, but hooks up to the PreRender Event to perform a classic Redirect to the previously visited page.

public class LogoutRedirectRouteHandler : IRouteHandler
{
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        var logout = BuildManager.CreateInstanceFromVirtualPath("/Util/Logout.aspx", typeof(Logout)) as Logout;
        if (logout == null)
        {
            // Something seems wrong
            throw new Exception();
        }

        logout.PreRender += this.LogoutOnPreRender;
        return logout;
    }

    private void LogoutOnPreRender(object sender, EventArgs eventArgs)
    {
        var returnUrl = HttpContext.Current.Request.QueryString["ReturnUrl"];
        HttpContext.Current.Response.Redirect(returnUrl);
    }
}

And to register my Route is easy as cake. With some inspiration from Johan Kronbergs blog about Custom Routes, I create an InitializableModule that adds my route to the RouteTable:

[InitializableModule]
[ModuleDependency(typeof(InitializationModule))]
public class LogoutQuickNavigatorInitializer : IInitializableModule
{
    private const string RouteName = "LogoutRedirect";

    public void Initialize(InitializationEngine context)
    {
        RouteTable.Routes.Add(RouteName, new Route("logout", new LogoutRedirectRouteHandler()));
    }

    public void Preload(string[] parameters) { }

    public void Uninitialize(InitializationEngine context)
    {
        RouteTable.Routes.Remove(RouteTable.Routes[RouteName]);
    }
}

3 thoughts on “Hooking up to the EPiServer QuickNavigator

  1. Very Nice. Thanks Alf

  2. Eric Pettersson says:

    Nice, have already implemented on a 7.5 site :)

Leave a reply to Eric Pettersson Cancel reply