This post is somewhat of a sequel to my previous one around multi-site and multi-language setup. When there is only one site and only one language things are pretty straightforward in terms of site context. Once multiple sites are introduced every time we are getting an item in Sitecore and/or building a link we need to make sure we do it within the correct site and correct language. For the most part Sitecore does it out of the box but there are cases when this functionality breaks down.
Here's an example. Suppose we have a multi-level navigation module that we assemble in the following manner:
1. an ajax call is made to the backend
2. backend method gets the item hierarchy from Sitecore
3. backend method returns serialized items as Json
4. in our java script code we generate navigation html with all the data we just got from Sitecore
Sounds easy, right? Not quite. By the time we arrive at step 2 we are stuck with null values for any item we try to get. We have lost our site context.
Let's bring it back! First thing to do is to pass some values from the view along with the ajax call. This could be done multiple ways. Below is just one way of doing so. We will add hidden values that would carry things like current item id, context database and language.
input type="hidden" id="currentItem" value="@Sitecore.Context.Item.ID;
input type="hidden" id="currentDb" value="@Sitecore.Context.Database;
input type="hidden" id="currentLanguage" value="@Sitecore.Context.Site.Language;
Then in the ajax call we need to make sure we pass these values to our backend method. Read the values first:
var currentItem = document.getElementById('currentItem').value;
var currentDb = document.getElementById('currentDb').value;
var currentLan = document.getElementById('currentLanguage').value;
and send them on their way:
var urlString = "yourUrlHere?item=" + currentItem + "&db=" + currentDb + "&lan=" + currentLan;
url: urlString...... and so on
And now we can rebuild our context and get what we need from the sitecore tree making sure we grab a correct site and a correct language.
public ActionResult GetJson()
//read query string params from the url
string currentItem = Request.QueryString["item"];
string currentDb = Request.QueryString["db"];
string currentLan = Request.QueryString["lan"];
// get current database, get current item and its path
var db = Sitecore.Configuration.Factory.GetDatabase(currentDb);
Item item = db.GetItem(currentItem);
string itemPath = item.Paths.FullPath;
//build sitecore context
SiteInfo site = SiteContextFactory.Sites
.Where(s => s.RootPath != "" & itemPath.StartsWith(s.RootPath, StringComparison.OrdinalIgnoreCase))
.Where(s => s.Language == currentLan)
.OrderByDescending(s => s.RootPath.Length)
var website = new SiteContext(site);
// now that we have our context let's throw in some url options that you might need depending on how you want it set up
using (new SiteContextSwitcher(website))
var options = LinkManager.GetDefaultUrlOptions();
options.AlwaysIncludeServerUrl = true; // could be false, depends on requirements
options.Site = new SiteContext(site);
options.SiteResolving = true;
options.LanguageEmbedding = LanguageEmbedding.Never; // could be Always or As Needed depending on requirements
// from here on we can get our items in the proper context and language and build links using the url options we just built. And of course serialize it all and return as json.
I hope this helps someone resolve issues around Sitecore context.