How to use Autofac to resolve instance per request dependencies for types in a child lifetime scope created by Nancy

autofac, c#, dependency-injection, nancy

Solution

Autofac should automatically resolve instances from "parent" lifetimes. If you configure your registrations using `InstancePerRequest`, Autofac will register these services with a special lifetime tag, `MatchingScopeLifetimeTags.RequestLifetimeScopeTag`, so it can be resolved in the correct scope later.

This means that there's no need to use the Nancy bootstrapper's `ConfigureRequestContainer` method to do request-scoped registrations. You've already done it! As long as Nancy creates the request lifetime using the same tag used in `InstancePerRequest` (this is done by default as of Nancy 1.1), the services should be resolved correctly.

Example:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var builder = new ContainerBuilder();

        // Do request-scoped registrations using InstancePerRequest...

        var container = builder.Build();

        // Pass the pre-built container to the bootstrapper
        var bootstrapper = new MyAwesomeNancyBootstrapper(container);

        app.UseNancy(options => options.Bootstrapper = bootstrapper);
    }
}
public class MyAwesomeNancyBootstrapper : AutofacNancyBootstrapper
{
    private readonly ILifetimeScope _lifetimeScope;

    public MyAwesomeNancyBootstrapper(ILifetimeScope lifetimeScope)
    {
        _lifetimeScope = lifetimeScope;
    }

    protected override ILifetimeScope GetApplicationContainer()
    {
        return _lifetimeScope; // Tell Nancy you've got a container ready to go ;)
    }
}

This setup should be enough (As of Nancy 1.1. In earlier versions you have to also override the `CreateRequestContainer` method and pass the request lifetime tag when creating the request lifetime scope).

EDIT: I put together an example for you at https://github.com/khellang/Nancy.AutofacExample

Problem

We have several applications hosted in Windows services that self host a Nancy endpoint in order to expose instrumentation about the operation of the applications. We use Autofac as our IOC. Several repositories are registered into the root container in a core DLL shared by all applications; this container is then passed to Nancy as its container using a bootstrapper derived from the `Nancy.Autofac.Bootstrapper`. What we found was that when a web request is received by Nancy it resolves a request for a repository from the root container and this led to memory being consumed by non-garbage collected `IDisposable`s as the root container does not go out of scope (it has the lifetime of the windows service). This led to the services "leaking" memory. We then switched to a model where we added registrations for the repositories using `InstancePerRequest` in the overridden `ConfigureRequestContainer()` method in our Nancy bootstrapper: ``` protected override void ConfigureRequestContainer(ILifetimeScope container, NancyContext context) { base.ConfigureRequestContainer(container, context); PerRequestContainerBuilder().Update(container.ComponentRegistry); } private static ContainerBuilder PerRequestContainerBuilder() { var builder = new ContainerBuilder(); // Dependency for repository builder.RegisterType<SystemDateTimeProvider>().InstancePerRequest().As<IDateTimeProvider>(); // Repository builder.RegisterType<BookmarkRepository>().InstancePerRequest().As<IBookmarkRepository>(); return builder; } ``` We also override the `CreateRequestContainer()` method to create the request container with the tag `MatchingScopeLifetimeTags.RequestLifetimeScopeTag`. ``` protected override ILifetimeScope CreateRequestContainer(NancyContext context) { return ApplicationContainer.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag); } ``` This appears to have solved the problem of `IDisposable`s not being disposed - the child request container is disposed at the end of the web request pipeline and objects resolved by it are also disposed and eventually garbage collected. Our problem is that this seems to be leaking the implementation details of the repositories into the services as we have to not only register the repository in `ConfigureRequestContainer()` but also any other objects required by the repository, i.e. if we want to change the implementation of a repository we have to "walk the dependency chain" to register required objects in each service using it - this seems wrong. Is there a way we can get Autofac to resolve supporting objects for the repositories out of the root container but keep the registration information within the scope of the web request container? Or is there a way to automatically copy existing registrations from the root container into the child container when it is created?

Original source