Tuesday, September 09, 2008 10:29:40 AM UTC #

Update: 2009-03-31: Go visit someone else's blog

Go visit Keith's blog for the definitive SharePoint disposal article. Also be aware that Microsoft has released the SPDisposeCheck tool.

That's pretty much it.

Introduction

If any of you out there are looking to find reasons why SharePoint is a "challenging" developer environment, you need look no further than explore the guidance on when to dispose SPWeb and SPSite objects. I was reading Chris O'Brien's blog (which is a veritable font of knowledge on SP dev topics) and found this page, discussing his generic approach to disposing objects, and figured I'd better post this so I can just get it out. Keep in mind folks, that every single SharePoint developer in the world must deal with this issue.

To introduce the problem: Your friendly SharePoint objects SPList and SPWeb will on occasion interact with a COM component. Each pop, for each reference, they hold between 1MB and 2MB of memory. That adds up quick.

So far we're okay, because .NET has a facility for disposing these unmanaged resources (among other things)—through the IDisposable interface. This is why we tell everyone to wrap their code in using blocks—it's to make sure that the unmanaged resources (like the COM components I mention above) are properly released. If you're writing code in SharePoint and you're don't know what a using block is, go read up on it. If you're ignorant of this, it isn't the end of the world for you, but it's close.

Where were we again? Oh yes—SPLists and SPWebs hold unmanaged resources and must be disposed. The "duh" solution is of course, to wrap everything in a using block.

Unfortunately, disposing in SharePoint ain't easy

The first problem you'll run into is when you try and use SPContext.Current.Web - a static getter method. Do you dispose the SPWeb object here, or not? Note that if you dispose an object that's in use elsewhere, you'll cause new problems! Problems you didn't forsee!

This is starting to feel like whack-a-mole. Whack the unmanaged resource mole, up pops the "you whacked the wrong mole" mole.

Whack the "you whacked the wrong mole" mole

So now we know, okay, dispose SPWeb and SPSite objects, but don't dispose the SPContext.Current.Web object. Okay, two things to remember, I can handle that. Unfortunately, we're not done—we're not even close to done. We still have to deal with the "SPList.Web" reference mole, "SPSite.RootWeb" reference mole, the "enumerating through a collection" mole, the "I didn't use the unmanaged resources, this time, and thus don't really need to dispose" mole, and so on.

Disposal strategy Whack-a-mole

Disposal strategy whack-a-mole There are a bunch of resources you can read on this topic, including:

I'm still playing whack-a-mole, but I'm holding steady at the "apathetic about which mole to whack because there are too many moles to keep track of" mole. Oops, sorry, "apathetic about which mole to whack because there are too many moles of which to keep track—there, now I'm not ending my sentence with a preposition" mole.

I'm probably stretching the whack-a-mole reference too far

If I've lost you in the craziness above, let me just summarize by saying: a) object disposal in SharePoint isn't simple, b) I've given up looking for the "perfect solution".

Let's tackle my less-than-perfect solution for object disposal next.

Peter's (newer—thanks Keith) imperfect strategy

Let me first say that I wrote up "my current technique" in this post and secretly published it to my blog. Unfortunately (or fortunately) "secretly publish" doesn't work as well as it should and I got comments. My original approach, which was my firm stance as of Sunday, has changed quite a bit, it's been a full 24 hours. I've taken a little learning journey in the comments below, and in a post on the MSDN forums, where I got an authoritative answer within an hour. Nice!

So, anyway. My newer strategy is to basically copy either Chris O'Brien's or Keith Dahlby's approach, with the one extra little tidbit thrown in: if I'm unsure whether or not to dispose an SPWeb object, I will gather the minimal information necessary from this SPWeb object (e.g. RelativeUrl, Id property), and spawn a second SPWeb object, which I am safe to dispose.

Here's the full algorithm that I use to guarantee I'm safe:

  • Follow published guidance to figure out whether the method call/property getter I'm using will produce a safely-disposable SPWeb or not. This applies really to any IDisposable SharePoint object, including SPSite, PublishingWeb(?), Area(?), and objects of which I've never heard. For this example, SPWeb.
    • If definitely yes,
      • Great! Enclose in a using block.
    • If we're unsure for any reason,
      • Use the SPWeb object we're given, and somehow, with the lightest footprint possible, create ourselves a second SPWeb object, that we're guaranteed we can dispose!
      • We can use this "spWeb2" object and proceed along our merry way, disposing it with glee!
    • If definitely no,
      • Great! Don't dispose it!

Tear it up

Feel free to tear this approach up (assuming I or someone else hasn't already done so). I can take it.

Categories: SharePoint
Technorati:
Tuesday, September 09, 2008 10:29:40 AM UTC  #     |  Comments [14]  |  Trackback
Sunday, September 07, 2008 10:32:30 PM UTC
Two questions:
1. How do you know properties.Feature.Parent (if SPSite or SPWeb) is safe for disposal? My assumption is that a feature would just pass a reference to itself when building the SPFeatureReceiverProperties. If it doesn't have a receiver it would have to clean up its own SPWeb and/or SPSite, so why would that change if it does have a receiver? If MS code can be trusted as an example, Microsoft.SharePoint.SPWikiWelcomeFeatureReceiver would seem to support my assumption.
2. Any particular reason you would rather incur the overhead of creating a new safe-to-dispose SPWeb instead of just marking that particular Web as non-disposable?
Monday, September 08, 2008 3:39:27 AM UTC
Ha! Keith, I'm glad this post hasn't been published in my RSS feed yet, gives me time to get my story right :) Expect my to revise the post/make you sound crazy in the comments, shortly :)

Seriously, I don't know what's safe to delete, so if you have to trust someone, let it not be me. I'll research the feature receiver scenario and get back to you.

As for #2, the real reason is because I'm lazy and have given up trying to do this "the right way." So I'm willing to create a few extra objects and probably waste some time (I haven't profiled it at all so I don't know), just so I don't have to wonder. I'm effectively wrapping a class that may or may not need to be disposed (which is complicated), into my wrapper which is always disposed. Easy to remember/use.
Peter Seale
Monday, September 08, 2008 4:06:47 AM UTC
You know what, I checked into a few open source projects and looked at their code...


The CKS:EBE doesn't dispose.


The CKS:IntranetExtranetEdition loops through site.AllWebs and also doesn't dispose. Any of them.


So you know what, this is officially the moment I give up trying. Even a little. So Keith, if you want to carry the torch and figure out whether it's safe to dispose the feature receiver's feature's parent, if you have that energy--definitely figure it out. But I wrote this post as a sort of "I give up, here's what I'm doing" post, and in researching the specific issue, it just confirmed that the gap between "best practices" and "actual practices" is vast. No one's talking about it, but they're all doing something. And from the brief survey of source code, I'm guessing that that something is worse than what I'm doing.


CKS:EBE feature receiver: (one of many) http://www.codeplex.com/CKS/SourceControl/FileView.aspx?itemId=71590&changeSetId=17054
CKS:IEE feature receiver: http://www.codeplex.com/CKS/SourceControl/FileView.aspx?itemId=71583&changeSetId=17054
Peter Seale
Monday, September 08, 2008 4:12:36 AM UTC
One last link: the Podcasting Kit for SharePoint project disposes their properties.Feature.Parent (which is an SPSite). This supports my opinion--but then again, they write the most defensive SharePoint code I've seen:
http://www.codeplex.com/pks/SourceControl/FileView.aspx?itemId=295248&changeSetId=19732

Any more evidence supporting either side is just more fodder for my "no one really knows the correct way" argument.
Peter Seale
Monday, September 08, 2008 5:54:38 AM UTC
I noticed the post was dated in the future, but I saw the referral so thought I'd check out what you had to say. :) Re: #1, I was just curious if you'd seen a post that I haven't - I'll probably put together a post on what I find.

Ultimately there should be a right answer for every scenario. Roger's post goes a long way (though I still disagree on BreakRoleInheritance, at least in SP1); we (the community and MS) just need to fill in the holes. We can figure out some current rules from the code, but implementations can always change. So eventually it would be nice to see something on MSDN that can serve as definitive guidance that hopefully won't be subject to change. In the meantime, I think it's easier (and safer) to watch for leaks than to detect the subtle corruption that could result from premature disposal.
Monday, September 08, 2008 1:29:03 PM UTC
Hmm, noted. Before this goes public (tomorrow morning) I'll try and remember to swap the example over to an item event receiver, which has the OpenWeb() method that is safe to dispose. It's safe, right? :)
Peter Seale
Monday, September 08, 2008 4:55:23 PM UTC
Just looked at the PKS code again. In the CreatePages method they dispose everything, but in the CreatePage they forget to dispose their PublishingWeb object...and their code is by far the most defensive SharePoint code I've ever seen. But they still get it wrong.

I just want to re-emphasize that everyone has an approach to this problem. Yours is probably the best, but mine is the easiest on me (and as a result, the slowest). Everyone else, it looks like, just does the best they can, and from what I've seen, they're getting it wrong, all over the place.
Peter Seale
Monday, September 08, 2008 5:32:53 PM UTC
And here's the SharePoint Branding Tool, a WinForms app: http://www.codeplex.com/BrandingTool/SourceControl/FileView.aspx?itemId=8451&changeSetId=10125 - not a single using block. I suppose in theory it's less important if you're running outside of the w3wp process, but...this is starting to annoy me.
Peter Seale
Monday, September 08, 2008 5:37:52 PM UTC
Hmm, here's the MSIT Governance site delete capture (which we're running in production): http://www.codeplex.com/governance/SourceControl/FileView.aspx?itemId=35311&changeSetId=1770 - site deletions are infrequent, but sure enough, they're using site.OpenWeb() to get an SPWeb object and aren't disposing.

Here's a fun line:
return new SPSite(siteUrl).OpenWeb().AllUsers[currentUser].Email;



Two leaks, right there.
Peter Seale
Monday, September 08, 2008 5:43:02 PM UTC
...ok, I'll call out the Org Chart web part for correctly disposing their SPSite object. I think they're the only flawless project I've found today. http://www.codeplex.com/orgchartpart/SourceControl/FileView.aspx?itemId=329677&changeSetId=15297
Peter Seale
Monday, September 08, 2008 5:46:16 PM UTC
One of the few things we know for certain is that a call to OpenWeb returns an instance that is safe to Dispose, so you should be in the clear. Of course you could use properties.ListItem.Web instead, but who knows if that needs to be disposed? ;)
Monday, September 08, 2008 6:22:24 PM UTC
Flawless is good, but why not skip the SPSite reference altogether:
ServerContext siteContext = ServerContext.GetContext(this.Context);
Monday, September 08, 2008 7:35:39 PM UTC
Keith, I'm putting in a Q to the MSDN forum:
http://forums.msdn.microsoft.com/en-US/sharepointdevelopment/thread/c0f1a05f-f1db-4f37-8f24-5966ab43e73b

Maybe someone will chime in. I'm secretly hoping someone will reply "why of course you dispose it" and then the next reply will say "why of course you don't dispose it" and then 50 replies later, they all have that same eureka moment. That's my secret hope. But we'll see how it turns out.
Peter Seale
Tuesday, September 09, 2008 3:39:15 AM UTC
Wow, I did not expect my MSDN question to receive an authoritative answer, awesome! Okay.

Also, if anyone mentions that I can submit a patch to fix the projects I mention above...I guess I could. If I thought it was really important, maybe I would; I was more interested in looking to see how they handle object disposal. The summary is: not perfect. But then again, the guidance hasn't been perfect either, nor have the consequences (in most cases).

If you're reading through my comments above on how they're not getting it right (which they aren't), please note I'm not criticizing them, I'm more interesting in pointing out what is common practice. I'd say it's a good bet that these open source projects represent the better half of SharePoint coders. It's not their (our) fault. I looked through some of my old projects and found that I disposed SPContext.Current.Web - oops! And of course I have been disposing SPWeb objects in my Feature Receivers since day 1. I think you can prove this if you look at my SharePointPdfIcon project, I'm one of the ones that doesn't get it right.

Anyway, enough talking to myself in the comments.
Peter Seale
Name
E-mail
Home page

Comment (Some html is allowed: a@href@title, b, blockquote@cite, em, i, strike, strong, sub, sup, u) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Enter the code shown (prevents robots):

Live Comment Preview
Syndication

Search
Posts on this page
Categories
Sites I visit regularly
About

Powered by: newtelligence dasBlog 2.2.8279.16125

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010, Peter Seale

Send mail to the author(s) E-mail



Sign In