This has come up in various conversations recently so I figured I’d write up a short post about it. When trying to obtain an SPWeb object there are a couple of different options available using members of an SPSite instance. The first, and more common, is the OpenWeb() method and the second is using the AllWebs[] property collection. Here’s the problem I have with OpenWeb() (specifically the overload that takes no arguments) – consider the following code:

1string url = "http://portal/sites/ActualSite/ChildWeb/GrandChildWeb";
2using (SPSite site = new SPSite(url))
3using (SPWeb web = site.OpenWeb())
4{
5    ...
6}

In the above code if both ChildWeb and GrandChildWeb actually exist then the OpenWeb() call will return the GrandChild web. However, lets assume that GrandChildWeb doesn’t exist (or perhaps it was spelled incorrectly), in that case what you will get for the web variable will be ChildWeb (assuming it exists). The problem is that the user will not get any error indicating that the URL provided was invalid – it simply returns back the first valid web in the URL hierarchy. In some cases this is exactly what you want (this is common when the URL you have is that of a List or Folder) but generally this is not going to be the case.

Now consider the following code where Utilities.GetServerRelativeUrl is a helper method that returns back the server relative URL:

1string url = "http://portal/sites/ActualSite/ChildWeb/GrandChildWeb";
2using (SPSite site = new SPSite(url))
3using (SPWeb web = site.OpenWeb(Utilities.GetServerRelativeUrl(url), true))
4{
5    ...
6}

In the above code if GrandChildWeb does not exist then an ArgumentException will be thrown thus ensuring that the code does not now inadvertently operate on the wrong SPWeb object. Alternatively you could do the exact same thing using the AllWebs property collection as shown below:

1string url = "http://portal/sites/ActualSite/ChildWeb/GrandChildWeb";
2using (SPSite site = new SPSite(url))
3using (SPWeb web = site.AllWebs[Utilities.GetServerRelativeUrl(url)])
4{
5    ...
6}

I actually prefer using this method when the URL I have is explicitly expected to be the URL of a web. This helps me during code reviews to do a quick search for all OpenWeb calls thus allowing me to focus my attention on how and where the URL parameter is coming from (so I use OpenWeb() with no arguments whenever I have an arbitrary URL that points to a resource below a web and not the web itself and I use AllWebs for everything else).

So I know what you’re thinking: “But Gary, won’t using a property collection result in all the webs being opened so isn’t using AllWebs less performant?”. Actually, no, that’s not how AllWebs works – internally the indexer for AllWebs makes a call to the SPSite.OpenWeb(string, bool) method passing in the server relative URL and true to ensure an exact match. This results in an ArgumentException if the URL specified does not correspond to a web.

In conclusion, use AllWebs when the URL you have is expected to correspond to a web and use OpenWeb when the URL corresponds to a list, folder, or file.