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 🔥🔥🔥
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, 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....
A second option is to use the
PageLink HTML helper. This helper can take a
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 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
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! The
PageUrl 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 🤘