Добрый день!
При реализации Domain events, я использую
Само событие:
public class ProductCreatedEvent : IDomainEvent
{
public Product Product { get; }
public ProductCreatedEvent(Product product)
{
Product = product;
}
}
Оброботчик:
public class EmailCustomerOnProductCreatedHandler : IDomainEventHandler<ProductCreatedEvent>
{
private readonly ILogger _logger;
public EmailCustomerOnProductCreatedHandler(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.Create(GetType());
}
public void Handle(ProductCreatedEvent @event)
{
_logger.Trace($"Send email to customer: Product \"{@event.Product.ProductName}\" was created.");
}
}
Для тестов я инжектирую в обработчик ILoggerFactory, но в реальности, туда будут помимо ILoggerFactory инжектироваться много компонент, например, IEmailSender и.т.п.
Также есть диспечер для Autofac'a:
public class AutofacDomainEventDispatcher : IDomainEventDispatcher
{
private readonly ILifetimeScope _container;
public AutofacDomainEventDispatcher(ILifetimeScope container)
{
if (container == null)
throw new ArgumentNullException("container");
_container = container;
}
public void Dispatch<TDomainEvent>(TDomainEvent @event) where TDomainEvent : IDomainEvent
{
// Для тестов я пока просто пытаюсь получить КОНЕКРЕТНЫЙ обработчик
var handler = _container.Resolve<IDomainEventHandler<ProductCreatedEvent>>();
handler.Handle(@event as ProductCreatedEvent); // Привожу к ProductCreatedEvent только для теста
}
}
Дальше вся проблема в настройке Autofac'a:
public static class Bootstrapper
{
public static void Setup()
{
var builder = new ContainerBuilder();
// Регистрируем фабрику для логгеров
builder.RegisterType(typeof(NLoggerFactory)).As(typeof(ILoggerFactory)).InstancePerRequest();
// Регистрируем конкретный обработчик
builder
.RegisterType(typeof(EmailCustomerOnProductCreatedHandler))
.As(typeof(IDomainEventHandler<ProductCreatedEvent>))
.InstancePerLifetimeScope();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
// Setup DomainEventDispatcher
DomainEventDispatcherProvider.Setup(new AutofacDomainEventDispatcher(container));
}
}
При такой конфигурации, Autofac выдает 2 exception'a в методе Dispatch:
var handler = _container.Resolve<IDomainEventHandler<ProductCreatedEvent>>();
1)
DependencyResolutionException: Unable to resolve the type 'ElibraryEngine.CrossCutting.Logging.NLog.NLoggerFactory' because the lifetime scope it belongs in can't be located. The following services are exposed by this registration:
- ElibraryEngine.CrossCutting.Logging.ILoggerFactory
2)
If you see this during execution of a web application, it generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario). Under the web integration always request dependencies from the dependency resolver or the request lifetime scope, never from the container itself.
Я пробовал регистрировать обработчик, не
.InstancePerLifetimeScope()
, а
.InstancePerRequest()
, тогда exception такой:
DependencyResolutionException: No scope with a tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested.
С IoC-контейнерами я познакомился недавно, поэтому есть недопонимание в использовании InstancePerLifetimeScope/InstancePerRequest.
Прошу помощи в настройке контейнера.
Буду благодарен за любые подсказки!