Recently I ran into a “feature” of SharePoint’s SPSite.OpenWeb() method (the no argument constructor specifically). If the OpenWeb() method is used with a URL that is not known to exist, it can result in some unexpected behavior.
Assuming you have the following site structure…
Can you find the bug?
1 2 3 4 5 6 7 8 9 10 11 12
|
<td>
<div class="csharp codecolorer">
<span class="co1">// !!! warning !!!</span><br /> <span class="co1">// !!! dangerous code ahead !!!</span><br /> <span class="kw4">string</span> server <span class="sy0">=</span> <span class="st0">"http://myserver"</span><span class="sy0">;</span><br /> <span class="kw4">string</span> siteUrl <span class="sy0">=</span> <span class="st0">"/sites/SiteCollection/This Subsite Does Not Exist"</span><span class="sy0">;</span><br /> <span class="kw1">using</span> <span class="br0">(</span>SPSite site <span class="sy0">=</span> <span class="kw3">new</span> SPSite<span class="br0">(</span>server <span class="sy0">+</span> siteUrl<span class="br0">)</span><span class="br0">)</span><br /> <span class="br0">{</span><br /> <span class="xtra ln-xtra"> <span class="kw1">using</span> <span class="br0">(</span>SPWeb web <span class="sy0">=</span> site<span class="sy0">.</span><span class="me1">OpenWeb</span><span class="br0">(</span><span class="br0">)</span><span class="br0">)</span><br /></span> <span class="br0">{</span><br /> Console<span class="sy0">.</span><span class="me1">WriteLine</span><span class="br0">(</span>site<span class="sy0">.</span><span class="me1">Url</span><span class="br0">)</span><span class="sy0">;</span><br /> Console<span class="sy0">.</span><span class="me1">WriteLine</span><span class="br0">(</span>web<span class="sy0">.</span><span class="me1">Url</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="br0">}</span>
</div>
</td>
</tr>
The problem reveals itself when the URL’s are printed. Output:
http://myserver/sites/SiteCollection
http://myserver/sites/SiteCollection
The URL for the SPWeb that was just opened is the same as the SPSite’s URL: http://myserver/sites/SiteCollection. There is no exception thrown.
The behavior I expected, would be some sort of exception when opening a web that does not exist. Even worse is the fact that no error is thrown; it simply defaults to the top level site collection that exists. This means, you get the wrong SPWeb object. This error can happen when you use the no argument OpenWeb method call.
A better way to get an SPWeb object passes an argument to OpenWeb (updated 7/13/09 per Rikard’s comment):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
<td>
<div class="csharp codecolorer">
<span class="co1">// better code to open a web</span><br /> <span class="kw4">string</span> server <span class="sy0">=</span> <span class="st0">"http://myserver"</span><span class="sy0">;</span><br /> <span class="kw4">string</span> siteUrl <span class="sy0">=</span> <span class="st0">"/sites/SiteCollection"</span><span class="sy0">;</span><br /> <span class="kw4">string</span> subSite <span class="sy0">=</span> <span class="st0">"This Subsite Does Not Exist"</span><span class="sy0">;</span><br /> <span class="kw1">using</span> <span class="br0">(</span>SPSite site <span class="sy0">=</span> <span class="kw3">new</span> SPSite<span class="br0">(</span>server <span class="sy0">+</span> siteUrl<span class="br0">)</span><span class="br0">)</span><br /> <span class="br0">{</span><br /> <span class="kw1">using</span> <span class="br0">(</span>SPWeb web <span class="sy0">=</span> site<span class="sy0">.</span><span class="me1">OpenWeb</span><span class="br0">(</span>subSite<span class="br0">)</span><span class="br0">)</span><br /> <span class="br0">{</span><br /> <span class="kw1">if</span> <span class="br0">(</span>web<span class="sy0">.</span><span class="me1">Exists</span><span class="br0">)</span><br /> <span class="br0">{</span><br /> <span class="co1">// do work with the web...</span><br /> Console<span class="sy0">.</span><span class="me1">WriteLine</span><span class="br0">(</span>site<span class="sy0">.</span><span class="me1">Url</span><span class="br0">)</span><span class="sy0">;</span><br /> Console<span class="sy0">.</span><span class="me1">WriteLine</span><span class="br0">(</span>web<span class="sy0">.</span><span class="me1">Url</span><span class="br0">)</span><span class="sy0">;</span><br /> <span class="br0">}</span><br /> <span class="br0">}</span><br /> <span class="br0">}</span>
</div>
</td>
</tr>
This code should be able to safely open a web at any location. Keep in mind, trying to access any of the properties of a web that does not exist will result in:
System.IO.FileNotFoundException: There is no Web named “/sites/SiteCollection”.
Again, the exception is not thrown in the constructor, but when attempting to access the SPWeb’s properties… such as web.Url.