Generating a friendly URL within your EPiServer MVC View

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 querystring parameter but, in most 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.

Url.PageUrl

In most situations, you will probably just want to display a link on it’s 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.

@using EPiServer.Web.Mvc.Html;
<a href="@Url.PageUrl(@page.LinkURL)">
@page.Name
</a>

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.

Html.PageLink

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:

@using EPiServer.Web.Mvc.Html;
@Html.PageLink(new PageData())
@Html.PageLink(new PageReference(0))
@Html.PageLink("example", new PageReference(0))

Which would spit out:

<a href="/tags/tagtwo/">TagTwo</a>

PageLink also has an overload that allows you to pass additional route information and styling information:

@Html.PageLink("A link to a Swedish page",
Model.SomePageReference,
new { language = "en", @class = "link-class" },
null)

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.

UrlResolver

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!  We’ve talked about the need that 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.

public static class UrlExtensions
{
internal static UrlResolver UrlResolver;
static UrlExtensions()
{
UrlResolver = ServiceLocator.Current.GetInstance<UrlResolver>();
}
public static string PageUrl(this UrlHelper urlHelper, PageReference pageLink)
{
return PageUrl(urlHelper, pageLink, null);
}
public static string PageUrl(this UrlHelper urlHelper, PageData page)
{
return PageUrl(urlHelper, page.PageLink, null);
}
public static string PageUrl(this UrlHelper urlHelper, PageReference pageLink, object routeValues)
{
var routeValueDictionary = new RouteValueDictionary(routeValues);
var language = routeValueDictionary[RoutingConstants.LanguageKey] as string
?? ContentLanguage.PreferredCulture.Name;
return PageUrl(urlHelper, pageLink, language, routeValueDictionary);
}
public static string PageUrl(this UrlHelper urlHelper, PageReference page, string lang, RouteValueDictionary routeValues)
{
var virtualPath = new VirtualPathArguments { RouteValues = routeValues };
return UrlResolver.GetUrl(page, lang, virtualPath);
}
}

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.

Jon D Jones

Software Architect, Programmer and Technologist Jon Jones is founder and CEO of London-based tech firm Digital Prompt. He has been working in the field for nearly a decade, specializing in new technologies and technical solution research in the web business. A passionate blogger by heart , speaker & consultant from England.. always on the hunt for the next challenge

More Posts

3 replies

Trackbacks & Pingbacks

  1. […] To do it, you need to use the UrlHelper’s ContentUrl() method.  This method can take a Url or a content reference depending on your situation.  If you have to, or, just disagree with me and want to create your links within your view, then I recommend reading this guide, Generating a friendly URL within your EPiServer MVC View […]

  2. […] There are several ways of getting a Url for a page. If you want to get a friendly Url from a view then I would strongly recommend reading this post to see all the options available to you: Creating a friendly URL within your EPiServer 7 MVC View with Route Data. […]

  3. […] For a more in-depth overview of how friendly Url’s work have a read of my other article Creating a friendly Url within your Episerver 7 MVC View […]

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *