2011-04-12 19 views
13

Estoy tratando de introducir eventos de dominio en un proyecto. El concepto se describe en el post de Udi Dahan - http://www.udidahan.com/2009/06/14/domain-events-salvation/Uso de Autofac con eventos de dominio

Aquí está el código de evento dominio

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); 
    } 
} 

La parte más importante es la implementación IEventDispatcher que desacopla el caso del dominio de lo tiene que suceder cuando se ha producido el evento. El truco es conectar este acoplamiento a través de un contenedor. Aquí está mi intento

Código para el registro de todos los controladores de eventos de dominio ....

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

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

y resolver todos los controladores de eventos en el despachador. El problema es que no se han resuelto los controladores.

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)); 
    } 
} 

Así que no estoy registrando los controladores de eventos correctamente o no los está resolviendo. ¿Cómo verifico si el registro está funcionando?

Código de ejemplo de un manejador de

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 
     } 
    } 
} 

ACTUALIZACIÓN Después de algunos ensayos y errores del EventDispatcher está trabajando bien! Si registro manualmente un controlador y luego activa el evento de dominio, funciona. El escaneo/registro de la asamblea es mi problema. El código de registro manual ...

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

Entonces, ¿cómo puedo escanear todos los montajes para todos IHandleDomainEvents<> dan se ven así

public class SendWebQuestionToCSO : IHandleDomainEvents<JobNoteCreated> 

Respuesta

7

Mientras señalaba a cabo, el problema fue registrado con su cláusula de Where().

Al escanear asambleas Autofac Filtros Componentes automáticamente en función de los servicios que especifique, por lo que sería igualmente correcto de usar Simplemente:

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

¡Perfecto Nick! ¡Estoy esperando su próximo curso! – CRG

+0

Ah, sí, incluso más suave. Me robaron de 15 rep sin embargo! –

+0

Hehe como si lo necesitaras, Sr. L.;) no obstante obtuviste mi voto. –

1

El problema en el código de exploración de ensamblaje es cuando usa IsAssignableFrom. El filtro preguntará: "¿podría asignarse una instancia de SendWebQuestionToCSO a una variable de IHandleDomainEvents<>?" La respuesta es obviamente "no" ya que nunca puede tener una variable de tipo genérico abierto.

El truco sería inspeccionar las interfaces implementadas por cada tipo y verificar si alguna de ellas está cerrando el tipo de interfaz genérica abierta. Aquí está un escáner revisado:

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

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

Hola Peter, en qué espacio de nombres puedo encontrar 'IsClosingTypeOf' – CRG

+0

¿Quiso decir IsClosedTypeOf? Lo intenté y no funcionó.Sin embargo, ¡parecía muy prometedor! Cualquier otra idea sería muy útil. He estado jugando con esto durante demasiado tiempo ... – CRG

+0

He consultado la fuente en code.google.com hg/src/Source/Autofac/Util/ReflectionExtensions.cs y el método de extensión IsClosingTypeOf es muy simple, así que copié el código que resulta en - .Where (t => t.GetInterfaces(). Any (i => i.IsGenericType && i.GetGenericTypeDefinition() == handlerType)). ¡¡¡ESTO FUNCIONA!!! La gran pregunta es ¿dónde se ha ido el método de extensión en la versión 2.4.5.724 .Net4? – CRG

Cuestiones relacionadas