I'm trying to figure out a work around for using multiple lifetimes with a single Container.
The problem is related to InstancePerRequest()
implementation.
There is an application based on WebAPI with custom WebHandler, so Autofac can not define whether the LifetimeScope
is initialized or disposed. So i can not use basic InstancePerRequest()
. I decided to implement semi-custom InstancePerRequest()
according to Autofac documentation
The Autofac registration looks like this:
...
private static IContainer Container;
private static void RegisterServices()
{
var builder = new ContainerBuilder();
builder.Register((c, p) => new CustomClass(p.Named<List<int>>("codes"), p.Named<User>("user")))
.InstancePerRequest();
Container = builder.Build();
}
public static ILifetimeScope BeginLifetimeScope()
{
return Container.BeginLifetimeScope(new[] { MatchingScopeLifetimeTags.RequestLifetimeScopeTag });
}
...
MatchingScopeLifetimeTags.RequestLifetimeScopeTag
is required in Autofac Custom per-request semantics according to this article (point 2)
So i manually create LifetimeScope
:
... // AutofacHelper.BeginLifetimeScope() is implemented above
using (var lifetimeScope = AutofacHelper.BeginLifetimeScope())
{
result = InvokeRequest(request.Api, context);
}
...
The problem is that there are as many LifetimeScope
's as requests. And the scope i need begins far away from the code, where i need to access it. I need to have access to the current scope from anywhere.
I guess i have to tag every LifetimeScope
with HttpContext.Current
and that would be unique enough to define which scope i need to use.
But how do i do that? Implementing BeginLifetimeScope()
with parameter new[] { MatchingScopeLifetimeTags.RequestLifetimeScopeTag, HttpContext.Current }
leads to exception as it can not find requested scope.
Is there a way to define which scope is being used in current request? Using my custom unique tag for example? ILifetimeScope
has implementation for parent scopes only. Is there a reason for not implementing child scopes so i could take them according to HttpContext.Current
?
Any ideas?
Thanks!
I think what you have is actually totally correct.
The problem is that there are as many LifetimeScope's as requests
That's not a problem, that's how it works. Even into ASP.NET Core today, and not even just Autofac - instance per request means one lifetime scope per request.
You have a couple of options to track the lifetime scope.
First, you can inject ILifetimeScope
into any constructor and the thing that gets injected is the lifetime scope that owns the object. So if you have something registered InstancePerRequest
then you can just add an ILifetimeScope
constructor parameter... and it gets the request scope.
Second, you can always store the lifetime scope in HttpContext.Current
when you create it.
using (var lifetimeScope = AutofacHelper.BeginLifetimeScope())
{
HttpContext.Current.Items["RequestLifetimeScope"] = lifetimeScope;
result = InvokeRequest(request.Api, context);
}
Then if you absolutely must get that scope for, like, service location, you can do it from the current context.
var scope = (ILifetimeScope)HttpContext.Current.Items["RequestLifetimeScope"];
var x = scope.Resolve<IService>();
If you want more pointers on where you can store the scope, how you can access it... or even if you want to use some of the built-in helpers, I'd check out the source for the Autofac WebAPI integration. You also may be interested in looking at how Web API itself moves the request scope around - it stores the scope along with the inbound request message so you can call message.GetDependencyScope()
and get the current lifetime scope. You could do something similar.
If you're using an OWIN pipeline, there is OWIN integration for WebAPI, too that might give you some ideas about how things are hooked up.