2011-04-12 5 views
13

Я пытаюсь ввести события домена в проект. Концепция описана в посте UDI Даан в - http://www.udidahan.com/2009/06/14/domain-events-salvation/Использование Autofac с событиями домена

Вот код события Доменные

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> 

ответ

7

Как Петр отметил, что проблема регистрации была с пунктом Where().

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

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

Идеальный Ник! Я с нетерпением жду вашего предстоящего курса! – CRG

+0

А, да, еще более гладко. Хотя меня ограбили 15 человек! –

+0

Хе-хе, как вам это нужно, мистер Л.;), тем не менее, вы получили мой голос. –

0

Я не знаком с Autofac, но я считаю, я m, имеющих аналогичную проблему, а не с autofac, но с архитектурой Dynamic generic interface cast.

Это, вероятно, вопрос Covariance and Contravariance.

+0

Спасибо Педро, думаю, я еще некоторое чтение делать! – CRG

1

Проблема в вашем коде сканирования сборки заключается в том, что вы используете 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(); 
+0

Привет, Питер, в каком пространстве имен я могу найти IsClosingTypeOf – CRG

+0

Вы имели в виду IsClosedTypeOf? Я попробовал, и это не сработало.Однако это выглядело очень многообещающе! Любые другие идеи были бы очень полезными. Я слишком долго общался с этим ... – CRG

+0

Я посмотрел источник на code.google.com hg/src/Source/Autofac/Util/ReflectionExtensions.cs и метод расширения IsClosingTypeOf очень прост, поэтому я скопировал код, приводящий к: .Where (t => t.GetInterfaces(). Любой (i => i.IsGenericType && i.GetGenericTypeDefinition() == handlerType)). ЭТО РАБОТАЕТ!!! Большой вопрос в том, где метод расширения ушел в версию 2.4.5.724 .Net4? – CRG

Смежные вопросы