World is now on Opti ID! Learn more

Johan Björnfot
Oct 19, 2012
  7319
(0 votes)

EPiServer7 – Routing

Introduction

In previous versions of EPiServer CMS the Friendly Url (FURL) handling was performed by an IHttpModule that executed early on incoming requests and rewrote the path to the aspx file that was specified by the page type. The module also hooked up a Filter on the outgoing response and parsed the outgoing html and rewrote urls to FURLs.

In CMS 7 the FURL handling has been rewritten to be based on the built-in routing in .NET 4.0. To use routing when using WebForms EPiServer.Web.HierarchicalUrlRewriteProvider must be set as URL rewrite provider on the site and the http module for url rewriting should be EPiServer.Web.RoutingUrlRewriteModule. Any other UrlRewriter (not inheriting HierarchicalUrlRewriteProvider) implementation will not use routing to handle incoming request but instead the previously used UrlRewrite functionality. MVC implementations will not use the UrlRewrite provider. In that case the outgoing urls are constructed using System.Web.Routing.RouteTable directly from views/controllers using for example HtmlHelper extension methods or UrlResolver class.

Default routes

There are several routes registered by default. The Shell modules will have routes registered to support routing to for example edit components and gadgets. The CMS will also register a number of routes by default. The CMS routes are registered in GlobalBase during initialization, it is possible to override method RegisterRoutes in Global.asax.cs to customize the registered routes or add additional routes. The namespace EPiServer.Web.Routing contains some extension methods for the class RouteCollection. Those extension methods can be used to register customized content routes. Among the default routes there will be one set up for routing simple address, one for each site (can be several in enterprise scenarios), and one that routes pages/content from the root (that is pages/content not under any start page). The "ordinary" MVC route "{controller}/{action}" is also registered to support partial request through for example Html.RenderAction, however direct browsing to those routes are prevented. The routes are registered in the order above. This is important because the first route will look if the URL matches its route, and if it does, the page will be routed through that route. If the URL does not match the first route, the next route will get its chance.

MVC and Web Forms

An URL can be routed through the routing framework for both MVC and web forms. The routing will first from the URL locate the content routed to. After the content has been located, the framework will query the EPiServer.Web.TemplateResolver instance which template that should be used to render the request. The template can be either a MVC controller or a WebForm. Then depending on if the template is a WebForm or a MVC controller a suitable httpHandler is set to handle the request. If no content is found that matches the URL or if no template is found that matches the routed content a 404 is returned.

Extending routing

Routing can be extended in several levels. There are events exposed both during incoming routing and creation of outgoing URLs that can be used to customize routing. It is also possible to modify the default URL pattern for content routing to handle part of the URL. And you can also add your own routes.

Events

The class EPiServer.Web.Routing.ContentRoute (that is responsible for routing to content) exposes static events RoutingContent, RoutedContent that are raised during incoming routing. RoutingContent are raised before the default routing implementation is executed and in an event handler can for example the content that should match the request be set. RoutedContent are raised after the default routing has executed and in an event handler can for example the routed content be replaced. During outgoing URL generation are the events CreatingVirtualPath and CreatedVirtualPath raised where event handlers can modify the URLs generated.

Modifying Content routing

The built in content routing is based on that an URL pattern is registered where each pattern is handled by an implementation of an interface EPiServer.Web.Routing.Segments.ISegment. It is possible to implement custom ISegment types and register them as part of the content routing.

By default content routing is registered with a pattern as  "{language}/{node}/{partial}/{action}". The {language} part says that in the url there might first be an optional part that states the language. The {node} part is used to specify the CMS page/content in the URL, it will follow the site structure and contain all page names after the start page on the site, down to the requested page. For example, in the following structure "start > news > firstNews", the URL part handled by {node} part would be "/news/firstNews". If there is something remaining in the URL after the page/content routing any registered EPiServer.Web.Routing.IPartialRouter that matches the type of located page will get a chance to route the remaining of the URL. Then at last any remaining part is checked if it is a valid action for a MVC controller. If the requested action would be "myAction" (MVC), the whole URL would be "http://mySite/news/firstNews/myAction".

The 'MapContentRoute' extension method takes the name of the route, the URL pattern, and default values as arguments. Each part in the URL pattern for content routing (for example {node} or {partial}) is handled by an implementation of EPiServer.Web.Routing.Segments.ISegment.

Below is an example on how to add a route:


using EPiServer.Web.Routing;
namespace EPiServer.Samples.MvcTemplates
{
    public class MvcApplication : EPiServer.Global
    {
        protected override void RegisterRoutes(RouteCollection routes)
        {
            //Call base.RegisterRoutes so default CMS routes are registered
            base.RegisterRoutes(routes);
            
            // Register a route, which will make all url:s with 'shop/' before page names route to the page last in the list of page names
            // For example, http://mySite/shop/News/ListOfNews/FirstNews/ will route to the 'FirstNews' page.             
            RouteTable.Routes.MapContentRoute(name: "customRoute", 
                url: "shop/{node}/{partial}/{action}",                
                defaults: new { action = "index" });
        }



Custom route implementations

It is also possible to add custom System.Web.Routing.Route implementations. The order of the routes are important since the first route that handles a request will prevent that following routes get a chance to route the request. So when registering custom routes it is important to decide whether it should be registered before or after the default routes.

Oct 19, 2012

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 |