Reputation: 58484
For my ASP.NET Web API project, I have the following set up which uses Autofac as the IoC container:
protected void Application_Start(object sender, EventArgs e)
{
HttpConfiguration config = GlobalConfiguration.Configuration;
config.DependencyResolver =
new AutofacWebApiDependencyResolver(
RegisterServices(new ContainerBuilder()));
config.Routes.MapHttpRoute("DefaultRoute", "api/{controller}");
}
private static IContainer RegisterServices(ContainerBuilder builder)
{
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<ConfContext>().InstancePerApiRequest();
return builder.Build();
}
And I have the following message handler which retrieves the ConfContext
instance just for fun:
public class MyHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
ConfContext ctx = (ConfContext)request.GetDependencyScope().GetService(typeof(ConfContext));
return base.SendAsync(request, cancellationToken);
}
}
As my message handler will be called before the controller is constructed, I should get the same ConfContext
instance at the controller. However, I want to get separate instances if I try to retrieve a ConfContext
as Func<Owned<ConfContext>>
but I am getting the same instance. If I remove the InstancePerApiRequest
registration, I will lose the Per API request support on cases where I want to just retrieve the ConfContext
as it is.
Is there any way to support both cases here?
Edit
Sample application is here: https://github.com/tugberkugurlu/EntityFrameworkSamples/tree/master/EFConcurrentAsyncSample/EFConcurrentAsyncSample.Api
Upvotes: 2
Views: 925
Reputation: 3831
In Autofac 3.0 I added support for applying multiple tags to a lifetime scope. You can use this to apply tags for the API request and Owned instance lifetime scopes.
The tag for Web API lifetime scopes is exposed via the AutofacWebApiDependencyResolver.ApiRequestTag
property, and Owned<T>
lifetime scopes are tagged with their entry point new TypedService(typeof(T))
.
Put that together into a handy registration extension method and you get the code below.
public static class RegistrationExtensions
{
public static IRegistrationBuilder<TLimit, TActivatorData, TStyle>
InstancePerApiRequestOrOwned<TLimit, TActivatorData, TStyle>(
this IRegistrationBuilder<TLimit, TActivatorData, TStyle> registration)
{
if (registration == null) throw new ArgumentNullException("registration");
var tags = new object[] {AutofacWebApiDependencyResolver.ApiRequestTag, new TypedService(typeof(TLimit))};
return registration.InstancePerMatchingLifetimeScope(tags);
}
}
Now you can use the extension method when registering your types and all is well.
builder.RegisterType<ConfContext>().InstancePerApiRequestOrOwned();
I sent you a pull request demonstrating this code.
https://github.com/tugberkugurlu/EntityFrameworkSamples/pull/1
Upvotes: 4