I’ll be speaking on about Domain-Driven Design, or DDD, with ASP.NET MVC at this year’s FalafelCON event, taking place 20-21 September 2014 in San Francisco. The event is limited to the first 200 people to register, so if you’re interested in attending, you may want to register today. DDD is a big topic, and one I’ve been interested in for many years now. In fact, I recently published a course on DDD Fundamentals with Julie Lerman for Pluralsight that covers the basics. If you have a chance to watch it, let me know what you think via the course’s discussion tab or my facebook page.
ASP.NET MVC is particularly well-suited to applying Domain-Driven Design. I recommend laying out your solution with separate projects for your Core domain, your Infrastructure concerns, your UI, and your tests. You don’t have to have all of these projects – in fact you could do the same thing with just one project and several different folders. However, one thing projects allow for that folders do not is the enforcement of directionality of dependencies. If your Infrastructure project references your Core project, there is no way (at compile time, without reflection, etc.) for objects in your Core project to depend on objects in your Infrastructure project. This is very helpful as a means of enforcing the Dependency Inversion Principle, which I cover in detail in my SOLID Principles of Object Oriented Programming course.
Essentially, the DIP principle states that your abstractions should not depend on details. If you have interfaces in your system, these are abstractions that should generally live in your Core. The specific implementation of these interfaces are details, and thus should depend on the interfaces. If for instance your application has an ICustomerRepository interface, it should be in your Core. But if you then have an implementation that uses Entity Framework, called for instance EfCustomerRepository, which implements ICustomerRepository, it should go into your Infrastructure project, which must then reference your Core project.
Once you have this solution structure in place, it’s very easy for you to create a properly decoupled MVC application. You’ll probably want to use some kind of dependency inversion container (also called an IOC container), like StructureMap, Ninject, Unity, etc. My preference is StructureMap, and I have a walkthrough showing how to set up StructureMap with ASP.NET MVC 5 here.
Repositories are one of the more mainstream design patterns from DDD, and I recommend their use as an abstraction over your data access in your MVC applications. Having this abstraction makes it easier to unit test your controllers and services that require data, since otherwise you may only be able to test these classes using integration tests and a test database. It’s useful to remember that you don’t need to have “one repository to rule them all.” You can (and should) create different repository implementations and/or interfaces that provide the specific interface your client classes need. To this end, I try to avoid using repositories that return IQueryable<T> for a couple of reasons:
- It can be difficult to know if expressions that are run against the IQueryable will operate on objects in memory or rows in the database. This is in my experience a very frequent source of confusion and errors.
- It makes it easy for calling code to implement complex filtering rules that might make more sense somewhere else. For instance, if a Controller class is looking to return all preferred customers. This query might look for customers who bought at least $10,000 in the last 12 months. If this logic is embedded in the controller, it’s likely to be duplicated, violating the Don’t Repeat Yourself principle. Instead, you can include a custom method on the CustomerRepository (and its interface) that returns preferred customers. Alternately, you could embed this logic in a Specification class (which will soon be added to the design pattern library).
If you’re following DDD, you’ll also want to break up your entities and value objects into Aggregates, and identify the Aggregate Root of each aggregate. Your repositories should then only work with Aggregate Root entities, something easily enforced by a marker interface (e.g. IAggregateRoot) and a constraint on your IRepository<T> interface.
Most of DDD is not concerned with the kind of user interface the application or system is using. Assuming you have the solution configured correctly, you could swap out the ASP.NET MVC project for a WPF or Console Application project and it should continue to work well. In my talk at FalafelCON I will try to demonstrate this as well, while also showing some specifics of how the MVC application works with the Entities, Value Objects, and Services exposed by the Domain-Driven Designed Core of the solution.