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.

March 2, 2010 at 7:22 am
[...] 6, the Sitecore LinkManager uses the context to render an URL, as internal links in the Rich Text Editor is stored internally [...]
March 29, 2010 at 8:49 pm
[...] 6, the Sitecore LinkManager uses the context to render an URL, as internal links in the Rich Text Editor is stored internally [...]
April 15, 2011 at 2:53 pm
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”)
});