Working with ServiceStack I've stuck with the problem of objects lifetime management in self-hosted web application.
My requirements:
General problem:
Castle Windsor IoC implements its own per-request lifetime strategy but it is binded to http modules, thus it works only with IIS hosted apps. Hence, I have to implement my custom IScopeAccessor (provided by Castle Windsor) to handle objects lifetime. The problem here is in absence of hooks which I can use to bind to current request.
Given
public class MyScopeAccessor : IScopeAccessor
{
public ILifetimeScope GetScope(CreationContext context)
{
//implement it
}
}
I have to implement GetScope method.
There are two main ideas I cannot complete:
Using of [Threadstatic]
In MyScopeAccessor I just store
[ThreadStatic]
private static ILifetimeScope _currentLifetimeScope;
and create new scope after first GetScope if it's not initialzied yet.
Problems:
Using of IRequest instance
In MyScopeAccessor I just store
private static readonly ConcurrentDictionary<IRequest, ILifetimeScope> LifetimeScopes;
and create and dispose current lifetime scope in corresponding custom ServiceRunner methods (OnBeforeEachRequest, OnAfterEachRequest).
Problems:
Also, it is interesting if ServiceStack default Funq IoC solves this problem.
Funq does handle RequestScoped dependencies which stores Request Context dependencies in the RequestContext.Instance.Items[]
dictionary.
Any disposables can be registered in RequestContext.Instance.TrackDisposable()
are automatically disposed of at the end of the request.
At the end of each request AppHost.OnEndRequest()
is fired which goes through and releases any dependencies stored in the RequestContext for that request.
If your Windsor ContainerAdapter implements the IRelease
interface it's automatically called to release any instances which can be handled itself. Both these API's are overridable in your AppHost
if you want to change the default behavior:
public virtual void OnEndRequest()
{
var disposables = RequestContext.Instance.Items.Values;
foreach (var item in disposables)
{
Release(item);
}
RequestContext.Instance.EndRequest();
}
public virtual void Release(object instance)
{
try
{
var iocAdapterReleases = Container.Adapter as IRelease;
if (iocAdapterReleases != null)
{
iocAdapterReleases.Release(instance);
}
else
{
var disposable = instance as IDisposable;
if (disposable != null)
disposable.Dispose();
}
}
catch { /*ignore*/ }
}