MIX AND MATCH: Combining Server with Client Routing in Episerver

MIX AND MATCH: Combining Server with Client Routing in Episerver

‘INTERACTIVE’. It’s the buzzword du jour for anyone working in web design. As technology progresses, more websites are functioning like a desktop application instead of a traditional website. ‘Makes sense’, you may argue. But from a technical perspective, there’s still a big difference between these Single Page Applications like Facebook, Cinema Bookings and Ticket Purchases etc compared to regular websites.

As a programmer, your starting point is to decide whether to build a Single Page Application (SPA) or a traditional website. There are a number of different frameworks that make it much easier to build SPAs today compared to a few years back, but it’s also possible to combine an SPA with a traditional website built on top of a CMS.

Given that sites need to deliver an ever-increasing level of user experience, you might have parts or an entire website using a front-end framework to deliver an SPA. Lately, I’ve used client side routing with HTML 5 push state to deliver user friendly navigation routes for two of my clients.

Take for example, a Cinema booking website I worked on last year. When a user visits the site and wants to check the movie time, I could choose to design the page so that the user navigates through a series of filters:

  • Choose city
  • Theatre
  • Date
  • Movie
  • Time
  • Chairs

As a traditional website, it would reload each time a user chooses one of those filters. Designed as an SPA, the client is able to manage this without the need to reload the entire page.

However, the result has been unfriendly URLs like

http://site.com/tickets/#city=losangeles&movie=batman

When the page is reloaded by refreshing the page or opening a link, then the server needs to know about all of the URLs that exist in the application. It needs to register what URLs are part of the client application.

Alternatively, imagine if I chose to create a friendly URL such as “site.com/tickets/cinema/show/date/seats” that can be sent to a friend, giving her the exact filter she needs when she loads the page.

What needs to happen in order to achieve this?

You copy the URL for the page you are and send to your friend

The friend opens this link

A request goes to the server

The server figures out: This is part of the single page application so it just loads the single page app to the user browser. This is all done without changing the URL to the browser.

The problem with this kind of approach is that the URL structure that lives in the client application does not match the one that lives on the server. If you are using a traditional hash-based approach, then this works since the Episerver routing does not take the hash part into consideration. But when using HTML5 push state, the Episerver based routing on the server gets confused since you are adding lots of segments that the server is not aware of. This is because Episerver’s structure is based on the content of the website. Sure, you can add custom routes using standard ASP.NET functionality, but things might get a bit tricky if you have a rather complex client application supporting many domain and languages with dynamic segments that are different in each language.

So, how do you combine client and server side routing? Is there another, better way compared to registering custom routes?

One site that I worked on uses Episerver as the back-end, together with one of the new emerging front-end technologies called Aurelia (for anyone interested in JavaScript frameworks and likes systems that are highly driven by following existing and emerging web standards, please have a look: http://aurelia.io/). In the case of the Cinema booking site, a lot of effort was put into creating a start page that is more of a single page app than a regular informational website to really improve the end user experience, specifically for mobile devices. The rest of the site consists of a regular content structure with standard Episerver routing and server generated views.

The challenge here was to have the server and client routing playing nicely together. Let's first take a look on how the client routing could have looked like:



The start page would be pretty simple on the server side using regular Episerver routing with a start page content type connected to a template. The other pages become a bit trickier though as you need to load the start page view for these as well and then let the client routing direct you to the correct view within the client application. To achieve this, we used the partial routing functionality in Episerver. In this case however, the partial router was not used to load sub content under a page like the case with catalog content in Episerver Commerce, but rather to have everything under a specific page in Episerver in order to load the main page. In other words, this action is similar to an internal redirect to the start page, though the URL remains unchanged since this is needed on the client to route there.

The combined routing for the server and client could be described like this:

 Adding the routing in Episerver

Let us take a look on how we achieve this in Episerver. We need to add a partial router. We start by adding a custom route handler in the application start:


public class EPiServerApplication : EPiServer.Global
    {
        protected void Application_Start()
        {
            RouteConfig.RegisterRoutes(RouteTable.Routes);
        }
    };

In the route config we just register our partial router


using System.Web.Routing;
using EPiServer.ServiceLocation;
using EPiServer.Web.Routing;
using Samples;
 
namespace PublicWeb.Web.Business.Initialization
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            var partialRouter = ServiceLocator.Current.GetInstance<PagePartialRouter>();
            routes.RegisterPartialRouter(partialRouter);
        }
    }
};

Then we add the partial router, where the ‘magic’ actually happens. In this case we made sure to always load the start page whenever underneath we have a URL for a page of the type “SpaPage”. As for the interface IStartPageRouteEndpoint this is just a required interface that is not used for this implementation, since we really do not care about the partial routing.  


using EPiServer;
using EPiServer.Core;
using EPiServer.ServiceLocation;
using EPiServer.Web.Routing;
using EPiServer.Web.Routing.Segments;
using System.Web.Routing;
 
namespace Samples
{
    [ServiceConfiguration(typeof(PagePartialRouter))]
    public class PagePartialRouter : IPartialRouter<SpaPage, IStartPageRouteEndpoint>
    {
        private readonly IContentLoader _contentLoader;
        public PagePartialRouter(IContentLoader contentLoader)
        {
            _contentLoader = contentLoader;
        }
 
        public object RoutePartial(SpaPage content, SegmentContext segmentContext)
        {
            segmentContext.RemainingPath = string.Empty;
            return _contentLoader.Get<StartPage>(ContentReference.StartPage);
        }
 
        public PartialRouteData GetPartialVirtualPath(IStartPageRouteEndpoint content, string language, RouteValueDictionary routeValues, RequestContext requestContext)
        {
            return new PartialRouteData()
            {
                BasePathRoot = content.ContentLink
            };
        }
    }
};

Combining the routing capabilities of Episerver with a client router like the one in Aurelia is just one option available to programmers. Other front-end frameworks with routers like React or Angular JS could also be used to achieve desired results too. Whatever match works for you, web interactivity remains the ultimate goal.

What are your experiences? Share them below.

More Reading

https://developer.mozilla.org/en-US/docs/Web/API/History_API

http://aurelia.io/

http://world.episerver.com/documentation/Items/Developers-Guide/Episerver-CMS/9/Routing/Partial-routing/Partial-routing/

About The Author

Linus Ekström

Linus Ekström

Chief Technology Officer

Linus is a prominent figure amongst Episerver professionals. He develops strategically sound solutions to business challenges.

Get more in-depth tech insights

How Can We Reach You?

Contact us

close