WindsorContainer not releasing transient components when are dependencies of SS services

I’m using Windsor as IoC through the

public sealed class WindsorContainerAdapter : IContainerAdapter, IDisposable, IRelease

I implemented IRelease interface to implement the RRR pattern correctly as suggest in your StackOverflow post

my sample object graph is the following

  • HelloService (SS service)
  • MyComp1
  • MyComp2

I do register my custom component in windsor
MyComp1 → LifestyleTransient
MyComp2 → LifestylePerWebRequest

as per SS wiki The IoC container · ServiceStack/ServiceStack Wiki · GitHub

the services are still registered in Funq but all their dependencies are resolved by the ContainerAdapter specified

Due to IRelease interface on WindsorContainerAdapter the Release method within AppHost has been called

var iocAdapterReleases = Container.Adapter as IRelease;
if (iocAdapterReleases != null)
{
    iocAdapterReleases.Release(instance);
}
else 
{
    var disposable = instance as IDisposable;
    if (disposable != null)
        disposable.Dispose();
}

but the “instance” object is HelloService, not MyComp1: that leads to have a zombie object(the instance of MyComp1 resolved through Windsor since that’s a dependecy oh HelloService) on each request: since the Release has been invoke on a an instance not created by Windsor is useless, while it should be called on each instance created through windsor
Since WindsorAdapter implements IRelease, HelloService will be tried to be disposed by windsor, but since it has not been created by Windsor, nothing happend: even worst the HelloService will not be disposed at all!

From the wiki

So to have resolved services released back into your IOC, implement the IRelease interface on your IContainerAdapter, e.g:

Why Windsor should dispose an instance (HelloService) that has not been Register neither so Resolved by itself???

In the other hand, MyComp2 will be disposed correctly since its lifestyle is PerWebRequest, so windsor take care of releasing it by itself with no explicit Release called on the instance.
If I change the MyComp1 lifestyle fromTransient to PerWebRequest it will be disposed correctly as well…

Now the question is: since SS/Funq invoke Windosor Resolve for MyComp1( since that’s a dependency of HelloService) IT SHOULD some how invoke Release as well (I assume throught the Release method within AppHost)
According to the “composition root” pattern, the Resolve/Release should be called only on the SS Services (HelloService in my sample)

Apparently the IRelease on WindsorContainerAdapter seems to having the following issues:

  • not Releasing the component Resolved by SS/service dependencies → zombie objects = memory leak

  • prevent the SS services disposing → what that gonna cause?

what am I missing here?

The hooks in ServiceStack are there to pass any dependencies back to the registered Container Adapter so it’s able to do whatever it needs to do, e.g. dispose of the Service, inspect its properties and dispose of any of its resolved dependencies if needed.

When the Adapter implements IRelease then it’s taking responsibility for disposing of the Service and all other IDisposable instances. So the Adapter can take care of disposing of the Service, i.e. Windsor doesn’t have to do it itself.

Let me know if there’s something else the Container Adapter needs that it’s not getting atm.

The adapter has to check in the object received ad input in Release is a “SS Service” so it calls the dispose… Understood, but since MyComp1 has been injected as constructor dependency, I don’t see any other way rather then a heavy use or reflection to find all SS service dependency created through windsor.
Again the point should be: Who resolved ( SS service) has to release according to the RRR pattern: within the adapter Release method, if the input is SS service, a dedicated method should be invoked on the SS service to release(through the custom ioc) the dependecies previously created through the custom ioc.

Somenthing like this

Adapter.Release(object)
{
var s=object sa Service;
If(s!=null)
s.ReleaseDependencies(_customContainer)

Or even better, the ss service Dispose should take care to release through the adapter all dependecies it has previously created through the adapter:
Adapter Release should online be a wrapper to the custom ioc Release method nothing else.

ServiceStack uses IContainerAdapter.Resolve<T> to resolve constructor dependencies and IContainerAdapter.TryResolve<T> to resolve and inject any property dependencies.

Dependencies that implement IDisposable are explicitly released through IRelease.Release().

The base Service class doesn’t know about any dependencies that are injected into the sub-class constructor, but the subclass can override Dispose() to manually dispose of them.

So the only possible solution I could figure out is something like this within the Adapter that implements IRelease

    public T Resolve<T>()
    {
    	var cmp = _container.Resolve<T>();
    
    	lock (_lock)//TOCHECK: do we really need?
    	{
    		var list = HttpContext.Current.Items["AdapterInstances"] as List<object> ?? new List<object>();
    		list.Add(cmp);
    		HttpContext.Current.Items["AdapterInstances"] = list;				
    	}
    
    	return cmp;
    }
    
public void Release(object instance)
{
	// disposing SS services and other ServiceStack instances geenrated by itself
	var disposable = instance as IDisposable;
	if (disposable != null)
		disposable.Dispose();

	var list = HttpContext.Current.Items["AdapterInstances"] as List<object>;
	if (list != null)
	{
		foreach (var cmp in list)
		{
			_container.Release(cmp);
		}

		HttpContext.Current.Items["AdapterInstances"] = null;
	}
}

do you agree? Any other options?

Is MyComp1 IDisposable? as it should already be explicitly released with IRelease.Release().

You don’t need to lock around HttpContext.Current since its specific to the Request WorkerHandler Thread, but yeah that would work. We use HttpContext.Current.Items to track IDisposables as well.

Yes, MyComp1 is IDisposable, but since has been created/resolved by Windsor, Windsor controls it so you need to explicitly release it through windsor: that’s what all the thread is about

I cannot release through IRelease.Release(). MyComp1 will not be passed by default as input paramerter since windsor hold a reference to it: that way I need the HttpContext.Items storage…

see

http://kozmic.net/2010/08/27/must-i-release-everything-when-using-windsor/