| As SharePoint developers, we all know that we have to Dispose our SPSite and SPWeb instances if we didn’t acquire them from the SPContext. If you don’t know what I’m talking about, STOP and go to Roger Lamb's blog read and understand. | |
| | |
| Now I’ll show you how I used to code to be sure to “never” leak any SharePoint resources. I created a utility class with (among others) a method called GetList( string webUri, string listName ) see below. | |
public SPList GetList( string webUri, string listName )
{
using (SPSite site = new SPSite(webUri))
{
using (SPWeb web = site.OpenWeb())
{
return web.Lists[listName];
}
}
}
|
|
| What is wrong with this method? I acquire the SPSite and SPWeb objects and then dispose of them, returning the SPList…. |
|
| |
|
| The problem is that we shouldn’t be able to use the SPList when the parent SPWeb has been disposed…. UNFORTUNATELY MS has put a lot of compensating logic into the Object Model to manage this instead of just throwing an ObjectDisposed exception. So if you you use this returned SPList instance what will happen is that the Object Model will instantiate a new SPWeb and you will leak this since the SPList does not implement IDisposable. If you turn on verbose logging you will see entries like this one below when WSS detects that you are using a disposed SPWeb. |
|
Detected use of SPRequest for previously closed SPWeb object. Please close SPWeb objects when you are done with all objects obtained from them, but not before Stack trace:
|
|
| So let’s look at my current favorite “pattern”. I use delegates so that I know that the lifetime of my SPSite and SPWeb are managed properly. This is the equivalent of a method called GetSPWeb( string uri ); |
|
| |
|
public void WithWeb(string uri, Action<SPWeb> action)
{
using (SPSite site = new SPSite(uri))
{
using (SPWeb web = site.OpenWeb())
{
action(web);
}
}
}
|
|
| Let’s take a look at the call site: |
|
| |
|
public void WithList(string webUri, string listName, Action<SPList> action)
{
WithWeb(webUri, delegate(SPWeb web)
{
foreach (SPList list in web.Lists)
{
if (list.RootFolder.Name == listName)
{
action(list);
break;
}
}
});
}
|
|
| As you can see, all instances are alive until the delegate has executed, then they are disposed of in the correct order. |
|
Disclaimer: There are so many interdependencies in the SharePoint object model so the above delegates won’t fix “everything” but the main point I want to get through is DON’T work with disposed objects or descendents of them.
|
|
/Jonas
|
|
Posted
Sep 29 2009, 05:47 PM
by
Jonas Nilsson
Please sign into Bamboo Nation to leave a comment.