HomeDev Guide
Dev GuideUser GuideGitHubNuGetDev CommunityDoc feedbackLog In
GitHubNuGetDev CommunityDoc feedback


Describes routing in Optimizely Content Management System (CMS).

The URL (Uniform Resource Locator), also known as a web address, is a character string reference to a resource. In most web browsers, the URL displays at the top of a web page, inside an address bar. URLs carry information from the browser to the server required to enact a desired action.

A content URL in Optimizely Content Management System (CMS) contains information that refers to content, including the language (specified either by host or a language segment). The URL can contain additional segments consumed by partial routes (if registered and matches content) and optional custom registered parameter segments.

Routing in CMS is divided in a content URL routing part that is not dependent on web context, meaning you can generate and resolve content URLs in a non-web context. There is an addition to the endpoint routing in ASP.NET Core that extends the content URL routing with routing to MVC controllers or Razor Pages, including parameters that are used when there is a web context.


The following endpoints are registered by default.

  • Shell modules have endpoints registered to support routing to module controllers.
  • CMS registers a wildcard endpoint that routes to content and then maps the request to a matching MVC controller or Razor Page.

The “ordinary” MVC routes like “{controller}/{action}” are not registered by default. You can call ASP.NET Core extension methods like MapRazorPages or MapControllerRoute to register "ordinary" MVC endpoints also.

Controller or Razor Page routing

You can route an URL through the routing framework for both controllers and Razor Pages. The routing first locates the content routed to from the URL. After the content is located, the framework queries the EPiServer.Web.TemplateResolver instance for the template that should be used to render the request. The template can be an MVC controller or a Razor Page or a custom endpoint. Here it will match any remaining path of the url that is not matching content against the parameters on the matched endpoints. If no endpoint is found that matches the URL, or if no template is found that matches the routed content, a 404 (not found) is returned.

Extend routing

You can extend routing in several levels. There are events exposed both during incoming routing and creation of outgoing URLs to customize routing. You also can modify the default URL pattern for content routing to handle a part of the URL. You can also add your own endpoints.

Access checks

In an ASP.NET Core application, .AddRouting() is typically called before .AddAuthentication(). This means that the user is not authenticated during routing; instead, authorization is performed after authentication, and the user is evaluated against the episerver:read policy at this stage. Therefore, extensions like partial routers and/or events to route events, should not perform access checks since user is not authenticated at that stage.

Request language

The request language (ContentLanguage.PreferredCulture and IContentLanguageAccessor.Language) is not set until routing has completed. This means that, for example, partial routers should not rely on them being set but should instead explicitly pass in language when, for example, loading content through IContentLoader. The routed language is available in routing context that is passed in to partial routers or routing event handlers.


The EPiServer.Core.Routing.IContentUrlResolverEvents interface exposes the events ResolvingUrl and ResolvedUrl, which are raised during incoming routing. ResolvingUrl events are raised before executing the default routing implementation, and the content that matches the request is set in an event handler. ResolvedUrl events are raised after executing the default routing, and the routed content is replaced in an event handler. The EPiServer.Core.Routing.IContentUrlGeneratorEvents interface exposes the events GeneratingUrl and GeneratedUrl that are raised where event handlers can modify the generated URLs.

Partial routing

You can register a partial route that is called during content routing if there is a remaining path after content routing. See Partial routing.

Custom content roots

To register content routing for a custom content root (that is a starting point for content routing) one can implement interface EPiServer.Core.Routing.Pipeline.IContentRouteRegister and register the implementation in the DI container. The implementation can then optionally define static segments that should prepend the content route.

Route parameters

If there is a remaining path after content routing the remaining path is matched against matched endpoints. If there is a single segment as remaining path and that segment matches an action on a matched controller then the request is routed to that action. You can also define routing to action parameters by using method MapTemplate on IContentEndpointRouteBuilder that is returned when extension method MapContent is called on IEndpointRouteBuilder.

The following example shows how to register actions with skip and take parameter for a controller:

app.UseEndpoints(endpoints =>

What’s Next