7

Dans ma dernière application ASP.NET MVC 2, j'ai essayé de mettre en pratique les concepts de Domain Driven Design (DDD), Single Responsibility Principle (SRP), Inversion of Control (IoC) et Test Driven Development (TDD). En tant qu'exemple d'architecture, j'ai suivi le "Onion Architecture" de Jeffery Palermo, qui est largement développé en ASP.NET MVC 2 in Action.Options de câblage automatique IoC dans la conception pilotée par domaine

Onion Architecture Diagram

Alors, j'ai commencé à appliquer avec succès la plupart (certains?) De ces principes que je me manque un élément clé du casse-tête. J'ai du mal à déterminer le meilleur mécanisme pour le câblage automatique d'une couche de service vers mes entités de domaine. Par exemple: chaque entité de domaine qui a besoin d'envoyer un courriel devrait dépendre d'une interface IEmailService. De ma lecture, la meilleure pratique pour révéler cette dépendance serait d'utiliser l'injection du constructeur. Dans ma couche d'interface utilisateur, j'effectue une injection similaire pour les implémentations d'interface de référentiel en utilisant le StructureMapControllerFactory de ASP.NET MVC Contrib. Où je suis confus est ce qui est le meilleur mécanisme pour le câblage automatique de l'injection des services nécessaires dans les entités de domaine

Est-ce que les entités de domaine devraient même être injectées de cette façon? Comment pourrais-je utiliser IEmailService si je ne l'injecte pas dans les entités de domaine?

questions Stack Overflow supplémentaires qui sont grandes DDD, SRP, IoC, TDD références:

Répondre

4

À moins que je suis malentendu votre intention et je suis plutôt le choix pour se concentrer sur la sémantique, je vais disséquer cette déclaration "A titre d'exemple: chaque entité de domaine qui a besoin de la capacité d'envoyer un email devrait dépendre d'une interface IEmailService."

Je voudrais faire valoir que c'est sur lui-même est un extrême bastardization de DDD. Pourquoi une entité de domaine doit-elle jamais dépendre d'un service de messagerie? OMI, il ne devrait pas. Il n'y a pas de justification pour cela. Cependant, il existe des opérations commerciales associées à une entité de domaine qui nécessiteraient l'envoi d'e-mails. Vous devriez avoir votre dépendance IEmailService contenue dans cette classe ici, pas l'entité du domaine. Cette classe tomberait probablement dans un de quelques noms presque synonymes: Modèle, service ou contrôleur dépendant de quelle architecture/couche vous êtes.

À ce stade votre StructureMapControllerFactory filerait alors correctement tout ce qui utiliserait le IEmailService. Bien que je puisse légèrement généraliser, il est normal que les entités de domaine soient des POCO ou soient des POCO (pour éviter la violation de la SRP), mais fréquemment, SRP est violée dans les entités de domaine à des fins de sérialisation et de validation. Choisir de violer le SRP pour ces types de préoccupations transversales est davantage une position de croyance personnelle qu'une décision «juste» ou «fausse».En guise de dernier conseil, si votre question porte sur la partie du code qui fonctionne réellement dans un service autonome, qu'il soit basé sur le Web ou sur un système d'exploitation, et comment débrancher les dépendances, une solution normale sera prise en charge. service à un niveau de base et appliquer IOC de la même manière que le StructureMapControllerFactory fait dans MVC. Comment y parvenir dépend entièrement de l'infrastructure avec laquelle vous travaillez.

Réponse:

Disons que vous avez IOrderConfirmService qui a une méthode EmailOrderConfirmation(Order order). Vous finiriez avec quelque chose comme ceci:

public class MyOrderConfirmService : IOrderConfirmService 
{  
    private readonly IEmailService _mailer; 

    public MyOrderConfirmService(IEmailService mailer) 
    {   
     _mailer = mailer;   
    } 

    public void EmailOrderConfirmation(Order order) 
    {   
     var msg = ConvertOrderToMessage(order); //good extension method candidite 
     _mailer.Send(msg);   
    }  
} 

Vous auriez alors votre classe OrderController qui serait quelque chose comme

public class OrderController : Controller 
{  
    private readonly IOrderConfirmService _service; 

    public OrderController(IOrderConfirmService service) 
    {   
     _service= service;   
    } 

    public ActionResult Confirm() 
    {  
      _service.EmailOrderConfirmation(some order); 

      return View(); 
    }  
} 

StrucutreMap va construire soi jusqu'à vous êtes chaîne d'architecture entière lorsque vous utilisez constructeur injection correctement. C'est la différence fondamentale entre le couplage serré et l'inversion de contrôle. Ainsi, lorsque StructureMapFactory va construire votre contrôleur, la première chose qu'il va voir est qu'il a besoin de IOrderConfirmService. À ce stade, il vérifie s'il peut connecter IOrderConfirmService directement, ce qu'il ne peut pas faire parce qu'il a besoin de IEmailService. Donc, il va vérifier si elle peut brancher IEmailService et pour arguments, disons que c'est possible. Donc, à ce stade, il construira EmailService, qu'il va ensuite construire MyOrderConfirmService et branchez EmailService, puis finalement construire OrderController et branchez MyOrderConfirmService. C'est de là que vient le terme inversion de contrôle. StructureMap construira d'abord le EmailService dans toute la chaîne des dépendances et se terminera en dernier avec le Controller. Dans une configuration étroitement couplée, ce sera le contraire où le contrôleur sera construit en premier et devra construire le service métier, puis créer le service de messagerie. La conception à couplage étroit est très fragile par rapport à la COI.

+0

Chris vous êtes mort. J'avais l'impression de violer quelque chose en injectant IEmailService dans des entités de domaine. En supposant que c'est un service de base comment/où dois-je câbler les différentes entités qui auront besoin d'utiliser IEmailService? Je suppose que j'ai du mal à visualiser comment cela fonctionnerait. – ahsteele

+0

Répondu à votre commentaire. –

+0

J'ai apporté une modification mineure au code du constructeur du contrôleur. – ahsteele