Skip to content

_AspNet_WebApi_DependencyInjectionwithAutofac

Michael Powell edited this page Feb 4, 2017 · 1 revision

Background and ASP.NET migration paths

See ASP.NET migration path for further details.

Dependency Injection with Autofac

Exposing performance measurement into ASP.NET Web API via Autofac is just a bit different than with Castle Windsor.

Package References
MeasureIt.AspNet.WebApi.Autofac
Microsoft.AspNet.WebApi.Core
Autofac.WebApi2
MeasureIt.AspNet.WebApi.Core
MeasureIt.AspNet.WebApi.Core
Microsoft.AspNet.WebApi.Core
MeasureIt.Core
MeasureIt.Core

Decorate your classes

See Decorating Your Controllers in Web API.

Wire up your measurement filters

Feel free to review the MeasuredStartupFixture.cs example, which is beyond the immediate scope of this documentation. Whether you run with a self-hosted server, you have to still do all the normal things you would do connecting your filters, routes, bundles, and so on. Additionally, some specific Castle Windsor things.

With Web API you generally require an HttpConfiguration. Starting from the ContainerBuilder and using the Autofac IContainer:

ContainerBuilder Builder { get; }
Builder new ContainerBuilder();
IContainer Container { get; }
Container = Builder.Build();

There are several things that need to occur besides the basics of connecting routes with controllers and actions.

First install the Web API services using, in this case, the StartupFixture to identify the assembly (or assemblies when otherTypes is specified) from which to identify ApiController types.

But before that, it is necessary to install a couple of services for Autofac usage.

Builder.RegisterApiServices<
    AutofacWebApiDependencyResolver
    , AutofacHttpControllerActivator
    , TraceExceptionLogger>();

In this case we want not only the third-party AutofacWebApiDependencyResolver, but also our AutofacHttpControllerActivator, as well as the TraceExceptionLogger, which is used in the text fixture in order to expose any internal exceptions that may occur during run time warm up.

Following which we register the ApiController classes found in the assembly.

Builder.RegisterApiControllers(typeof(MeasuredController).Assembly)

After building the Autofac Container, then use the container and middleware.

app.UseAutofacWebApi(config);
app.UseAutofacMiddleware(container);

Finally, inform the HttpConfiguration as to what its DependencyResolver ought to be.

config.DependencyResolver = container.Resolve<IDependencyResolver>();

Then we much configure for measurements to occur via the MeasuredStartupFixture:

Builder.EnableApiMeasurements<
    IHttpActionInstrumentationDiscoveryService
    , HttpActionInstrumentationDiscoveryService>(CreateDiscoveryOptions);

And remember the options:

private static InstrumentationDiscoveryOptions CreateDiscoveryOptions()
{
    return new InstrumentationDiscoveryOptions
    {
        ThrowOnInstallerFailure = false,
        ThrowOnUninstallerFailure = false,
        Assemblies = new[]
        {
            typeof(MeasuredController).Assembly
            , typeof(AverageTimePerformanceCounterAdapter).Assembly
        }
    };
}

Enabling measurements can happen in a couple different ways:

public static ContainerBuilder EnableApiMeasurements<TInterface, TService>(
    this ContainerBuilder builder
    , Func<InstrumentationDiscoveryOptions> createOptions = null)
    where TInterface : class, IHttpActionInstrumentationDiscoveryService
    where TService : class, TInterface;
public static ContainerBuilder EnableApiMeasurements<TInterface, TService, TOptions>(
    this ContainerBuilder builder
    , Func<TOptions> createOptions = null)
    where TInterface : class, IHttpActionInstrumentationDiscoveryService
    where TService : class, TInterface
    where TOptions : class, IInstrumentationDiscoveryOptions, new();
public static ContainerBuilder EnableApiMeasurements<TInterface, TService, TOptions, TProvider>(
    this ContainerBuilder builder
    , Func<TOptions> createOptions = null)
    where TInterface : class, IHttpActionInstrumentationDiscoveryService
    where TService : class, TInterface
    where TOptions : class, IInstrumentationDiscoveryOptions, new()
    where TProvider : class, ITwoStageMeasurementProvider;

Then the categories must be installed. In a production environment, something like this might be done via some sort of installation procedure.

private void Install<TDiscoveryService>()
    where TDiscoveryService : class, IInstallerInstrumentationDiscoveryService
{
    // Where the Container may be found in the calling scope.
    var discoveryService = Container.Resolve<TDiscoveryService>();

    using (var context = discoveryService.GetInstallerContext())
    {
        context.Install();
    }
}

In the case of the unit testing, I install a couple different ways:

Install<IInstallerInstrumentationDiscoveryService>();
Install<IHttpActionInstrumentationDiscoveryService>();

And that's it. Feel free to run the unit tests for yourself to see how it works. Happy measuring!