This is a follow up to my previous post. If you haven’t yet – go and read that one first. I’ll wait.
So where were we? Aha…
In the last post I said, that Windsor (any container in general) creates objects for you, hence it owns them, ergo its responsibility is to properly end their lifetime when they’re no longer needed.
Since as I mentioned in my previous post, Windsor will track your component, it’s a common misconception held by users that in order to properly release all components they must call Release method on the container.
How will Windsor know I no longer need an object?
That’s the most important part of this post really, so pay attention.
In Windsor (every container in general) every component has a lifestyle associated with it. In short lifestyle defines the context in which an instance should be reused. If you want to have just single instance of a component in the context of the container, you give the object a singleton lifestyle (which is the default in Windsor). If you want to reuse your object in the context of a web request, you give it a lifestyle of a per-web-request and so on. Now the word context (though overloaded) is important here.
When the context ends?
While some contexts, like web request have a well defined ends that Windsor can detect, that’s not the case for every of them. This brings us to the Release method.
Windsor has a Release method that you use to explicitly tell it “hey, I’m not gonna use this this object anymore.” Although the method is named very imperatively, which would suggest it takes immediate action, it’s not often the case. Quite a lot of time may pass between you call the method and Windsor will get the object destroyed. When the object gets really destroyed is up to its lifestyle manager, and they act differently.
- Singleton will ignore your call to Release because the instance is global in the scope of the container that created it, and the fact that you don’t need the object in one place does not mean you won’t need it moments later somewhere else. The scope of the singleton lifestyle has a well defined end. Windsor will destroy the singletons when the container itself is being disposed. This also means that you don’t have to Release your singletons – disposing of the container will take care of that.
- Per-web-request will ignore your call to Release for similar reasons – the object is global in the scope of a web-request. Web request also has a well defined end, so it will wait with destroying the object till the end of the web request and then do all the work necessary. This also means that you don’t have to release your per-web-request components – Windsor can detect end of a web request and release the per-web-request components without and intervention from your side.
- Per-thread is like singleton in the scope of a thread. Releasing Per-thread components does nothing, they will be released when the container is disposed. This means that in this case as well you don’t have to do anything explicitly about them (except for remembering to dispose the container obviously) ..
- Pooled components are different. They don’t really have a well defined “end” so you need to return a component to the pool explicitly (that is pass them to container’s Release method), and Windsor (depending on the component and configuration of the pool) may either return the object to the pool, recycle it, or destroy and let it go. Thing is - it matters, and it usually makes sense to return the object to the pool, as soon as possible (think connection pooling in ADO.NET).
- Transient components are similar to pooled, because there’s no well known end to transient component’s lifetime, and Windsor will not know if you still want to use a component or not, unless you explicitly tell it (by calling Release). Since transient components are by definition non-shared Windsor will immediately destroy the component when you Release it.
And then it gets interesting
If you’re now scratching your head thinking “Does Windsor really puts all the burden of releasing stuff on me?” don’t despair. The reality is – you never have to call Release explicitly in your application code. Here’s why.
You never have to call Release…
Releasing a component releases entire graph. As outlined in previous section, Windsor can detect end of scope for components with most lifetimes. In that case, if you have a per-web-request ShoppingCard component that depends on transient PaymentCalculationService and singleton AuditWriter, when the request ends Windsor will release the shopping card along with both of its dependencies. Since auditwriter is a singleton releasing it will not have any effect (which is what we want) but the transient payment calculator will be releases without you having to do anything explicitly.
You obviously need to structure your application properly for this to work. If you’re abusing the container as service locator than you’re cutting a branch you’re sitting on.
This also works with typed factories – when a factory is released, all the components that you pulled via the factory will be released as well. However you need to be cautious here – if you’re expecting to be pulling many components during factory’s lifetime (especially if the factory is a singleton) you may end up needlessly holding on to the components for much too long, causing a memory leak.
Imagine you’re writing a web browser, and you have a TabFactory, that creates tabs to display in your browser. The factory would be a singleton in your application, but the tabs it produces would be transient – user can open many tabs, then close them, then open some more, and close them as well. Being a web savvy person you probably know firsthand how quickly memory consumption in a web browser can go up so you certainly don’t want to wait until you dispose of your container to release the factory and release all the tabs it ever created, even the ones that were closed days ago.
More likely you’d want to tell Windsor to release your transient tabs as soon as the user closes it. Easy – just make sure your TabFactory has a releasing method that you call when the tab is closed. The important piece here is that you’d be calling a method on a factory interface that is part of your application code, not method on the container (well – ultimately that will be the result, but you don’t do this explicitly).
As Mark pointed out in the comment there are certain low level components that act as factories for the root object in our application (IControllerFactory in MVC, IInstanceProvider in WCF etc). If you’re not using typed factories to provide these service and implement them manually pulling stuff from the container, than the other rule (discussed below) applies - release anything you explicitly resolve
In your application code
There are places where you do need to call Release explicitly – in code that extends or modifies the container. For example if you’re using a factory method to create a component by resolving another component first, you should release the other component.
var country = k.Resolve<ICountry>(user.CountryCode);
var taxCalculator = country.GetTaxCalculator();
This is a code you could place in one of your installers. It is completely artificial but that’s not the point. Point is, we’re using a factory method to provide instances of a component (tax calculator) and for this we’re using another component (country). Remember the rule – You have to release anything you explicitly resolve. We did resolve the country, so unless we are sure that the country is and always will be a singleton or have one of the other self-releasing lifestyles, we should release it before returning the tax calculator.
08-27-2010 3:52 AM