In this tutorial, you will learn how to get the friendly URL for an Episerver CMS power page. Using SEO friendly URLs within your pages are essential to improve the usability and accessibility of your website. If you only referenced other pages on the site using the internal CMS link you're also removing an extra layer of security. Internal links are created using the page Id. If a hacker noticed this pattern, they could in theory be tempted to try and access hidden pages by experimenting with different Ids in a browser. A page ID isn't the worst thing in the world to pass as a query string parameter, however, why give a potential intruder more information than they need?
If you look at the Alloy sample site, you can find a good example of how you can use the link resolver to create a friendly Url
in code, however, sometimes you may want to create URLs in your views. Out-of-the-box, Episerver provides several options and in this tutorial, I will show you all of them! First, we will look at the PageUrl
property 🔥🔥🔥
Url.PageUrl()
In a lot of situations, you will simply want to display the current pages Url in a view. You can do this using the Url()
HTML helper. The Url()
HTML helper lives in the EPiServer.Web.Mvc.Html
namespace, within UrlExtensions
. In UrlExtensions
, you will come across the PageUrl
helper. This method requires a pages internal Url to be passed into it. This is done using the page objects LinkURL
property. An example of how to do this is shown below. This code will return the friendly Url for the page:
Page Url is probably my preferred choice for rendering a URL, we do have other options....
Html.PageLink()
A second option is to use the PageLink
HTML helper. This helper can take a PageData
, PageReference
, or LinkItem
object and will spit out all the HTML required to render an anchor tag. Some examples of how to sue this helper can be seen here:
This call would spit out this HTML:
PageLink
also has an overload that allows you to pass additional route information and styling information:
This is brilliant if you want to create a very basic anchor tag, however, what happens when you want to create something more complex?
UrlResolver
The UrlResolver
API can be thought of as an advanced friendly Url solution. The UrlResolver
is not an HTML helper method and needs to be called using the ServiceLocator
. The class has a method named GetUrl
(it used to be called GetVirtualPath()
but that is now obsolete). The simple overload only requires a ContentReference
to be passed in as the argument. The method also provides additional overloads. You can pass in options like language, additional virtual path arguments and a RequestContext
. Just like the PageUrl
helper, the relative URL for the page is returned.
I do not recommend using UrlResolver
in your view, as you will likely need to call IContentRepository
or Service Locator
in your view. This means adding code into your views. Adding code like this breaks your logical layering of presentation and logic. This will make unit testing impossible. The most obvious solution to avoid breaking your MVC paradigm is to do the URL look-up in your controller. Add a Link
property within your view model and pass the friendly Url value down from the controller to the view. Over the years, I have been asked a number of times if we really need a view model when we have the Episerver page object. This is a perfect example of the split between presentation logic and additional logic to the page object.
We've gone through the main API's provided by Episerver to generate Url's... now's the time to go custom! ThePageUrl
is a helper and can be used within your views, however, it only provides basic functionality. The UrlResolver
is a more complex API, however, it is not wrapped in an HTML helper... what happens if we combine the two? To do this we can create some extra extension overloads for PageUrl
to accept PageReference
objects, routing data and anything else we may need...
By using the above extension method, you can not only pass in PageData
objects via the PageUrl
extension, now you can also pass in any route values you need. This extension can also very easily be updated to override the default action and context by adding them to the RouteValueCollection
. Happy Coding 🤘