Getting To the Root (Well Almost) - Navigating the SPWeb Hierarchy
Recently I was faced with the problem of finding an ancestor web (SPWeb object) of the current web. The ancestor needed to be the one just below the RootWeb. I quickly put together a solution that worked, but I later realized that it had massive memory "leaks" (technically, they're not memory leaks, but they have the same effect so we'll just call them leaks). For more information on this common coding problem, see Roger Lamb's excellent blog entry on this topic: https://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss-3-0-dispose-patterns-by-example.aspx
SPWeb nextToTopWeb = SPContext.Current.Web; while (nextToTopWeb.ParentWeb != null && !nextToTopWeb.ParentWeb.IsRootWeb) { nextToTopWeb = nextToTopWeb.ParentWeb; } // Code that uses nextToTopWeb
The problem is that the ParentWeb method returns an SPWeb object that needs to be disposed and I was calling ParentWeb multiple times without any disposing going on (and in the while expression, it wasn't even returning to a variable). Also, at the end I was not disposing of nextToTopWeb, which you should do if it got assigned a ParentWeb (which happened when it went at least once through the loop), but should not do if you got it through SpContext.Current (which happened if we start at the root web or one below). For some reason, it took me a while to wrap my brain around this little problem and I think I've come up with a solution:
SPWeb nextToTopWeb = SPContext.Current.Site.OpenWeb(SPContext.Current.Web.ServerRelativeUrl); while (true) { SPWeb nextWeb = nextToTopWeb.ParentWeb; if (nextWeb == null || nextWeb.IsRootWeb) { // We found the next-to-top web nextWeb.Dispose(); // Line added 1/15/08 break; } nextToTopWeb.Dispose(); nextToTopWeb = nextWeb; } // Code that uses nextToTopWeb nextToTopWeb.Dispose();
There are probably more elegant ways to do this (code purists won't like using break in an otherwise infinite while loop), but this worked for our project. The key here is to have an intermediary variable (in this case, nextWeb) that holds a reference to the parent web so the current one can be disposed. Also, this code should be put in a try...catch...finally block so if there is an error, you can still dispose of topWeb.
I'm also a bit concerned about performance since it is throwing around SPWeb objects like candy at a parade (SPWeb objects are pretty heavy and have sharp corners - not recommended for throwing at bystanders). There hasn't been an issue thus far, but any suggestions on improving the algorithm are welcome.
Comments
Anonymous
November 11, 2008
PingBack from http://www.tmao.info/getting-to-the-root-well-almost-navigating-the-spweb-hierarchy/Anonymous
January 14, 2010
Hi! Better use this code: SPWeb site = .. SPWeb rootSite = site.Site.RootWeb;Anonymous
January 15, 2010
Vladimir, your code would get you to the root web of the site collection. In my case, I needed to get to one level down from there: the child of the root web that is "up" the tree from (an ancestor of) the current web.