Disposing list’s SPSite/SPWeb without ParentWeb

Update 12/10/2008: Don’t use this technique; use the guidance here instead: The New Definitive SPSite/SPWeb Disposal Article

Chris O’Brien’s recent post discusses the need to dispose of SPSite and SPWeb objects, but only if they didn’t come from SPContext. To do this he depends on a list’s ParentWeb property, which currently returns the same instance as the original SPWeb. However, he notes that this strategy depends on the internal implementation of ParentWeb, which (however unlikely) might change.

As a future-proof alternative, I propose capturing the SPWeb as an out parameter if it will need to be disposed:

public void DoSomething() {
  SPWeb webToDispose = null;
  SPList list = getList(out webToDispose);

  // do something with list..
  foreach (SPListItem item in list.Items) {
    processItem(item);
  }

  // ** PROBLEM - how do we now dispose of the SPSite/SPWeb objects we created earlier? **
  // ** SOLUTION - if we didn't use context, webToDispose has reference
  if (webToDispose != null) {
    webToDispose.Dispose();
    webToDispose.Site.Dispose();
  }
}

private SPList getList(out SPWeb webToDispose) {
  webToDispose = null;

  SPContext currentContext = SPContext.Current;
  SPList list = null;

  if (currentContext != null) {
    list = currentContext.Site.AllWebs["MyWeb"].Lists["MyList"];
  }
  else {
    SPSite site = new SPSite("http://solutionizing.net");
    webToDispose = site.OpenWeb("/MyWeb");
    list = webToDispose.Lists["MyList"];
  }

  return list;
}

This code should be functionally equivalent and perhaps a bit easier to read, but without the dependency on ParentWeb. Thoughts?

Also, to add to Chris’s list of required reading, check out Roger Lamb’s excellent SharePoint 2007 and WSS 3.0 Dispose Patterns by Example.

Update 7/23/2008: How ironic…Chris and I have a leak! If you can’t spot it, I explain here.

Advertisement

8 Responses to “Disposing list’s SPSite/SPWeb without ParentWeb”

  1. SPSite/SPWeb Leaks Revisited « Solutionizing .NET Says:

    […] Leaks Revisited July 23, 2008 — Keith Dahlby A while back I posted a rather clumsy technique to mitigate an SPWeb leak discussed here. I knew there had to be a better way, and Rob […]

  2. Is SPList.ParentWeb a Leak? « Solutionizing .NET Says:

    […] SPList.ParentWeb a Leak? August 10, 2008 — Keith Dahlby As previously discussed, doing the “right thing” with our SPSite and SPWeb references’ […]

  3. Andrew Challen Says:

    SPSite site = new SPSite(“http://solutionizing.net”);

    shouldn’t you dispose the site too?

    i.e.

    using(SPSite site = new SPSite(“http://solutionizing.net”)){
    webToDispose = site.OpenWeb(“/MyWeb”);
    list = webToDispose.Lists[“MyList”];
    }

  4. Keith Dahlby Says:

    The site is disposed at the end of DoSomething():

    if (webToDispose != null) {
    webToDispose.Dispose();
    webToDispose.Site.Dispose(); // <–
    }

    The site can’t be disposed within getList because disposing an SPSite also disposes all webs opened from it, including the web we need to leave open.

  5. Andrew Challen Says:

    I’d not tired executing it! My feeling is that
    private SPList getList(out SPWeb webToDispose)
    is dangerous though as you need to remember to know what to do with webToDispose perhaps out
    I think I’d rather see
    private SPList getList(out object[] objectsToDispose)
    I’m still thinking that I’d rather see neither
    For my task I’m going to try using similar idea to the CacheData function here
    http://msdn.microsoft.com/en-us/library/bb687949.aspx

  6. Keith Dahlby Says:

    I agree that this approach isn’t pretty, it was just one of my first investigations into this issue. I prefer the pattern described in my post “SPSite/SPWeb Leaks Revisited”, though the initial example is still rather contrived. Ultimately there are several correct solutions, depending on what you need from the objects in question. Just be careful returning any SharePoint object from a function in which its parent web (or site) has been disposed. If you’re caching a DataTable as recommended, you shouldn’t have much to worry about.

  7. Andrew Challen Says:

    What I’m still struggling to get my head round is that even if you move the
    webToDispose.Dispose();
    webToDispose.Site.Dispose();
    to inside the getList method; when the foreach on the returned SPList doesn’t fail. What’s more is that if I compare the hash code before my premature dispose and after the for each they are the same, why? I have a few ideas but don’t know how to find out which is right yet.

    Secondly if I return a SPListItem or SPListItem.File etc. do I still need to dispose of the SPSite and SPWeb only after I’ve used them?

  8. Keith Dahlby Says:

    You’ve discovered the fundamental issue with the current implementation of Dispose(): The objects are closed and marked as invalid, but they still work. However, behavior of an IDisposable after it has been disposed is technically undefined. While the code might seem to work 99% of the time, there is absolutely no guarantee that it will always work.

    Regarding returning an SPListItem or SPFile, I think you have to assume they might need a reference to their parent Web at any time. So you should either extract the data you need into a non-SP object (DataTable, custom business object, anonymous type in 3.5), or find a way to Dispose later. Ultimately, you should only dispose if you’re 100% certain the reference will never be used again.


Comments are closed.

%d bloggers like this: