Welcome to the navigation

Tempor ut sunt duis amet, in et sint dolore id laboris consectetur qui incididunt in reprehenderit ipsum aliquip deserunt exercitation aute irure nulla ea ut. Nulla deserunt et nostrud lorem laboris sunt adipisicing do excepteur tempor consequat, ipsum irure ut est proident, veniam, eiusmod minim pariatur, anim labore exercitation dolore

Yeah, this will be replaced... But please enjoy the search!

Get external page urls on a multi-tenant multi-language Episerver site

Sometimes it seems as if the hardest thing in Episerver is to retreive a proper external url of a PageData or ContentReference item. This especially occurs on multi-language or multi-tenant sites. 

The url repository of Episerver may sometimes be complex, and the api's may be changing. What I typically need is a stable method that will be able to resolve the external url of content links no matter which site setup I got. The methods I use have been developed over years and the one I use mostly at the moment seem to do it all.

TLDR; here it is

/// <summary>
/// Resolve the absolute external url of a ContentReference
/// http://www.herlitz.nu/2016/11/29/get-external-page-urls-on-a-multi-tenant-multi-language-episerver-site/
/// </summary>
/// <param name="contentLink"></param>
/// <returns></returns>
public static class PageDataExtensions
{
    public static string ExternalUrl(this ContentReference contentLink)
    {
        var locator = ServiceLocator.Current.GetInstance<IContentLoader>();
        var pd = locator.Get(contentLink);

        var urlString = UrlResolver.Current.GetUrl(contentLink, pd.LanguageBranch, new VirtualPathArguments { ForceCanonical = true });
        if (string.IsNullOrEmpty(urlString))
        {
            return urlString;
        }

        var uri = new Uri(urlString, UriKind.RelativeOrAbsolute);
        if (uri.IsAbsoluteUri)
        {
            return urlString;
        }

        // optional
        //if (!uri.IsAbsoluteUri && HttpContext.Current != null)
        //{
        //    return new Uri(HttpContext.Current.Request.Url, uri).ToString();
        //}

        if (!uri.IsAbsoluteUri)
        {
            var siteDefinitionResolover = ServiceLocator.Current.GetInstance<SiteDefinitionResolver>();
            SiteDefinition siteDefinition = siteDefinitionResolover.GetDefinitionForContent(
                contentLink: contentLink,
                fallbackToWildcardMapped: true,
                fallbackToEmpty: true);

            return new Uri(siteDefinition.SiteUrl, uri).ToString();
        }

        return urlString;
    }
}

In a bit more detail

First I construct a PageData object from the contentLink which is required to distinguish the different language branches

var locator = ServiceLocator.Current.GetInstance<IContentLoader>();
var pd = locator.Get(contentLink);

Next up I use the UrlResolver singleton to tech the url for the page, this is where the language specific url is resolved. If no url is detected this is a good place to exit, handle the null return in your call

var urlString = UrlResolver.Current.GetUrl(contentLink, pd.LanguageBranch, new VirtualPathArguments { ForceCanonical = true });
if (string.IsNullOrEmpty(urlString))
{
    return urlString;
}

Check if the urlString was absolute, if it was we are done

var uri = new Uri(urlString, UriKind.RelativeOrAbsolute);
if (uri.IsAbsoluteUri)
{
    return urlString;
}

If the url still is relative we are probably missing httpcontext, possibly the method is run by a service like an indexer or another timer job. To ensure we construct a correct absolute url we need to fetch the site url from the SiteDefinition which we can construct from the contentLink using the SiteDefinitionResolver

if (!uri.IsAbsoluteUri)
{
    var siteDefinitionResolover = ServiceLocator.Current.GetInstance<SiteDefinitionResolver>();
    SiteDefinition siteDefinition = siteDefinitionResolover.GetDefinitionForContent(
        contentLink: contentLink, 
        fallbackToWildcardMapped: true,
        fallbackToEmpty: true);

    return new Uri(siteDefinition.SiteUrl, uri).ToString();
}

Thats it, happy urling.