views:

81

answers:

1

In my latest ASP.NET MVC 2 application I have been trying to put into practice the concepts of Domain Driven Design (DDD), the Single Responsibility Principle (SRP), Inversion of Control (IoC), and Test Driven Development (TDD). As an architecture example I have been following Jeffery Palermo's "Onion Architecture" which is expanded on greatly in ASP.NET MVC 2 in Action.

Onion Architecture Diagram

While, I have begun to successfully apply most (some?) of these principles I am missing a key piece of the puzzle. I am having trouble determining the best mechanism for auto-wiring a service layer to my domain entities.

As an example: each domain entity that needs the ability to send an email should depend on an IEmailService interface. From my reading, best practice to reveal this dependency would be to use constructor injection. In my UI layer I perform a similar injection for repository interface implementations using the StructureMapControllerFactory from ASP.NET MVC Contrib.

Where I am confused is what is the best mechanism for auto-wiring the injection of the necessary services into domain entities? Should the domain entities even be injected this way? How would I go about using IEmailService if I don't inject it into the domain entities?

Additional Stack Overflow questions which are great DDD, SRP, IoC, TDD references:

+3  A: 

Unless I'm misunderstanding your intent and instead I'm choosing to focus on semantics I'm going to dissect this statement "As an example: each domain entity that needs the ability to send an email should depend on an IEmailService interface."

I would have to argue this is upon itself is an extreme bastardization of DDD. Why should a domain entity ever need to depend on an email service? IMO it shouldn't. There is no justification for it.

However there are business operations in conjunction with a domain entity that would require the need to send emails. You should have your IEmailService dependency contained in this class here, not the domain entity. This class would most likely fall into one of a few nearly synonymous names: Model, Service or Controller dependent upon which architecture/layer you're in.

At this point your StructureMapControllerFactory would then correctly auto wire everything that would use the IEmailService.

While I might be minorly over generalizing it's pretty much standard practice to have domain entities be POCOs or be nearly POCOs (to avoid violation of the SRP) however frequently SRP is violated in domain entities for sake of serialization and validation. Choosing to violate SRP for those types of cross cutting concerns is more of a personal belief stance as opposed to a "right" or "wrong" decision.

As a final follow up if your question is on the portion of code that is truly operating in a stand alone service whether web or OS based and how to wire up the dependencies from that, a normal solution would be take over the service at a base level and apply IOC to it in the same similar fashion as the StructureMapControllerFactory does in MVC. How to achieve this would be entirely dependent upon the infrastructure you're working with.

Response:

Lets say you have IOrderConfirmService which has a method EmailOrderConfirmation(Order order). You would end up with something like this:

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

You would then have your OrderController class that would be something like

public class OrderController : Controller
{    
    private readonly IOrderConfirmService _service;

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

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

            return View();
    }    
}

StrucutreMap will inherently build up you're entire architecture chain when you use constructor injection correctly. This is the fundamental difference between tight coupling and inversion of control. So when the StructureMapFactory goes to build up your controller the first thing it will see is that it needs IOrderConfirmService. At this point it will check if it can plug IOrderConfirmService directly which it can't because it needs IEmailService. So it will check if it can plug IEmailService and for argumentsake lets say it can. So at this point it will build EmailService, which it will then build MyOrderConfirmService and plug in EmailService, and then finally build OrderController and plug in MyOrderConfirmService. This is where the term inversion of control comes from. StructureMap will build the EmailService first in the entire chain of dependencies and ending last with the Controller. In a tightly coupled setup this will be the opposite where the Controller will be built first and have to build the business service and then build the email service. Tightly coupled design is very brittle when compared to IOC.

Chris Marisic
Chris you're dead on. I felt like I was violating something by injecting `IEmailService` into domain entities. Assuming that it's a Core service how / where do I wire the various entities that will need to use `IEmailService`? I guess I am having a hard time visualizing how that would work.
ahsteele
Responded to your comment.
Chris Marisic
@Chris I made a minor change to the controller constructor code.
ahsteele
So this definitely clarifies how `IEmailService` would be wired. This leads me to a couple more questions. Would the wiring of a `IValidationService` be implemented similarly to `IEmailService`? I can envision a controller that would have a `IRespoisotry`, `IEmailService`, and `IValidationService` injected. At what point am I violating the guideline that *any class having more then 3 dependencies should be questioned for an SRP violation*? Is the simple answer to break my controller up into smaller parts?
ahsteele
Statements like "more than 3 dependencies" are just guide lines. There really is no finite number that automatically becomes bad. The main thing to watch as your dependency list grows is to make sure you still keep your code DRY. When you start to see patterns emerge of duplicate or similar code with multiple dependencies it would be time to combine some of them into a specific service. However if no patterns emerge then your code is pretty much about as simple as it can be already. But yes many times a controller will end up with some kind of data service, validation service etc.
Chris Marisic