EpiServer - get absolute friendly url for given culture for page

gringo_dave picture gringo_dave · Apr 27, 2015 · Viewed 7.1k times · Source

I've a following setup in my Manage Websites panel

General Url is set to alloy.com

alloy.no is set for no culture

alloy.se is set for sv culture

alloy.com is set for en culture

In my code, i want to get the friendly external url for given language for given page. So for Search page I want to get absolute friendly url in all languages.

I use following code to get friendly url for page (found on Anders G. Nordby blog):

var urlResolver = ServiceLocator.Current.GetInstance<UrlResolver>();
var pageAddress = urlResolver.GetUrl(reference, language);

var builder = new UrlBuilder(pageAddress);

Global.UrlRewriteProvider.ConvertToExternal(builder, null, Encoding.UTF8);

var friendlyUrl = builder.Uri.IsAbsoluteUri
    ? builder.ToString()
    : UriSupport.AbsoluteUrlBySettings(builder.ToString());

return friendlyUrl;

It is simple if I will use the alloy.com webpage and in my custom code generate friendly url.

  • no - alloy.no/søk
  • se - alloy.se/sök
  • en - alloy.com/search

But when I use alloy.no to enter edit mode and I will try to generate address for no i get alloy.com/søk when it should be alloy.no/søk.

I found that if I use alloy.no to go to Edit Mode, code :

urlResolver.GetUrl(reference, language)

returns only /søk and code

UriSupport.AbsoluteUrlBySettings(builder.ToString())

add the General URL (alloy.com) instead of alloy.no.

How can I improve this code to take correct host name for page in different culture?

Answer

Henrik N picture Henrik N · Apr 29, 2015

The GetUrl method of the UrlResolver will return a URL to a page that is relative or absolute depending on the current request context. A URL will be relative if the page is located in the current site and absolute if in another site or if the call is made outside a request.

If you are using EPiServer.CMS.Core version 8.0 or later there is also support for identifying one site as the primary site. This update also made it possible to explicitly request that the URL should be to the primary site by setting the ForceCanonical flag on the VirtualPathArguments parameter. If not the flag is not set, it will prefer the current site URL over the primary (given the requested content is located on the current site).

So, with this in mind, you can assume that the returned URL, if not absolute, will be relative to the currently requested site and safely combine it with the currently requested URL such as:

private static string ExternalUrl(this ContentReference contentLink, CultureInfo language)
{
    var urlString = UrlResolver.Current.GetUrl(contentLink, language.Name, new VirtualPathArguments { ForceCanonical = true });
    if (string.IsNullOrEmpty(urlString) || HttpContext.Current == null) return urlString;

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

    return new Uri(HttpContext.Current.Request.Url, uri).ToString();
}

In most cases I would probably prefer not to use HttpContext.Current directly and instead pass in the current request URL. But in this case I have opted to use it directly to keep the example more contained.