Must Windsor track my components?

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?

lifecycle_simplifiedOne 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.

It depends.

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.


Posted 08-19-2010 3:07 PM by Krzysztof Koźmic
Filed under: , ,

[Advertisement]

Comments

Julian Birch wrote re: Must Windsor track my components?
on 08-20-2010 1:40 AM

I'm afraid I don't agree, (as you know).  The problem is: how on earth are you meant to write

public ObjectThatDependsOnFactory(Func<DisposableServiceInWindsor> factory) {

}

Without a memory leak?  The only answer appears to be to break abstraction.  You shouldn't need to know your code is running under an IoC container.

Armin wrote re: Must Windsor track my components?
on 08-20-2010 5:21 AM

@Julian: Very interesting comment!

I suggest, that in this case, and because of symmetry (when you create it, you must destroy it), the client needs to maintain the lifetime of this object by wrapping it in a using() or disposing it in its very own Dispose().

But the problem persists if the container creates dependent "IDisposable" instances when the "factory" function is called. Arguably, this is the container's responsibility.

So the only option I see, is to use Dispose() and restrict the factory types to interfaces and create a dynamic proxy around them. The proxy's IDisposable implementation calls Dispose() on the returned instance and then on all (lifetime) dependent instances.

Krzysztof Koźmic wrote re: Must Windsor track my components?
on 08-20-2010 11:27 PM

@Julian

I'll touch upon it the next post.

In short - this may not be an issue in some cases. In other cases don't use delegate - use interface-based factory with methods like:

DisposableServiceInWindsor GiveMeTheService();

void TakeItIDontNeedItAnymore(DisposableServiceInWindsor instance)

if you really want to stick to a delegate you can do what Armin is suggesting (I had a post about this a while back) or you can take similar approach to what Autofac is doing and create Owned<T> class, alghouth that would require slight customization of ReleasePolicy to not track Owned<> itself..

Anyway, this is a trade of and you are constrained by the delegate here.

Julian Birch wrote re: Must Windsor track my components?
on 08-24-2010 11:15 AM

I think the Owned<T> model's probably the least ugly here.  Although intercepting Dispose remains an option (the real question's what kind of performance impact it has).

Going back to the Owned<T> model, what would be ideal is if you used a transient that needed to be tracked, it refused to give you the object directly.  Of course, that'll break existing code.  Welcome to the World of the Future.

And yes, you could design your interfaces with object release in mind, but the CSL doesn't, and Caliburn uses CSL... in general terms I think you'll find very few libraries designed the way you describe.

The thing I really dislike about the current arrangement is that it often results in you memory leaking only because you used Castle Windsor in the first place.  

Can't believe we've been discussing this for two years now...

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)