Windsor Container: How to force dispose of an object?
Asked Answered
S

3

11

I have an object that implements IDisposable that is registered with the Windsor Container and I would like to dispose of it so it's Dispose method is called and next time Resolve is called it fetches a new instance.

Does

container.Release(obj); 

automatically call Dispose() immediately? Or do I need to do

obj.Dispose();
container.Release(obj);

Couldn't find anything in the documentation on what exactly Release does

EDIT: See my answer below for the results of tests I ran. Now the question becomes, how do I force the container to release an instance of a component with a singleton lifecycle? This only needs to be done in one place and writing a custom lifecycle seems far too heavyweight, is there no built in way of doing it?

Skive answered 17/9, 2008 at 16:44 Comment(0)
M
14

This is something I think people aren't really aware of when working with the Windsor container - especially the often surprising behavior that disposable transient components are held onto by the container for the lifetime of the kernel until it's disposed unless you release them yourself - though it is documented - take a look here - but to quickly quote:

the MicroKernel has a pluggable release policy that can hook up and implement some routing to dispose the components. The MicroKernel comes with three IReleasePolicy implementations:

  • AllComponentsReleasePolicy: track all components to enforce correct disposal upon the MicroKernel instance disposal
  • LifecycledComponentsReleasePolicy: only track components that have a decommission lifecycle associated
  • NoTrackingReleasePolicy: does not perform any tracking

You can also implement your own release policy by using the interface IReleasePolicy.

What you might find easier is to change the policy to a NoTrackingReleasePolicy and then handle the disposing yourself - this is potentially risky as well, but if your lifestyles are largely transient (or if when your container is disposed your application is about to close anyway) it's probably not a big deal. Remember however that any components which have already been injected with the singleton will hold a reference, so you could end up causing problems trying to "refresh" your singletons - it seems like a bad practice, and I wonder if perhaps you can avoid having to do this in the first place by improving the way your applications put together.

Other approaches are to build a custom lifecycle with it's own decommission implementation (so releasing the singleton would actually dispose of the component, much like the transient lifecycle does).

Alternatively another approach is to have a decorator for your service registered in the container with a singleton lifestyle, but your actual underlying service registered in the container with a transient lifestyle - then when you need to refresh the component just dispose of the transient underlying component held by the decorator and replace it with a freshly resolved instance (resolve it using the components key, rather then the service, to avoid getting the decorator) - this avoids issues with other singleton services (which aren't being "refreshed") from holding onto stale services which have been disposed of making them unusable, but does require a bit of casting etc. to make it work.

Mellman answered 3/10, 2008 at 11:55 Comment(2)
I have a similar problem, i very much like the decorator concept very much. Nice one...Marte
@Mellman if I am disposing the container will it call dispose for singleton objects how to force it?Jeromyjerreed
I
3

It depends on the lifestyle of the component you specified when you added it to the container.

You would use Release() If the lifestyle is Pooled. This puts the component back in the pool for the next retrieval (the object is not destroyed, so disposing would be bad)

if the lifestyle is transient, a new object is created when you get the component. In this case the disposal is up to you, and you do not need to call Release

If the lifestyle is Thread, the same component is used for each thread, not destroyed.

If the lifestyle is Singleton, only one component is created and not detroyed.

Most likely, you are using transient components? (if you are concerned about disposing of them in a timely manner) in that case, just wrap it with a using and you're set (or call the dispose yourself somewhere)

using(ISomeService service = container.Resolve<ISomeService>())
{
 // Do stuff here
 // service.Dispose is automatically called 
}

Edit - Yes, in order to "refresh" or dispose and recreate your singleton you would need to either destroy the container or write a custom lifecycle. Doing a custom lifecycle is not actually that difficult and keeps the logic to do so in one place.

Intone answered 17/9, 2008 at 17:15 Comment(1)
Actually I'm doing singletons but would like to force it to regenerate the component occasionally.Skive
S
1

Alright, so I've been running tests and it seems like Container.Release() WILL implicitly cause an IDisposable's Dispose() method to execute only if the lifestyle is Transient (this is probably not exactly correct but point is that it wont' do a darn thing if the lifestyle is singleton).

Now if you call Container.Dispose() it WILL call the disposable methods also, though unfortunately it will dispose of the whole kernel and you will have to add all components back in:

var container = new WindsorContainer();
container.AddComponentWithLifestyle<MyDisposable>(Castle.Core.LifestyleType.Singleton);
var obj = container.Resolve<MyDisposable>();  // Create a new instance of MyDisposable
obj.DoSomething();
var obj2 = container.Resolve<MyDisposable>();  // Returns the same instance as obj
obj2.DoSomething();
container.Dispose();  // Will call the Disposable method of obj
// Now the components need to be added back in   
 container.AddComponentWithLifestyle<MyDisposable>(Castle.Core.LifestyleType.Singleton);
var obj3 = container.Resolve<MyDisposable>();  // Create a new instance of MyDisposable

Fortunately in my case I can afford to just drop all components and I can restore them fairly easily. However this is sub-optimal.

Skive answered 17/9, 2008 at 17:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.