AAron nAAs

All MindsharpBlogs

AAron's SharePoint notepad

My Links

Archives

Blog Stats

My Sites

Thursday, April 03, 2008 #

Safely SPWeb.Dispose()

When to call Dispose() on your SharePoint WSSv3 site and web objects seems like an ornery topic. Dispose should be releasing memory and resources, and not actually writing or destroying any data, so not calling it properly could cause leaks of memory or other resources. Here is the general rule I've learned.

1) If you instantiate the object with “new” or OpenWeb, you need to Dispose() of it.
2) If you indirectly instantiate the web object by using SPSite.RootWeb, then you need to Dispose() of it... but not in the way you might think.
This is what SPSite.RootWeb is doing:

public SPWeb RootWeb

{

    get

    {

        if (this.m_rootWeb == null)

        {

            this.m_rootWeb = this.OpenWeb(this.ServerRelativeUrl);

            this.m_rootWebCreated = true;

        }

        return this.m_rootWeb;

    }

}

So now it makes sense as to why SPSite.RootWeb might need special care to Dispose() just as if you had called OpenWeb... because you effectively did, since SPSite.Dispose() doesn't dispose the web object.

BUT, you could Dispose() of the SPWeb, OR the SPSite object to release that SPWeb. If you Dispose() the SPWeb, the SPSite gets a little confused, but not tragically (m_rootWeb ends up null, but m_rootWebCreated remains true). If you Dispose() of the SPSite instead, everything is properly Dispose()ed and all state remains consistent. With the varied advice on when and how to Dispose of the SPWeb from the SPSite.RootWeb, it is lucky that doing extra Dispose() calls don't do anything, or even error.

Look at this debugging session. Notice how the internal state of the “site“ object changes based on the worst case scenario of getting the RootWeb twice and Dispose()ing it between the references to RootWeb (I was trying to cause an error by calling Dispose() then getting the RootWeb again). The most interesting revelations are that Dispose()ing the Web immediately affects the state of its parent SPSite, and that Dispose()ing the SPSite automatically, and completely, cleans up the SPWeb gotten via RootWeb.

        static void Main(string[] args)

        {

            SPSite site = new SPSite("http://localhost");

            SPWeb web = null;

            try

            {

                // site.m_rootWeb == null

                // site.m_rootWebCreated == false

 

                ShowDetails(site);

 

                // site.m_rootWeb == null

                // site.m_rootWebCreated == true

 

                web = site.RootWeb;

            }

            finally

            {

                // site.m_rootWeb == web

                // site.m_rootWebCreated == true

                // web.m_closed = false

 

                site.Dispose();

 

                // site.m_rootWeb == null

                // site.m_rootWebCreated == false

                // web.m_closed = true

 

                web.Dispose();

 

                // site.m_rootWeb == null

                // site.m_rootWebCreated == false

                // web.m_closed = true

 

                web.Dispose(); // Extra Disposes do nothing

 

                // site.m_rootWeb == null

                // site.m_rootWebCreated == false

                // web.m_closed = true

            }

        }

 

        static void ShowDetails(SPSite site)

        {

            SPWeb web = null;

            try

            {

                // site.m_rootWeb == null

                // site.m_rootWebCreated == false

 

                web = site.RootWeb;

            }

            finally

            {

                // site.m_rootWeb == web

                // site.m_rootWebCreated == true

                // web.m_closed = false

 

                web.Dispose(); // This is where SPSite's state first gets confused.

 

                // site.m_rootWeb == null

                // site.m_rootWebCreated == true

                // web.m_closed = true

            }

        }

NOTE: The above example intentionally uses the long hand try/finally blocks to be clear about the point. The better way to code Dispose() is with the C# “using” directive to implicitly call Dispose(), such as “using (SPWeb web = site.RootWeb) { do something; }”

posted @ 12:39 AM | Feedback (4)