views:

387

answers:

3

The scenario I have, is in the Execute method of a SPJobDefinition I want to go through every SPSite in the web application. So I have the following code:

foreach (SPSite site in this.WebApplication.Sites)
{
  ...
}

Question is, do I need to dispose of each site? The rule I normally go by is dispose or put inside a using only if I new it up myself. Will that Sites property actually contain fully constructed site objects to begin with which I'll only have a reference to in this code. If so then disposing the sites would be dangerous as I'm modifying another object that might want them. Or the opposite is does the Sites property construct the objects on request.. in which case is it my responcibility to dispose of them?

Plus how do I dispose them if I do need to do that. I can't use a using in this case, and will calling a dispose inside the foreach break the enumeration?

+11  A: 

Yes you do. See "Writing Applications That Scale to Large Numbers of Users" in Best Practices: Common Coding Issues When Using the SharePoint Object Model. The correct pattern is:

foreach (SPSite site in this.WebApplication.Sites)
{
  try
  {
    ...
  }
  finally
  {
    site.Dispose();
  }
}

Calling dispose will not break the enumeration. It just cleans up the unmanaged memory used by the object.

Alex Angas
I asked about it breaking the enumeration because I've had problems where deleting something out of a list your currently enumerating over with a foreach throws an exception. I just didn't know if the same applied here. Makes sense that if I'm making a copy of the site inside WebApplication.Sites then disposing that won't modifcy the collection that enumeration is running on
Dan Revell
I prefer to encapsulate this disposal logic into an AsSafeEnumerable() extension method: http://solutionizing.net/2009/01/05/linq-for-spwebcollection-revisited-assafeenumerable/ This method is included in SPExLib: http://spexlib.codeplex.com/
dahlbyk
A: 

The guidance here http://www.sharepointdevwiki.com/display/public/When+to+Dispose+SharePoint+objects

suggests that

//loop through each sub site
for (int i = 0; i <= rootweb.Webs.Count; i++)
{
  using (SPWeb subweb = rootweb.Webs[i])
  {
    //do stuff
  }
}

is the prefered solution to this problem.

There is also a tool you can run over your solution to check you are doing things right. http://code.msdn.microsoft.com/SPDisposeCheck

Aidan