tugberk
tugberk

Reputation: 58484

Autofac OwnedInstances and ASP.NET Web API's InstancePerApiRequest support

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

Answers (1)

Alex Meyer-Gleaves
Alex Meyer-Gleaves

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

Related Questions