Зарегистрируйте тип как InstancePerRequest с исключением (ями)
Я использую AutoFac в своем приложении Web API (используя последние версии, доступные на момент публикации этого вопроса). Одна из моих служебных зависимостей - это AuditService
который использует экземпляр по DbContext
тип (давайте назовем это MyDbContext
на данный момент). Большинство моих услуг и MyDbContext
Все типы зарегистрированы с использованием InstancePerRequest. Для меня AuditService
Я хочу сделать исключение, я всегда хочу внедрить собственный (новый) экземпляр моего MyDbContext
,
Вопрос: Как зарегистрироваться в AutoFac, как мне зарегистрировать AuditService
таким образом, что он всегда получает собственный (новый) экземпляр MyDbContext
?
Что может сработать:
- Я мог бы жестко закодировать создание
MyDbContext
в конструктореAuditService
таким образом обойдя AutoFac все вместе. - Я мог бы использовать PropertyInjection или MethodInjection и предоставить новый экземпляр
MyDbContext
в событии Life Time OnActivating - Я мог бы определить второй интерфейс на
MyDbContext
и предоставить вторую регистрацию и использованиеInstancePerOwned
,
Должен ли я выбрать один из указанных выше вариантов (если это так, я бы склонялся к 3) или я упустил что-то простое? Есть ли способ определить, что я хочу в своем регистрационном коде?
// registration called in web api startup code
public void RegisterAutofac(ContainerBuilder builder)
{
builder.RegisterType<MyDbContext>()
.As<IMyDbContext>()
.InstancePerRequest();
builder.RegisterType<BusinessService>()
.As<IBusinessService>()
.InstancePerRequest();
builder.RegisterType<AuditService>()
.As<IAuditService>()
.InstancePerRequest();
}
public class AuditService
{
// expects an isolated instance on this request
private readonly IMyDbContext _dbContext;
public AuditService(IMyDbContext dbContext)
{
_dbContext = dbContext;
}
}
public class BusinessService
{
// expect a shared IMyDbContext instance across the request
private readonly IMyDbContext _dbContext;
public BusinessService(IMyDbContext dbContext)
{
_dbContext = dbContext;
}
}
Решение проблемы с InstancePerOwned
Это вызывает исключение
builder.RegisterType<MyDbContext>()
.As<IMyDbContext>()
.InstancePerRequest()
.InstancePerOwned<AuditService>();
Autofac.Core.DependencyResolutionException: "Из области, в которой был запрошен экземпляр, не видна область с тегом, совпадающим с" AuditService ". Если вы видите это во время выполнения веб-приложения, это обычно означает, что компонент зарегистрирован как per-HTTP" запрос запрашивается компонентом SingleInstance() (или аналогичным сценарием).В рамках веб-интеграции всегда запрашивайте зависимости из средства разрешения зависимостей или области действия запроса, а не из самого контейнера.
at Autofac.Core.Lifetime.MatchingScopeLifetime.FindScope(ISharingLifetimeScope mostNestedVisibleScope) at Autofac.Core.Resolving.InstanceLookup..ctor(IComponentRegistration registration, IResolveOperation context, ISharingLifetimeScope mostNestedVisibleScope, IEnumerable`1 parameter
Я пытался изменить порядок InstancePerOwned
а также InstancePerRequest
звонки, но это, кажется, не имеет никакого эффекта, то же самое MyDbContext
Экземпляр повторно используется для обоих BusinessService
а также AuditService
экземпляры в том же запросе. Это было проверено с object.ReferenceEquals
из в ApiController
и прошло в обоих экземплярах _dbContext
поля.
builder.RegisterType<MyDbContext>()
.As<IMyDbContext>()
.InstancePerOwned<AuditService>()
.InstancePerRequest();
1 ответ
Попробуйте переключиться с InstancePerRequest
в InstancePerLifetimeScope
, В большинстве приложений это, как правило, ведет себя одинаково и является способом обмена регистрациями между приложениями, которые в любом случае имеют семантику для каждого запроса и не имеют ее. (То есть это довольно распространено.)
Когда у вас есть InstancePerLifetimeScope
на вашем объекте контекста, вы можете использовать Owned<T>
в вашем AuditService
конструктор, чтобы получить свежую копию.
Так...
builder.RegisterType<MyDbContext>()
.As<IMyDbContext>()
.InstancePerLifetimeScope();
затем...
public AuditService(Owned<IMyDbContext> dbContext)
Обратите внимание на ваш AuditService
будет нести ответственность за утилизацию dbContext
когда это будет сделано, так что вам придется обрабатывать это вручную (это часть использования Owned<T>
). Но если у вас уже есть что-то одноразовое, это не должно иметь большого значения.