@WhiteNinja

C#: Как правильно скофигурировать Autofac для Domain events dispatcher?

Добрый день!

При реализации 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.

Прошу помощи в настройке контейнера.

Буду благодарен за любые подсказки!
  • Вопрос задан
  • 879 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы