So I’m working on an end user focused blog post about the difference between closing (Close) and deleting (Delete) a web part. In the middle of that I realized that although we’ve been told that the web part still runs when you close a web part on a page, we’ve not been told what still runs in the web part. So I fire up Visual Studio and I create the world’s dumbest web part. (There should be a competition.) All this web part does is log each time any one of the methods that can be overridden is called. Essentially any time the web part receives any sort of action. I run the web part in WSS v3 and I get the following results:
Adding | Regular Load | Minimized | Closing | Closed |
Constructor | Constructor | Constructor | Constructor | Constructor |
Constructor | ResolveAdapter | ResolveAdapter | ResolveAdapter | Missing: Dispose |
ResolveAdapter | OnInit | OnInit | OnInit | |
OnInit | TrackViewState | TrackViewState | TrackViewState | |
TrackViewState | HasControls | OnLoad | HasControls | |
OnLoad | OnLoad | EnsureChildControls | OnUnload | |
EnsureChildControls | EnsureChildControls | ResolveAdapter | Missing: Dispose | |
ResolveAdapter | ResolveAdapter | CreateChildControls | ||
CreateChildControls | CreateChildControls | OnPreRender | ||
OnPreRender | OnPreRender | SaveViewState | ||
SaveViewState | SaveViewState | HasControls | ||
HasControls | HasControls | RenderControl | ||
RenderControl | RenderControl | Render | ||
Render | Render | RenderBeginTag | ||
RenderBeginTag | RenderBeginTag | AddAttributesToRender | ||
AddAttributesToRender | AddAttributesToRender | RenderContents | ||
RenderContents | RenderContents | RenderChildren | ||
RenderChildren | RenderChildren | RenderEndTag | ||
RenderEndTag | RenderEndTag | OnUnload | ||
OnUnload | OnUnload | Dispose | ||
Dispose | Dispose |
There are a couple of things to note here. First, in the Adding scenario – when the web part is being added to the page, two instances of the web part are created but only one of them has events fired against it. You’ll have to trust me that it’s only one instance that’s being used. This means we’ve got one Dispose method call that’s missing. i.e. Web Parts must implement IDisposable which is the Dispose method and the dispose method should be called every time the web part is created. When I get to the closed scenario is where it gets bad. When you’re closing the web part and when the web part is closed you only get one constructor – but never a dispose.
By the way, please don’t get too hung up on the order of events here. You’ll see that HasControls fired twice in the Regular Load scenario – that’s pretty normal to have some slight variations in timing that cause a few extra or fewer calls. This might serve as a rough framework but it’s not the final word on event firing. (You’ve been warned.)
Back to our story… what does all of this mean? Well, let me first say that I’ve had several folks who’ve asked me questions via email over the years and when it comes to be parts I always encourage them to move code out of the constructor and into OnInit or one of the other functions. In Web Part land there’s just not enough spun up at constructor time for things to work all the time. I’ve had more than a few folks say that their web parts magically started working once they moved code back into OnInit. So again, what does this mean?
Essentially, unless you’ve got a good reason, don’t use the Web Part’s constructor. I’ve seen problems with web parts that use it and this latest data seems to show that the dispose method doesn’t always get called – in some cases you’ll get a constructor call but no Dispose. However, in every case if OnInit is called there seems to be an Dispose call.
No comment yet, add your voice below!