Inconvenient opening sites – SPSite.OpenWeb()


While working with SharePoint I have stumbled upon quite some inconveniences. Most of the time they were in methods that you don’t use that often, and when you do, you expect them to do something else than they actually do. I probably haven’t worked on a single SharePoint project where I wasn’t instantiating sites. So I was quite surprised when I found out that even something as simple as SPSite.OpenWeb doesn’t always do what you would it expect it to.

Recently I got the task to design and develop a mechanism to provide context help for a SharePoint solution. The visitor would browse on the website and if requested help, the help would by default open on the section related to the current location.

Imagine having a site hierarchy like this:

Site Hierarchy

If the visitor would be on the Contact page and requested help, he should get the help page describing the Contact functionality, Contact form, etc (1). Similar with the products: if the visitor would be browsing through the products catalog and requested help about some particular page, the help system should automatically find and display the relevant information (2).

Request help for existing pages

As this is a real world requirement, there might be a chance that some products or sections on the website don’t have any specific help information. In such situation the help system should be intelligent enough to go up the hierarchy until it finds a help section.

Request help for sections which don't have specific help pages. The help system goes up the help hierarchy until it finds an existing section

I wanted to make this work as simple as possible. Looking closer at the requirements they seemed very similar to what SharePoint does by default while opening sites. Imagine you have a URL “http://adventureworks.com/pressreleases/archive/nonexistingsite”. If you pass this to the constructor of SPSite and then call OpenWeb(), SharePoint automatically returns the first existing web, for example:

string url = "http://adventureworks.com/PressReleases/Archive/NonExistingSite";

using (SPSite site = new SPSite(url))
{
  using (SPWeb web = site.OpenWeb())
  {
    // web.SiteRelativeUrl = /PressReleases/Archive
  }
}

Using that idea I wanted to copy the whole site hierarchy under a site called “Help”. Like this we would fully leverage the concept of SharePoint data structure, we would decrease the level of custom development and we would provide a simple mechanism for maintaining the help pages. The only thing we would have to develop was a Help link control which would determine the URL of the help page for the current location.

Inconvenient SPSite.OpenWeb(string)

As we were working in the context of a SharePoint site, I have decided not to open a new instance of SPSite but to use the one existing in the context:

string sectionUrl = SPContext.Current.Web.ServerRelativeUrl;

using (SPWeb web = SPContext.Current.Site.OpenWeb(sectionUrl))
{
  // ....
}

Opening an existing site worked perfectly: we’ve all done that thousands of times. But as soon as I passed a non-existing URL I got an unpleasant surprise:

string sectionUrl = "/PressReleases/Archive/NonExistingSite";

using (SPWeb web = SPContext.Current.Site.OpenWeb(sectionUrl))
{
  // web.Exists = false;
  // web.Title > FileNotFoundException!!!
}

Instead of getting a reference to the Press Releases Archive site, I got a reference to a non-existing site. Retrieving the value of any other property resulted in a FileNotFoundException. So was the ability to find the first existing parent site something that the SPSite constructor only could do or was I missing something?

I wasn’t particularly happy about the idea of creating a new SPSite instance on every page load. And even if I could cache the once retrieved help page URL, it was still a penalty we didn’t want to have. Don’t forget the help link was included in the Master Page and available on every single page on the website.

There is more to OpenWeb

Looking at the definition of the SPSite.OpenWeb method I have found out that there are a couple overloads to it among which the SPSite.OpenWeb(string, bool). According to the SDK the string parameter contains either a server-relative (begins with a “/” (slash)) or a site-relative URL. The boolean parameter was there to determine whether the URL was exact or not. What IS an exact URL?

I’ve found out what the Windows SharePoint Services (WSS) team meant with “exact URL”. It was exactly what I needed: if passed a URL of a non-existing site, SharePoint would go one level up the hierarchy until it found a valid site!

Summary

Although I’ve been using the SPSite.OpenWeb method thousands of times I never took a look at the OpenWeb(string, bool) overload. The fact that it was there and working exactly the way I needed it to, made one thing clear to me: it’s all in the details. Look carefully at what’s there before you start writing your own code: and SharePoint has a lot of such gems.

Technorati Tags: SharePoint, SharePoint 2007, WSS 3.0, MOSS 2007

Others found also helpful: