SPList.RootFolder causes Dispose Problem

I recently wrote an extension method to several built-in SharePoint objects to allow easier setting and getting of custom properties. You may or may not know that SPList objects do not contain a property bag, so you need to store custom properties in the SPList.RootFolder property.

Here’s what I did to the SPList extension method to get a custom property:

public static string GetCustomProperty(this SPList list, string key)
{
    SPFolder rootFolder = list.RootFolder;
    if (rootFolder.Properties[key] != null)
    {
        string s = rootFolder.Properties[key].ToString();
        return s;
    }
    else
    {
        return string.Empty;
    }
}

Seems simple enough, look for the given key in the RootFolder propertybag, and return empty if not found.

Turns out, this causes a Dispose failure, and you’re left with a memory leak. Can you spot the error?

Neither could I at first, nor could SPDisposeCheck. However, every hit to any page containing this code cause 400Kb of “Potentially excessive number of SPRequest objects currently unreleased on thread” messages.

Of course, the trusted .NET Reflector comes to the rescue, and after wandering through almost one property, I found the error in the getter for the SPList.RootFolder property:

public SPFolder RootFolder
{
    get
    {
        if (this.m_rootFolder == null)
        {
            this.m_rootFolder = this.ParentWeb.GetFolder(this.RootFolderUrl);
        }
        return this.m_rootFolder;
    }
}

In short, the access to this.ParentWeb.GetFolder causes an undisposed SPWeb object to remain in memory.

Updating the code as such caused any potentially excessive numbers of SPRequest objects to disappear:

public static string GetCustomProperty(this SPList list, string key)
{
    SPFolder rootFolder = list.RootFolder;
    if (rootFolder.Properties[key] != null)
    {
        string s = rootFolder.Properties[key].ToString();
        list.ParentWeb.Dispose(); //Dispose orphan SPWeb
        return s;
    }
    else
    {
        return string.Empty;
    }
}

.b

Found this article valuable? Want to show your appreciation? Here are some options:

a) Click on the banners anywhere on the site to visit my blog's sponsors. They are all hand-picked and are selected based on providing great products and services to the SharePoint community.

b) Donate Bitcoins! I love Bitcoins, and you can donate if you'd like by clicking the button below.

c) Spread the word! Below, you should find links to sharing this article on your favorite social media sites. I'm an attention junkie, so sharing is caring in my book!

Pin It

Published by

Bjørn Furuknap

I previously did SharePoint. These days, I try new things to see where I can find the passion. If you have great ideas, cool projects, or is in general an awesome person, get in touch and we might find out together.

3 thoughts on “SPList.RootFolder causes Dispose Problem”

  1. It's not necessarily safe to just dispose list.ParentWeb, as in the majority of cases it will return a reference to the SPWeb from which the SPList was created. At a minimum, you should ensure list.ParentWeb != list.Lists.Web before you Dispose() it. I explore SPList.ParentWeb leaks in more detail here.

    Cheers ~
    Keith

  2. Do sharePoint objects implement IDisposable in some peculiar way that forces us to make these unusual and seemingly incorrect considerations?

    Viewing your code sample through the lens of traditional (non-sharepoint) CLR IDispoable best practices, I have the following concerns:

    1: The code sample suggests that anytime you write an extension method for an object that has one or more IDisposable properties, you should call dispose on each them even when you have not accessed them at all.

    2: Your method surreptitiously and implicitly disposes of the list instance's ParentWeb property. Should any user invoke your method and later attempt to access the list's ParentWeb property, the runtime will likely throw an ObjectDisposedException.

    3: Additionally, let's say I call your method, then on the next line, I call one of the list's built in methods that internally accesses either it's ParentWeb property or the private field that the property encapsulates. Doing so will likely result in another ObjectDisposedException.

    If you wanted to make an Extension Method for the SqlCommand class called AppendParameters, would you do this:

    public static void AppendParameters(this SqlCommand cmd, List> params){
    params.ForEach(p=>{
    cmd.Parameters.AddWithValue(p.key, p.value);
    });
    if(cmd.Connection != null) cmd.Connection.Dispose();
    }

    ????????????

Leave a Reply

Your email address will not be published.