Sitecore.Links.LinkManager and the context

A new feature in Sitecore 6 is the LinkManager. Previously, in Sitecore 5, in order to get a friendly url (an URL with the .aspx extension) you would write the following:

Item item;
string path = item.Paths.GetFriendlyUrl(false);

In Sitecore 6, the GetFriendlyUrl() is deprecated. Instead we are encouraged to use the Sitecore.Links.LinkManager. The same piece of code would look like this:

Item item;
string path = Sitecore.Links.LinkManager.GetItemUrl(item);

The LinkManager provides us with a lot of features that the GetFriendlyUrl() did not. But it also introduces some pitfalls. The LinkManager runs in a context that is not necessarily the same as the Item you are getting the link from, nor the context you wish to run in. Let me explain. Imagine you write a Sitecore shell extension that returns the path to an item. The Item is grabbed from the web database:

Sitecore.Data.Database database = Sitecore.Data.Database.GetDatabase("web");
Sitecore.Data.Items.Item item = database.GetItem("/sitecore/content/home");
string path = item.Paths.FullPath;

The path to the item is “/sitecore/content/home”.

Now, lets get the item’s URL:

string path = Sitecore.Links.LinkManager.GetItemUrl(item)

This returns the item URL for the current Site as defined in the LinkManager.GetDefaultUrlOptions().Site. If my code runs in the modules_shell site, the url is /en/sitecore modules/shell.aspx. Is this really the url of my item? Yes, seen from the modules_shell site it is, but not as seen from the website site.

So my Item used the website site, but my LinkManager uses the modules_shell site. The URL i wanted is the one from the website site, but the URL i requested is from the modules_shell site.

What can I do about this? The URL is constructed by prefixing the current site’s virtual path (which for the modules_shell site is /sitecore modules/shell) to the actual path. The easy solution would be to remove the virtual path from the URL:

string virtualFolder = LinkManager.GetDefaultUrlOptions().Site.VirtualFolder.TrimEnd('/');
Response.Write(LinkManager.GetItemUrl(item).Replace(virtualFolder, ""));

This produces the URL /en.aspx, which is correct for my website site, since this site has no virtual path.

Another, and probably better, solution would be to change the context before getting the link:

string oldSiteName = Sitecore.Context.GetSiteName();
Sitecore.Context.SetActiveSite("website");
Response.Write(LinkManager.GetItemUrl(item));
Sitecore.Context.SetActiveSite(oldSiteName);

This produces the URL “/”, which is correct for the home page of my website.

3 Responses to “Sitecore.Links.LinkManager and the context”

  1. Working with multiple sites in Sitecore « Brian Pedersen’s Sitecore and .NET Blog Says:

    [...] 6, the Sitecore LinkManager uses the context to render an URL, as internal links in the Rich Text Editor is stored internally [...]

  2. Working with multiple sites in Sitecore | cmsnewstoday.com Says:

    [...] 6, the Sitecore LinkManager uses the context to render an URL, as internal links in the Rich Text Editor is stored internally [...]

  3. Phoenix Zerin Says:

    Great article! We used your suggestions in a custom PublishItem processor to send links to recently-published items to a mirror site.

    An alternate approach to the “change the context before getting the link” idea that we used is to provide the desired site context directly to GetItemUrl() via UrlOptions:

    string link = LinkManager.GetItemUrl(item, new UrlOptions
    {
    Site = Sitecore.Sites.SiteContext.GetSite(“website”)
    });


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 92 other followers