Как использовать Autofac для разрешения зависимостей между экземплярами и запросами для типов в дочерней области времени жизни, созданной Нэнси
У нас есть несколько приложений, размещенных в службах Windows, которые самостоятельно размещают конечную точку Nancy для предоставления инструментария по работе приложений.
Мы используем Autofac в качестве нашего МОК. Несколько репозиториев зарегистрированы в корневом контейнере в базовой DLL, совместно используемой всеми приложениями; этот контейнер затем передается Нэнси в качестве его контейнера с помощью загрузчика, полученного из Nancy.Autofac.Bootstrapper
,
Мы обнаружили, что когда Нэнси получает веб-запрос, он обрабатывает запрос на хранилище из корневого контейнера, и это приводит к тому, что память используется не сборщиком мусора. IDisposable
Так как корневой контейнер не выходит из области видимости (у него есть время жизни службы Windows). Это привело к тому, что сервисы "утекли" в память.
Затем мы переключились на модель, где мы добавили регистрации для репозиториев, используя InstancePerRequest
в переопределенном ConfigureRequestContainer()
метод в нашей загрузке Нэнси:
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;
}
Мы также отменяем CreateRequestContainer()
метод для создания контейнера запроса с тегом MatchingScopeLifetimeTags.RequestLifetimeScopeTag
,
protected override ILifetimeScope CreateRequestContainer(NancyContext context)
{
return ApplicationContainer.BeginLifetimeScope(MatchingScopeLifetimeTags.RequestLifetimeScopeTag);
}
Это, похоже, решило проблему IDisposable
не удаляется - дочерний контейнер запроса располагается в конце конвейера веб-запроса, и объекты, разрешенные им, также удаляются и, в конечном итоге, собирают мусор.
Наша проблема в том, что это, похоже, приводит к утечке деталей реализации репозиториев в сервисы, так как мы должны не только регистрировать репозиторий в ConfigureRequestContainer()
но также и любые другие объекты, требуемые хранилищем, то есть, если мы хотим изменить реализацию хранилища, мы должны "пройтись по цепочке зависимостей", чтобы зарегистрировать требуемые объекты в каждом сервисе, использующем его - это кажется неправильным.
Есть ли способ, которым мы можем заставить Autofac разрешать вспомогательные объекты для репозиториев из корневого контейнера, но сохранять регистрационную информацию в пределах контейнера веб-запроса? Или есть способ автоматически скопировать существующие регистрации из корневого контейнера в дочерний контейнер при его создании?
1 ответ
Autofac должен автоматически разрешать экземпляры из "родительских" времен жизни. Если вы настраиваете свои регистрации с помощью InstancePerRequest
, Autofac зарегистрирует эти сервисы с помощью специального тега, MatchingScopeLifetimeTags.RequestLifetimeScopeTag
, так что это может быть решено в правильном объеме позже.
Это означает, что нет необходимости использовать загрузчик Нэнси ConfigureRequestContainer
способ сделать регистрацию по запросу. Вы уже сделали это! Пока Нэнси создает время жизни запроса, используя тот же тег, что и в InstancePerRequest
(это делается по умолчанию в версии Nancy 1.1), службы должны быть разрешены правильно.
Пример:
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 ;)
}
}
Этой настройки должно быть достаточно (Начиная с Nancy 1.1. В более ранних версиях вы также должны переопределять CreateRequestContainer
метод и передать тег времени существования запроса при создании области действия запроса).
РЕДАКТИРОВАТЬ: я собрал пример для вас на https://github.com/khellang/Nancy.AutofacExample