2017-10-20 12 views
0

Pour un projet sur lequel je travaille, nous pratiquons la conception par domaine et l'utilisation de ninject comme conteneur IOC. J'essaye de mettre en application des événements de domaine semblables à l'approche décrite par Tony Truong here. J'essaie d'utiliser ninject sans devoir avoir un service statique ou référencer le noyau en dehors de la racine de la composition. Je suis en train de faire quelque chose comme çaInterface générique Multi-Injection avec Ninject

/// <summary> 
/// Service to dispatch domain events to handlers. 
/// </summary> 
public class NinjectDomainEventDispatcher : IDomainEventDispatcher 
{ 
    /// <summary> 
    /// Array containing domain event handler registrations. 
    /// </summary> 
    private readonly IDomainEventHandler<IDomainEvent>[] _handlers; 

    /// <summary> 
    /// Initializes a new instance of the <see cref="NinjectDomainEventDispatcher"/> class. 
    /// </summary> 
    /// <param name="handlers">Registered domain event handlers.</param> 
    public NinjectDomainEventDispatcher(IDomainEventHandler<IDomainEvent>[] handlers) 
    { 
     _handlers = handlers; 
    } 

    /// <summary> 
    /// Dispatch domain event to subscribed handlers. 
    /// </summary> 
    /// <typeparam name="T">Type of domain event to dispatch.</typeparam> 
    /// <param name="domainEvent">Domain event to dispatch.</param> 
    public void Dispatch<T>(T domainEvent) where T : IDomainEvent 
    { 
     foreach (var handler in _handlers.Where(x => x.GetType() == typeof(IDomainEventHandler<T>))) 
     { 
      handler.Handle(domainEvent); 
     } 
    } 
} 

/// <summary> 
/// Module that will be used for the registration of the domain event handlers 
/// </summary> 
public class DomainEventHandlerModule : NinjectModule 
{ 
    /// <summary> 
    /// The method that will be used to load the ninject registration information. 
    /// </summary> 
    public override void Load() 
    { 
     Bind<IDomainEventDispatcher>().To<NinjectDomainEventDispatcher>(); 
     Bind<IDomainEventHandler<ConcreteDomainEvent>>().To<ConcreteDomainEventHandler1>(); 
     Bind<IDomainEventHandler<ConcreteDomainEvent>>().To<ConcreteDomainEventHandler2>(); 
     Bind<IDomainEventHandler<AnotherConcreteDomainEvent>>().To<AnotherConcreteDomainEventHandler1>(); 
     Bind<IDomainEventHandler<AnotherConcreteDomainEvent>>().To<AnotherConcreteDomainEventHandler2>(); 
    } 
} 

L'objectif est d'appeler tous les gestionnaires enregistrés pour le type de l'instance d'événement de domaine passé dans la méthode d'expédition. Mon problème est, le tableau de gestionnaires est vide lorsqu'il est injecté (je devine parce qu'il recherche spécifiquement des gestionnaires liés à IDomainEventHandler <IDomainEvent>, pas tous les gestionnaires de types implémentant IDomainEvent comme j'ai besoin).

+0

cette réponse récente peut vous aider que la question semble vraiment semblable à la vôtre https://stackoverflow.com/a/46729694/1236044 – jbl

+0

Je suis déplacé loin de un répartiteur d'événements statiques et que mon domaine renvoie plutôt des événements. La couche d'application/d'intégration publiera/déclenchera des événements puisqu'il y a des chances qu'un autre BC soit également intéressé par un événement dans ce BC et pas seulement par d'autres agrégats dans le même BC. Vous auriez toujours besoin d'un mécanisme pour effectuer la publication mais cela serait injecté dans votre contrôleur/application et utilisé à partir de là. Juste un peu :) –

Répondre

0

au lieu de filtrer les gestionnaires corrects dans votre propre code, vous pouvez utiliser ninject à faire pour vous:

public class NinjectDomainEventDispatcher : IDomainEventDispatcher 
{ 
    private readonly IResolutionRoot resolutionRoot; 

    public NinjectDomainEventDispatcher(IResolutionRoot resolutionRoot) 
    { 
     this.resolutionRoot = resolutionRoot; 
    } 

    public void Dispatch<T>(T domainEvent) where T : IDomainEvent 
    { 
     var handlers = this.resolutionRoot.GetAll<IDomainEventHandler<T>>(); 
     foreach (var handler in handlers) 
     { 
      handler.Handle(domainEvent); 
     } 
    } 
} 

Pro-Tip: la pratique de conception recommandée est de déplacer le code dépendant IResolutionRoot (Ninject) à une implémentation d'usine dans le composition root. Au lieu de faire cela, vous pouvez également faire manuellement l'utilisation de Ninject.Extensions.Factory