Yugeen Klimenko
Jun 30, 2011
(3 votes)

How EPiServer URL Rewriting works.

It is known that EPiServer transforms the urls in both directions – internal and external. For example when you type in your browser “http:// YourEpiSite / Default” this address is transformed into its internal form  inside EPiServer –   http:// YourEpiSite / Default.aspx?id=3&epslanguage=se . Anyway you will continue to observe the http:// YourEpiSite / Default  in the address field.

From the other side if EpiServer  comes upon a reference somewhere in your .aspx page template –  like …<a href=’http:// YourEpiSite / en / Default.aspx?id=3’ \>, – then this address would be transformed into its external form:

http:// YourEpiSite / Default .

Two main principles are at the heart of those transformatiions: modifying the HttpContext address and filtering the HttpResponse via streaming. Let us look on these techologies.

To Internal Direction.

One can change the URL addressed via HttpContext. That is if you address  the http://…./Default.aspx page but you provide your  Application_BeginRequest handler with the following code :

HttpContext context = HttpContext.Current;

context.RewritePath (“~/WebForm.aspx), -

then the WebForm.aspx content would be displayed in browser while the http://…./Default.aspx being displayed in the browser address field.

This technique is used in EPiServer URL Rewriting infrastructure. It relies upon two main items :

1) UrlRewriteModule, i.e. http module implementing the IHttpModule interface;

2) FriendlyUrlRewriteProvider – the “working horse" class which really performs converting the URL in both directions itself.

This is the correspondent class diagram :


The core of the process consists in that UrlRewriteModule being the ASP.NET HttpModule performs its Init function in which it sets the HttpApplication.BeginRequest to its own BeginRequestEventHandler. As a result when the request takes place code in BeginRequestEventHandler makes a call to the HttpUrlRewriteToInternal method. The latter one prepares the query parameters namely page id and language identificator. These parameters are passed to the HttpContext.RewritePath method. This is the “magic” place itself where the redirection takes place.

The sequence diagram is



To External Direction.

If you want to put neccessary corrections into the whole http response content  (f.e. to turn every letter in uppercase or trim the spces between the words) you should:

1) declare new class inherited from Stream, f.e.:

public class TrimStream: Stream

2) implement the Write method in it:

public override void Write (byte[] buffer …)


… trim all the spaces ….


3) set it to the http response filter (you can do it in Application_PostRequestHandlerExecute method in Global.asax):

Response.Filter = new TrimStream (Response.Filter);


EPiServer uses the same principle.

For example, you have <a href=’http://YourEpiSite/en/Default.aspx?id=3’ \> in your .aspx page. When displayed in browser url would be transformed into its external form - http://YourEpiSite/Default. This is made via streaming – in the HtmlRewriteStream class object.

The sequence diagram is given below.


1) In UrlRewriteModuleBase.Init PostRequestHandlerExecuteEventHandler is attached:

… Init (HttpApplication application)


application.PostRequestHandlerExecute += new EventHandler(this.PostRequestHandlerExecuteEventHandler);

2) When PostRequest takes place the HtmlRewriteStream object is created in UrlRewriteModule.HtmlAddRewriteToExternalFilter method:

UrlRewriteModule.HtmlAddRewriteToExternalFilter (HttpApplication application)


Stream stream = htmlRewriter.GetRewriteFilter;

application.Context.Response.Filter = stream;


where HtmlRewriteToExternal.GetRewriteFilter() returns the object of HtmlRewriteStream class.

3)  Finally HtmlRewriteStream.Close is triggered and HtmlRewritePipe.RewriteToEnd method is called.


Then HtmlRewritePipe parses the html content looking for the special elements – i.e. those which can contain urls as their attributes values – f.e. a, area, script. etc…, – and transforms urls into their external forms. Transformation itself is made the following way:

1) obtain the PageReference object from the current url via

PermanentLinkUtility.GetPageReference( string url)

2) obtain PageData object from the PageReference object:

PageData pageData = DataFactory.Instance.GetPage(PageReference pageReference, …)

Due to PageData hierarchical structure we can call the Parent.SegmentURLs recursively and combine them into the whole external address: http:\\EpiSite\Level1\Level2\…..


You can exclude the part of your HTML markup from this kind of processing by putting it inside the container with EPiNoRewrite=”True” and id=”idNoRewrite” attributes:

<div EPiNoRewrite=”True” id=”idNoRewrite”>

<a href=’http://YourEpiSite/en/Default.aspx?id=3’ />


Jun 30, 2011


Hans Arne Vartdal
Hans Arne Vartdal Aug 18, 2011 01:27 PM

Regarding the markup for excluding links from rewriting:

The EPiNoRewrite atribute will cause the markup to be invalid. It would be nice if EPiServer could remove the attribute "after use", leaving the link intact but also the html valid.

Please login to comment.
Latest blogs
How Optimizely Web Experimentation enables fast validation of design and UX changes

Ever wondered how to increase conversion rates and quickly validate design/UX alternatives to find the most impactful changes? I wrote a practical...

Jacob Pretorius | Jan 31, 2023

What’s next after Google Optimize’s sunsetting?

Google has announced that it is sunsetting the Google Optimize and Optimize 360 services, forcing customers to explore new platforms and invest in...

Ynze | Jan 31, 2023 | Syndicated blog

What’s next after Google Optimize’s sunsetting?

Google has announced that it is sunsetting the Google Optimize and Optimize 360 services, forcing customers to explore new platforms and invest in...

Ynze | Jan 31, 2023 | Syndicated blog

Migrating from Providers to CMS 12 ASP.NET Identity with cookie tweaks

Notes on migrating a multi-site from Membership and Role Providers to ASP.NET Identity and changing cookie options dynamically.

Johan Kronberg | Jan 30, 2023 | Syndicated blog

Integrating generative AI in Optimizely CMS: A quick test with OpenAI

Some of the new AI services have received a lot of attention recently. Can you integrate them in Optimizely CMS? Of course, you can!

Tomas Hensrud Gulla | Jan 30, 2023 | Syndicated blog

When best practice isn't the best - Dependency Injection and Optimizely CMS

Some people live and breath 'best practice' development. I am not one of them. Risk is, in-experienced developers (or sometimes experienced) might...

Allan Thraen | Jan 29, 2023 | Syndicated blog