Probably the single most misunderstood feature of Castle Windsor is regarding its lifetime management of components. Hopefully in this post (and the next one) I’ll be able to clear all the misconceptions.
Why is Windsor tracking components in the first place?
One of the core responsibilities of a container is to manage lifecycle of components. At a very high level it looks like in the picture on the right. The container creates the object, sets it up, then when it’s ready to go, it gives it to you, so that you can use it, and when it’s no longer needed it carefully tears it apart and sends it to happy hunting ground. Many people forget about that last part, and indeed some containers lack support for this crucial element at all.
In order to be able to identify objects it created and destroy them when their time has come, Windsor obviously needs to have access to them and that’s why it keeps reference to the objects it needs to destroy.
Destroy objects. What does that even mean?
I’ve been pretty abstract until now, let’s look at an actual (trivialized) example .
public class UnitOfWork
public void Init()
// some initialization logic...
public void Commit()
// commit or rollback the UoW
We want to create the instance of our UnitOfWork, then before we use it, we want to initialize it, then use it for a while to do the work, and then when we’re done, commit all the work that we’ve done. Usually in a web-app the lifetime of the unit or work would be bound to a single web request, in a client app it could be bound to a screen.
It is container’s work to create the object. It’s container’s work to initialize it. So that I don’t need to remember to call the Init method myself. Especially that within a web request (let’s stick to the web example) I can (and likely will) have multiple components depending on my unit of work. Which one of them should call Init?
None. It’s not their job. Their job is to make use of it. Be lazy and outsource this to the container. Which of my components should Commit the unit of work? Also none.
None of my components is responsible for the unit of work, since none of them created it. The container did, so it’s container’s job to clean up after the object when I’m done using it.
The destroy part is just it – do all the things with the components that need to be done after the component is no longer being used by the application code, but before the object can be let go. The most common example of that is the IDisposable interface and Dispose method.
The rule in .NET framework is very simple when it comes to Disposing objects.
Dispose what you’ve created, when you’re done using it.
Hence clearly since the container is creating the object it’s its responsibility to dispose of them. In Windsor lingo, you’d call the Init method on the UnitOfWork a commission concern and the Commit method a decommission concern.
What if my object requires no clean up? Will Windsor still track it?
This is a very important question. The answer is also important. In short.
Windsor by default will track objects that themselves have any decommission concerns, are pooled, or any of their dependencies is tracked.
We will discuss this in more details in a future post, since it is a big and important topic. In short though – you as a user of a component should not know all these things (especially that they can change), so you should treat all components as being tracked..
What do you mean by default?
Windsor is very modular and unsurprisingly tracking of components is contained in a single object, called release policy. The behavior described above is the behavior of default, LifecycledComponentsReleasePolicy. Windsor comes also with alternative implementation called NoTrackingReleasePolicy which as its name implies will never ever track your components, hence you never want to use it.
Now seriously – often people see that Windsor holds on to the components it creates as a memory leak (it often is, when used inappropriately which I’ll talk about in the next post), and they go – Windsor holding on to the objects causes memory leaks, so lets use the NoTrackingReleasePolicy and the problem is solved.
This reasoning is flawed, because the actual reason is you not using this feature correctly, not the feature itself. By switching to no tracking, you end up out of the frying pan and into the fire, since by not destroying your objects properly you’ll be facing much more subtle, harder to find and potentially more severe in results bugs (like units of works not being committed, hence losing work of your users). So in closing – it’s there when you need it, but even when you thing you need it, you really don’t.
08-19-2010 3:07 PM