SEO friendly URLs are essential to improve the usability and accessibility of your website, also by hiding your Page Id's from your customer, you're adding an extra layer of security by not leaking any of your internal Episerver data. A page ID isn't the worst thing in the world to pass as a query string parameter but, in most cases, why give a potential intruder more information than they need? If you look at the Alloy sample site, it shows a good way to use a link resolver to create a friendly Url for you, however, sometimes you may want to create URLs in your views. Out of the box, Episerver provides several options.
In most situations, you will probably just want to display a link on its own. The PageUrl helper which lives in EPiServer.Web.Mvc.Html will do this for you. If you look in the EPiServer.Web.Mvc.Html namespace within UrlExtensions, you will come across the PageUrl helper. The helper required a page's internal Url to be passed in, using the LinkURL property for example, and it will pass you back the friendly Url for the page.
Page Url is probably my preferred choice. In most cases, however, we do have other options. More information about this can be found on this page, StructureHtmlHelperExtensions Methods.
The second option is to use the Episerver Html helper. The PageLink helper can take a PageData, PageReference, or LinkItem and will spit out all the HTML for an anchor tag pre-populated. Some examples can be seen here:
Which would spit out:
PageLink also has an overload that allows you to pass additional route information and styling information:
This is brilliant is you want to create a very basic anchor tag but what happens if you want to create something more complex on your page like the below snippet.
The UrlResolver can be thought of as an advanced friendly Url solution. The UrlResolver is not a 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 version requires a single ContentReference to be passed in as the argument. The class also provides additional overloads to pass in all sorts of configurable options like language, additional Virtual path arguments and a RequestContext. Just like the PageUrl helper the relative URL for the page is returned. If you use either PageUrl or UrResolver in your view, you then have the issue that you might need to add called to IContentRepository or the UrlResolver itself and that requires the Service Locator code in your view. This breaks your logical layering of presentation and logic which is bad for your unit tests.
The most obvious solution to get around this problem is add a Link property within your View Model and place all the logic in there. I've been asked quite a lot over the years what should the View Model be used for and when and this is a perfect example of the split between presentation logic and view model logic. Ok so 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 but only provides basic functionality and UrlResolver can be tough as a more complex API but is not a provider in an html helper... what happens if we combine the two, to allow the PageUrl property to have more parameters passed in how for doing getting the page data object and passing it into around for needing a page data object sometimes in the presentation view. To do this we can create some extra extension overloads for PageUrl to accept PageReferenceobjects, route 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.