2011-04-12 13 views
13

Sto tentando di introdurre eventi di dominio in un progetto. Il concetto è descritto nel post di Udi Dahan - http://www.udidahan.com/2009/06/14/domain-events-salvation/Utilizzo di Autofac con eventi di dominio

Ecco il dominio codice evento

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 più importante è l'implementazione IEventDispatcher che disaccoppia l'evento dominio da ciò che deve accadere quando l'evento viene generato. Il trucco è quello di cablare questo accoppiamento attraverso un contenitore. Ecco il mio tentativo

Codice in materia di registrazione di tutti i gestori di eventi di dominio ....

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

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

e risolvere tutti i gestori di eventi nel dispatcher. Il problema è che non vengono risolti i gestori.

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

Quindi non sto registrando correttamente i gestori di eventi o non li risolvo. Come posso verificare che la registrazione funzioni?

codice Esempio di un gestore

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 Dopo alcuni tentativi ed errori l'EventDispatcher sta funzionando bene! Se registro manualmente un gestore e poi sparo l'evento del dominio, funziona. Il processo di scansione/registrazione è il mio problema. Il codice di registrazione manuale ...

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

Allora, come faccio la scansione di tutte le assemblee per tutti IHandleDomainEvents<> dato assomigliano questo

public class SendWebQuestionToCSO : IHandleDomainEvents<JobNoteCreated> 

risposta

7

Come Peter ha sottolineato, il problema di registrazione è stato con il tuo Where() clausola.

Durante la scansione di assemblee Autofac Filtri componenti automaticamente in base ai servizi specificati, quindi sarebbe altrettanto corretto di utilizzare solo:

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

Nick perfetto! Non vedo l'ora del tuo prossimo corso! – CRG

+0

Ah, sì, ancora più liscio. Mi ha derubato di 15 rep! –

+0

Hehe like you need it, Mr. L.;) hai comunque il mio voto. –

1

Il problema nel codice di scansione assembly è quando si utilizza IsAssignableFrom. Il filtro chiederà: "potrebbe essere assegnata un'istanza di SendWebQuestionToCSO a una variabile di IHandleDomainEvents<>?" La risposta è ovviamente "no" poiché non si può mai avere una variabile di tipo generico aperto.

Il trucco sarebbe quello di ispezionare le interfacce implementate da ciascun tipo e verificare se qualcuno di loro sta chiudendo il tipo di interfaccia generica aperta. Ecco uno scanner rivisto:

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

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

Ciao Peter, in quale spazio dei nomi posso trovare "IsClosingTypeOf" – CRG

+0

Intendevi IsClosedTypeOf? L'ho provato e non ha funzionato.Comunque è sembrato molto promettente! Qualche altra idea sarebbe di grande aiuto, ho lavorato troppo a lungo ora ... – CRG

+0

Ho dato un'occhiata all'origine su code.google.com hg/src/Source/Autofac/Util/ReflectionExtensions.cs e il metodo di estensione IsClosingTypeOf è molto semplice, quindi ho copiato il codice risultante in - .Where (t => t.GetInterfaces(). Any (i => i.IsGenericType && i.GetGenericTypeDefinition() == handlerType)). QUESTO FUNZIONA !!! La grande domanda è dove è andato il metodo di estensione nella versione 2.4.5.724 .Net4? – CRG

Problemi correlati