SharePoint development, while built on top of ASP.NET, has its own unique challenges. Microsoft provides an excellent site for SharePoint development best practices. On this site, Disposing Objects gets special consideration and its own MSDN page. Now any .NET developer whose been around the block knows all about disposing objects and this is nothing new. When it comes to custom SharePoint development, there are a lot of objects that require disposing. For instance SPSite and SPWeb objects, which anyone doing SharePoint development knows, these get used a lot. When you are in a time crunch and writing a lot of code, these can sometimes get overlooked. From MSDN this can result in:

  • Frequent recycles of the SharePoint Foundation application pool, especially during peak usage
  • Application crashes that appear as heap corruption in the debugger
  • High memory use for Internet Information Services (IIS) worker processes
  • Poor system and application performance

Once these are in your code it can be a long trek into the depths of your solution to find where you've missed a Dispose call. Fortunately, we have the SPDisposeCheck tool to help us out.

From the SPDisposeCheck page: "SPDisposeCheck is a tool that helps developers and administrators check custom SharePoint solutions that use the SharePoint Object Model helping measure against known Microsoft dispose best practices." In addition to checking for items that are not disposed of properly, it also checks for items that SHOULD NOT be disposed. So let's take a look at installing this plugin into Visual Studio and then look at how to use it.

You can download the tool via the SPDisposeCheck website. About mid-way down there is the link to download. The download is an MSI that you can run on your machine with SharePoint and Visual Studio installed.

Running the install you will be presented with options to "Install Visual Studio AddIn" and "Execute SPDisposeCheck after Visual Studio Build". For my development environment, I did not choose either of these. I will show you how to add it to the Visual Studio Tools instead so you can run it on demand. Also, you can easily integrate this into your build later or on a build machine if your enterprise uses one. For now, I find it easier and faster to leave these un-checked and run on demand.

Once the installation is complete the SPDisposeCheck tool will the located here (64-bit systems): "C:\Program Files (x86)\Microsoft\SharePoint Dispose Check".

Now launch Visual Studio and click "Tools -> External Tools". You will get the External Tools window, click "Add" and fill in the following information:

  • Title: SP Dispose Check
  • Command: C:\Program Files (x86)\Microsoft\SharePoint Dispose Check\SPDisposeCheck.exe
  • Arguments: $(BinDir)
  • Initial directory: $(SolutionDir)
  • Use Output window: Checked

Click "OK", now under "Tools" you will see your new option "SP Dispose Check".

Now that we have our SPDisposeCheck installed and loaded as a Tool in Visual Studio, let's write some code and see how it works. First we'll look at a really simple example of bad coding practices in SharePoint, opening an SPWeb and an SPSite object and not disposing. (Note: I have created a Project called "Using_SPDisposeCheck"", the examples below will be referencing this project name.)

protected void Page_Load(object sender, EventArgs e)
{
SPSite site = new SPSite("http://sp2010");
SPWeb web = site.RootWeb;
}

This code is obviously poor since we are opening these two objects without disposing. Building this project and we'll get a successful build with no complaints from Visual Studio. However, running the SPDisposeCheck tool we get the following output:

ID: SPDisposeCheckID_110
Module: Using_SPDisposeCheck.dll
Method: Using_SPDisposeCheck.VisualWebPart1.VisualWebPart1UserControl.Page_Load(System.Object,System.EventArgs)
Statement: site := new Microsoft.SharePoint.SPSite("http://sp2010")
Source: C:\Projects\Using_SPDisposeCheck\Using_SPDisposeCheck\VisualWebPart1\VisualWebPart1UserControl.ascx.cs
Line: 14
Notes: Disposable type not disposed: Microsoft.SharePoint.SPSite
***This may be a false positive depending on how the type was created or if it is disposed outside the current scope
More Information: http://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss...
----------------------------------------------------------


ID: SPDisposeCheckID_140
Module: Using_SPDisposeCheck.dll
Method: Using_SPDisposeCheck.VisualWebPart1.VisualWebPart1UserControl.Page_Load(System.Object,System.EventArgs)
Statement: web := site.{Microsoft.SharePoint.SPSite}get_RootWeb()
Source: C:\Projects\Using_SPDisposeCheck\Using_SPDisposeCheck\VisualWebPart1\VisualWebPart1UserControl.ascx.cs
Line: 15
Notes: Disposable type not disposed: Microsoft.SharePoint.SPWeb
***This may be a false positive depending on how the type was created or if it is disposed outside the current scope
More Information: http://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss...
----------------------------------------------------------

Total Found: 2

----------------------------------------------------------

Modules Checked: 1
----------------------------------------------------------
Using_SPDisposeCheck.dll
----------------------------------------------------------

Modules Ignored: 0
----------------------------------------------------------
----------------------------------------------------------

Methods Ignored: 0
----------------------------------------------------------

SPDisposeCheck found both of our objects and has given us a warning with line numbers of the offending code, excellent! Now, we'll rewrite this block using some best practices.

using (SPSite site = new SPSite("http://sp2010"))
{
using (SPWeb web = site.RootWeb)
{
// Some code here
}
}

Now re-running SPDisposeCheck gives us the following output:

ID: SPDisposeCheckID_655
Module: Using_SPDisposeCheck.dll
Method: Using_SPDisposeCheck.VisualWebPart1.VisualWebPart1UserControl.Page_Load(System.Object,System.EventArgs)
Statement: web.{System.IDisposable}Dispose()
Notes: Dispose should not be called on this object.
Initial Assignment: web := site.{Microsoft.SharePoint.SPSite}get_RootWeb()
More Information: http://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss...
----------------------------------------------------------

Total Found: 1

----------------------------------------------------------

Modules Checked: 1
----------------------------------------------------------
Using_SPDisposeCheck.dll
----------------------------------------------------------

Modules Ignored: 0
----------------------------------------------------------
----------------------------------------------------------

Methods Ignored: 0
----------------------------------------------------------

Still no good! This is because SPDisposeCheck will also notify you of things that should not be disposed! In this case, the RootWeb object of a site collection, even better! Let try this one more time.

using (SPSite site = new SPSite("http://sp2010"))
{
using (SPWeb web = site.AllWebs[0])
{
// Some code here
}
}

In this example, we'll still open the site collection root web, but not by using the site.RootWeb property, this is ok. Now, running SPDisposeCheck gives us the following output:

Total Found: 0

----------------------------------------------------------

Modules Checked: 1
----------------------------------------------------------
Using_SPDisposeCheck.dll
----------------------------------------------------------

Modules Ignored: 0
----------------------------------------------------------
----------------------------------------------------------

Methods Ignored: 0
----------------------------------------------------------

Perfect! We went from having two open objects in memory to none, all while using some best practices! The previous examples are fairly simple and fairly easy to catch. But what about something like this:

using (SPSite site = new SPSite("http://sp2010"))
{
foreach(SPWeb web in site.AllWebs)
{
// Some code here
}
}

Every SharePoint developer has written this code at least once in their career. At first glance it looks good, I have my site collection in a using statement and just simply iterating through the sub-webs, no big deal. However, by now you should already see the issue, and SPDisposeCheck will catch it. Here is the output:

ID: SPDisposeCheckID_130
Module: Using_SPDisposeCheck.dll
Method: Using_SPDisposeCheck.VisualWebPart1.VisualWebPart1UserControl.Page_Load(System.Object,System.EventArgs)
Statement: web := (Microsoft.SharePoint.SPWeb) CS$5$0000.{System.Collections.IEnumerator}get_Current()
Source: C:\Projects\Using_SPDisposeCheck\Using_SPDisposeCheck\VisualWebPart1\VisualWebPart1UserControl.ascx.cs
Line: 16
Notes: Disposable type not disposed: Microsoft.SharePoint.SPWeb
***This may be a false positive depending on how the type was created or if it is disposed outside the current scope
More Information: http://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss...
----------------------------------------------------------

Total Found: 1

----------------------------------------------------------

Modules Checked: 1
----------------------------------------------------------
Using_SPDisposeCheck.dll
----------------------------------------------------------

Modules Ignored: 0
----------------------------------------------------------
----------------------------------------------------------

Methods Ignored: 0
----------------------------------------------------------

Sure enough, iterating through the sub-webs is opening an SPWeb object (for each sub-web!) and there is no dispose, so this is bad. Let's change that up a little.

using (SPSite site = new SPSite("http://sp2010"))
{
foreach(SPWeb web in site.AllWebs)
{
using (web)
{
// Some code here
}
}
}

Now SPDisposeCheck is happy with the following output:

Total Found: 0

----------------------------------------------------------

Modules Checked: 1
----------------------------------------------------------
Using_SPDisposeCheck.dll
----------------------------------------------------------

Modules Ignored: 0
----------------------------------------------------------
----------------------------------------------------------

Methods Ignored: 0
----------------------------------------------------------

Again, in this last example, the open SPWeb objects should be fairly easy to catch. However when you are writing a lot of code these mistakes can creep in. Luckily you have the tools available to you to catch these mistakes and rectify them before deploying your code.