2014-10-27 7 views
11

Sto tentando di implementare un semplice esempio di applicazione CQRS.Autofac risolve la dipendenza in CQRS CommandDispatcher

Questa è una struttura della mia parte "Command":

public interface ICommand 
{ 
} 

//base interface for command handlers 
interface ICommandHandler<in TCommand> where TCommand: ICommand 
{ 
    void Execute(TCommand command); 
} 

// example of the command 
public class SimpleCommand: ICommand 
{ 
    //some properties 
} 

// example of the SimpleCommand command handler 
public class SimpleCommandHandler: ICommandHandler<SimpleCommand> 
{ 
    public void Execute(SimpleCommand command) 
    { 
     //some logic 
    } 

} 

Questa è l'interfaccia ICommandDipatcher. Invia un comando al suo gestore.

public interface ICommandDispatcher 
{ 
    void Dispatch<TCommand>(TCommand command) where TCommand : ICommand; 
} 

Questa è un'implementazione predefinita ICommandDispatcher e il problema principale è quello di ottenere il gestore di comando necessaria per il tipo di comando tramite Autofac.

public class DefaultCommandDispatcher : ICommandDispatcher 
{ 
    public void Dispatch<TCommand>(TCommand command) where TCommand : ICommand 
    { 
     //How to resolve/get object of the neseccary command handler 
     //by the type of command (TCommand) 
     handler.Execute(command); 
    } 
} 

Qual è il modo migliore per risolvere attuazione ICommandHanler per tipo di comando in questo caso tramite Autofac?

Grazie!

risposta

11

Con Autofac, è necessario iniettare IComponentContext nel dispatcher. In questo modo è possibile richiamare nel contenitore per risolvere il gestore di comandi necessaria:

public class AutofacCommandDispatcher : ICommandDispatcher 
{ 
    private readonly IComponentContext context; 

    public AutofacCommandDispatcher(IComponentContext context) 
    { 
     this.context = context; 
    } 

    public void Dispatch<TCommand>(TCommand command) 
    { 
     var handler = this.context.Resolve<ICommandHandler<TCommand>>(); 

     void handler.Execute(command); 
    } 
} 

È possibile registrare il AutofacCommandDispatcher come segue:

builder.RegisterType<AutofacCommandDispatcher>().As<ICommandDispatcher>(); 

ed è possibile registrare tutti i gestori di comandi in un colpo solo, come segue:

builder.RegisterAssemblyTypes(myAssembly) 
    .AsClosedTypesOf(typeof(ICommandHandler<>)); 

Due note però. Prima di tutto, probabilmente hai definito lo ICommandHandler<T> come controvariante (con la parola chiave in) perché lo ha detto Resharper, ma questa è una cattiva idea per i gestori di comandi. Esiste sempre una mappatura uno-a-uno tra un gestore di comandi e comandi, ma la definizione della parola chiave in comunica che possono esserci più implementazioni.

Secondo, a mio parere, avere un commander di comandi è una cattiva idea, perché questo può nascondere il fatto che le classi consumatrici di gestori di comandi hanno troppe dipendenze, che è un'indicazione di una violazione del Principio di Responsabilità Unica. Inoltre, l'utilizzo di un dispatcher di questo tipo posticipa la creazione di parte del grafico dell'oggetto (la parte del gestore comandi) finché il comando non viene effettivamente eseguito (contrario a quando il consumatore viene risolto). Ciò rende più difficile verificare la configurazione del contenitore.Quando i gestori di comandi vengono iniettati direttamente, si è sicuri che l'intero grafico degli oggetti può essere risolto quando i tipi di root nella configurazione possono essere risolti. È facile definire un comando, ma dimentica di creare il corrispondente gestore di comandi, quindi dovrai aggiungere test di unità per verificare se ciascun comando ha un gestore corrispondente. È possibile evitare di dover scrivere tale test se si rimuove il dispatcher tutti insieme.

+0

Come posso registrare ICommandHandler di Autofac nel tuo esempio? Devo trovare il modo in cui fornire la possibilità di registrare tutti i gestori di comandi. –

+0

@ArtyomPranovich: vedere il mio aggiornamento. – Steven

+0

Ottimo! Funziona :) Grazie per l'esempio e la fantastica spiegazione. –

2

Supponendo di avere ConcreteCommand : IComman e ConcreteCommandHandler : ICommandHandler<ConcreteCommand> uso RegisterType metodo come questo:

builder.RegisterType<ConcreteCommandHandler>() 
     .As<ICommandHandler<ConcreteCommand>>(); 

E poi iniettare il vostro gestore:

private ICommandHandler<ConcreteCommand> concreteCommandHandler; 

Vedi anche il automatic assembly types registration capacità autofac.

Se si desidera risolvere l'implementazione ICommandHandler per ICommand, la registrazione di fabbrica può essere d'aiuto. Registrati Func<Type, ICommandHandler> o definisci una classe speciale che risolva il gestore di comandi appropriato.