FriendlyUrls and when to call ConvertToExternal and when not to
It’s not always obvious, but most explicit calls by EPiServer applications made to Global.UrlRewriterProvider.ConvertToExternal() are at best superfluous, at worst directly detrimental to both functionality and performance.
First of all the extra code adds complexity that is not required, causing increased thresholds for maintenance and risk of bugs. Secondly, calls to ConvertToExternal() are rather expensive, so they should not be done when they are not needed. Simply more and unnecessary work for both the developer and the server. That can’t be good!
Background
Internally EPiServer uses URLs looking like this: http://www.example.local/Templates/ArticlePage.aspx?id=1234&epslanguage=sv .
A friendly URL for the same page might look like this: http://www.example.local/sv/blogs/friendlyurls-and-converttoexternal/ .
EPiServer works internally with the ‘ugly’ URLs, only at a late stage are links to pages translated to the external friendly form. This is done by something called the HTML rewriter. EPiServer injects a filter to the output stream, intercepting all HTML output, parsing it and finding all URLs with the ‘ugly’ form, and translating them to the friendly form, with the help of the UrlRewriteProvider.
The UrlRewriteProvider thus knows how to convert from the internal (‘ugly’) format to the external (‘friendly’), and back again. Both the rewriter and the UrlRewriteProvider can be extended, modified and replaced by developers, but this is not the topic of this post.
This post is about what EPiServer with the help of the HTML rewriter and the UrlRewriteProvider already does for you, so you do not have to.
Browsers and URLs
When you browse to http://www.example.local/sv/blogs/friendlyurls-and-converttoexternal/, the browser keeps the address around to use as a base for relative and root-relative references. Thus, a link to a resource in this context might be “document.docx” or “/images/picture.png”. The first link will be interpreted by the browser as http://www.example.local/sv/blogs/friendlyurls-and-converttoexternal/document.docx, and the second as http://www.example.local/images/picture.png .
The important part here is that the scheme (HTTP), and the host (www.example.local) are implied by the context the relative URL is used in. This means informally that as long as we refer to resources in the same site, there is no need to specify either the host or the scheme.
This property is often crucial in order to handle situations where proxy servers expose one host-name to the Internet, while the actual EPiServer site uses a different site internally in it’s IIS host. Many sites will unnecessarily have code where the external host name is provided via settings or similar, and all URLs are decorated with this in order to work externally. A better solution is to simply only use root-relative URLs for site-global resources and other pages, and relative URLs for any page-specific resources (not so frequent).
The one common case where you need to specify the external host, is when you need to provide a redirection to a different scheme, i.e. from HTTP to HTTPS or vice-versa. The best way to handle this, is by at an early stage ensure that the outer elements such as the proxy, terminates the SSL connection and ensures via local redirection that the client always uses SSL (HTTPS). This is in cases where HTTPS support is required at all of course. If you really must provide redirection behind a reverse-proxy, try to do this at a single point in the code, and examine if the proxy can be configured to provide the original client-URL via HTTP headers. Many proxies will provide standard headers “X-Forwarded-For” providing the original IP, “X-Forwarded-Host” for the original hostname and “X-Forwarded-Proto” for the original scheme etc. Prefer these over application settings.
Situations where ConvertToExternal is needed
There are essentially two situations where an application may need to call ConvertToExternal explictly.
- A URL with a differing scheme than the page being rendered is required. This should be avoided if at all possible, it’s also confusing and annoying for the user.
- A URL to a page on the site needs to be made available to JavaScript. This can often also be avoided, and that should be the first option to pursue.
Since EPiServer will parse all outgoing HTML, and also inspect the value of a redirection via Response.Redirect(), all references to images, style sheets, script and same-scheme redirection will be handled automatically.
However, EPiServer cannot parse arbitrary JavaScript and determine what is a URL and what is not. Therefore it does not try.
So, unless your cases fits within one of the two cases above, there is probably no need to call ConvertToExternal. Let EPiServer and it’s HTML Rewriter to the heavy lifting for you. That’s what it’s for.
Great article.
I'll also point out that if you use ConvertToExternal() to create links to other CMS pages in EPiServer 7, this can cause issues when navigating within Edit Mode. EPiServer knows how to create the proper CMS page links for the context that the user is working with (i.e. inside vs. outside of Edit Mode), and using ConvertToExternal() will cause the incorrect links to be generated in Edit Mode, resulting in a 404.
I've just fallen into and now climbing back out again of this particular bear pit.
Thanks for the insight :)
I'd add 3) When creating a sitemap