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?
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 inInstancePerRequest
(this is done by default as of Nancy 1.1), the services should be resolved correctly.Example:
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