Dépendance de résolution automatique dans CQRS CommandDispatcher

J’essaie d’implémenter un exemple simple d’application CQRS.

Ceci est une structure de ma partie “Command”:

public interface ICommand { } //base interface for command handlers interface ICommandHandler 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 { public void Execute(SimpleCommand command) { //some logic } } 

C’est l’interface ICommandDipatcher . Il envoie une commande à son gestionnaire.

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

Il s’agit d’une implémentation par défaut d’ ICommandDispatcher . Le principal problème consiste à obtenir le gestionnaire de commandes nécessaire en fonction du type de la commande via Autofac .

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

Quel est le meilleur moyen de résoudre l’implémentation d’ ICommandHanler par type de commande dans ce cas via Autofac ?

Merci!

Avec Autofac, vous devez injecter IComponentContext dans le répartiteur. De cette façon, vous pouvez rappeler dans le conteneur pour résoudre le gestionnaire de commandes requirejs:

 public class AutofacCommandDispatcher : ICommandDispatcher { private readonly IComponentContext context; public AutofacCommandDispatcher(IComponentContext context) { this.context = context; } public void Dispatch(TCommand command) { var handler = this.context.Resolve>(); void handler.Execute(command); } } 

Vous pouvez enregistrer AutofacCommandDispatcher comme suit:

 builder.RegisterType().As(); 

Et vous pouvez enregistrer tous vos gestionnaires de commandes en une fois, comme suit:

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

Deux notes cependant. Tout d’abord, vous avez probablement défini ICommandHandler comme contravariant (avec le mot-clé in ) car Resharper l’a dit, mais c’est une mauvaise idée pour les gestionnaires de commandes. Il existe toujours un mappage un à un entre une commande et un gestionnaire de commandes, mais la définition du mot clé in indique qu’il peut y avoir plusieurs implémentations.

Deuxièmement, à mon avis, avoir un répartiteur de commandes est une mauvaise idée, car cela peut masquer le fait que les classes consommasortingces de gestionnaires de commandes ont trop de dépendances, ce qui indique une violation du principe de responsabilité unique. De plus, l’utilisation d’un tel répartiteur retarde la création d’une partie du graphe d’object (la partie du gestionnaire de commandes) jusqu’à ce que la commande soit réellement exécutée (par opposition à la résolution du consommateur). Cela rend plus difficile la vérification de la configuration du conteneur. Lorsque les gestionnaires de commandes sont injectés directement, vous savez avec certitude que tout le graphe d’object peut être résolu lorsque les types racine de votre configuration peuvent être résolus. Il est facile de définir une commande, mais oubliez de créer le gestionnaire de commandes correspondant. Vous devrez donc append des tests unitaires pour vérifier si chaque commande possède un gestionnaire correspondant. Vous pouvez vous épargner de devoir écrire un tel test si vous supprimez le répartiteur dans son ensemble.

En supposant que vous ayez ConcreteCommand : IComman et ConcreteCommandHandler : ICommandHandler utilisez la méthode RegisterType comme ceci:

 builder.RegisterType() .As>(); 

Et puis injectez votre handler:

 private ICommandHandler concreteCommandHandler; 

Examinez également les capacités d’ enregistrement automatique des types d’ assemblage.

Si vous souhaitez résoudre l’ ICommandHandler d’ ICommand par ICommand , l’enregistrement en usine peut vous aider. Enregistrez Func ou définissez une classe spéciale qui résoudra le gestionnaire de commandes approprié.