Подтвердить что ты не робот

Использование Autofac с событиями домена

Я пытаюсь ввести события домена в проект. Концепция описана в сообщении Udi Dahan - http://www.udidahan.com/2009/06/14/domain-events-salvation/

Здесь код события домена

public interface IDomainEvent { }

public interface IHandleDomainEvents<T> where T : IDomainEvent
{
     void Handle(T args); 
}

public interface IEventDispatcher
{
    void Dispatch<TEvent>(TEvent eventToDispatch) where TEvent : IDomainEvent;
}

public static class DomainEvents
{
    public static IEventDispatcher Dispatcher { get; set; }

    public static void Raise<TEvent>(TEvent eventToRaise) where TEvent : IDomainEvent
    {
        Dispatcher.Dispatch(eventToRaise);
    }
}

Самая важная часть - реализация IEventDispatcher, которая отделяет событие домена от того, что должно произойти, когда возникает событие. Хитрость заключается в подключении этой муфты через контейнер. Здесь моя попытка

Код для регистрации всех обработчиков событий домена....

        var asm = Assembly.GetExecutingAssembly();
        var handlerType = typeof(IHandleDomainEvents<>);

        builder.RegisterAssemblyTypes(asm)
            .Where(t => handlerType.IsAssignableFrom(t)
                        && t.IsClass
                        && !t.IsAbstract)
            .AsClosedTypesOf(handlerType)
            .InstancePerLifetimeScope(); 

И разрешение всех обработчиков событий в диспетчере. Проблема заключается в том, что обработчики не разрешены.

public class EventDispatcher : IEventDispatcher
{
    private readonly IContainer _container;

    public EventDispatcher(IContainer container)
    {
        _container = container;
    }

    public void Dispatch<TEvent>(TEvent eventToDispatch) where TEvent : IDomainEvent
    {
        var handlers = _container.Resolve<IEnumerable<IHandleDomainEvents<TEvent>>>().ToList();
        handlers.ForEach(handler => handler.Handle(eventToDispatch));
    }
}

Итак, я не правильно регистрирую обработчики событий или не разрешаю их. Как проверить, работает ли регистрация?

Пример кода обработчика

public class SendWebQuestionToCSO : IHandleDomainEvents<JobNoteCreated>
{
    private readonly IConfig _config;

    public SendWebQuestionToCSO(IConfig config)
    {
        _config = config;
    } 

    public void Handle(JobNoteCreated args)
    {
        var jobNote = args.JobNote;
        using(var message = new MailMessage())
        {
            var client = new SmtpClient {Host = _config.SmtpHostIp};
            message.From = new MailAddress(_config.WhenSendingEmailFromWebProcessUseThisAddress);
            ...... etc
        }
    }
}

UPDATE После некоторых проб и ошибок EventDispatcher работает нормально! Если я вручную зарегистрирую обработчик, а затем запустим событие домена, он будет работать. Сборочное сканирование/регистратура - моя проблема. Код регистрации вручную...

builder.RegisterType<SendWebQuestionToCSO >().As<IHandleDomainEvents<JobNoteCreated>>();

Итак, как я сканирую все сборки для всех IHandleDomainEvents<>, если они выглядят так:

public class SendWebQuestionToCSO : IHandleDomainEvents<JobNoteCreated>
4b9b3361

Ответ 1

Как отметил Питер, проблема регистрации была связана с вашим предложением Where().

При сканировании сборок Autofac автоматически фильтрует компоненты на основе указанных вами служб, поэтому было бы справедливо использовать:

builder.RegisterAssemblyTypes(asm)
    .AsClosedTypesOf(handlerType)
    .InstancePerLifetimeScope();

Ответ 2

Проблема в коде сканирования сборки при использовании IsAssignableFrom. Фильтр спросит: "Можно ли присвоить экземпляр SendWebQuestionToCSO переменной IHandleDomainEvents<>?"? Ответ, очевидно, "нет", поскольку у вас никогда не может быть переменной открытого типа.

Фокус в том, чтобы проверить интерфейсы, реализованные каждым типом, и проверить, закрывает ли какой-либо из них открытый тип интерфейса общего типа. Здесь пересмотренный сканер:

    var asm = Assembly.GetExecutingAssembly();
    var handlerType = typeof(IHandleDomainEvents<>);

    builder.RegisterAssemblyTypes(asm)
        .Where(t => t.GetInterfaces().Any(t => t.IsClosedTypeOf(handlerType)))
        .AsImplementedInterfaces()
        .InstancePerLifetimeScope();