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.