Series Navigation

  1. Setup
  2. Mapping and Entity Equality

Introduction

In this series of posts, I will detail how I setup projects using the principles of domain driven design in ASP.NET MVC.

The tools and libraries we will use are as follows:

The sample app will be the canonical blog example. This series will be light on the discussion of the theory of DDD and heavy on the nuts and bolts of asp.net MVC implementation.

Project Structure

Create a new directory for the project.  I'm calling mine DDDSample.  Following subversion convention, create a trunk and branches folder inside of DDDSample.  Inside of trunk, create three directories: src, tools, and libraries.

The 'src' directory is where our code will go.  The 'tools' directory will have NUnit and in the future, NAnt.  The 'libraries' directory will contain the third party binaries that the project references.

Gathering the Libraries and Tools

1) Download the latest binary of fluent nhibernate from http://fluentnhibernate.org/downloads.  Put the fluent nhibernate binaries in trunk/libraries/fluent-nhibernate.

2) Download NHibernate.Burrow from http://sourceforge.net/project/showfiles.php?group_id=216446.  Put the burrow binaries in trunk/libraries/nhibernate.burrow.  Important Note: Sometimes the latest version of NHibernate.Burrow will not have been built against the same version of NHibernate as fluent nhibernate was.  Therefore, it is important that you be able to build NHibernate.Burrow, and the rest of the libraries that follow, from source.  NHibernate.Burrow is a part of NHContrib.  The NHContrib svn repository is located at https://nhcontrib.svn.sourceforge.net/svnroot/nhcontrib/trunk.  There is a build script in the root directory of the NHibernate.Burrow subdirectory of the project.  To rebuild with a different version of NHibernate, just replace the NHibernate dll in NHibernate.Burrow/lib/NHibernate with the binary of NHibernate from the fluent nhibernate.

3) Download NUnit from http://www.nunit.org/index.php?p=download.  Get the zip distribution . Unzip the entire contents into trunk/tools/nunit.  It is important that you include the full NHibernate distribution with your project so when we add an automated build tool later it will be able to run the unit tests without assuming that every developer has installed the correct version of NUnit from msi.

4) Download Moq from http://code.google.com/p/moq/downloads/list.  Put the binaries in trunk/libraries/moq.

5) Download MVCContrib from http://www.codeplex.com/MVCContrib.  Put the binaries in trunk/libraries/mvccontrib.

As an added measure of safety against change, I like to reference the MVC libraries themselves from binaries I store in my svn repository instead of from source.  You don't have to do this, but if you choose to, I put System.Web.Mvc, System.Web.Routing, and System.Web.Abstractions in trunk/libraries/mvc.

Your completed project structure should look like this:

Creating the Projects

Our mvc project and class libraries will go in trunk/src. 

Create an asp.net MVC project.  For this sample, I'm calling mine Blog.Web. 

Create two class libraries: Blog.Domain and Blog.Service.  Blog.Domain is where our POCO (Plain Old C# Objects) entities and our repository interfaces will reside.  Blog.Service is where the business logic that ties the application together will live.

Reference Blog.Domain and Blog.Service from Blog.Web.  Reference Blog.Domain from Blog.Service. 

Create a new solution folder (right click on project, hover over add, choose new solution folder) called Test.  This is where our test projects will go.

Create three class libraries: Blog.Web.Test, Blog.Domain.Test, and Blog.Service.Test.  In each of these projects reference NUnit.Framework from /trunk/tools/nunit.

More test projects may be needed later for separating unit tests from integration tests, but this is how I like to start with one unit test project for each of my projects.

The solution should now look like this:

Entity Base Class

In the domain, create an object ot be the base class for entities.  An entity is an object that has an identity.   

    1 namespace Blog.Domain

    2 {

    3     public abstract class Entity

    4     {

    5         private int id;

    6 

    7         public virtual int Id { get { return id; } }

    8     }

    9 }

There is no way to set the id property of the Entity base class.  This is by design.  Our persistence layer will use NHiberante generators to generate the identity values when we save new entities to the database.

Repositories

Just what are repositories?  Repositories are an abstraction of the way we manage aggregates.  Repositories should correspond only to aggregate roots.   An aggregate is a cluster of objects that are treated as a unit.  The aggregate root is the root object of the unit.

In Domain Driven Design, the repository interfaces are a part of the domain, but the implementations are not. 

Generic Repository of Entities

All entity repositories will need some base functionality, so we define IRepository<T> with some basic methods that we expect any repository to need. 

    1 using System.Collections.Generic;

    2 

    3 namespace Blog.Domain

    4 {

    5     /// <summary>

    6     /// Repository of entities. 

    7     /// </summary>

    8     public interface IRepository<T> where T : Entity

    9     {

   10         /// <summary>

   11         /// Find an entity by unique identifier.

   12         /// </summary>

   13         /// <param name="id">Unique identifier of the entity.</param>

   14         /// <returns>Entity if found, <c>null</c> otherwise.</returns>

   15         T Find(int id);

   16 

   17         /// <summary>

   18         /// Find all entities.

   19         /// </summary>

   20         /// <returns>Sequence of entities found.</returns>

   21         IEnumerable<T> FindAll();

   22 

   23         /// <summary>

   24         /// Save (insert or update as appropriate) <paramref name="entity"/> on next commit of the unit of work.

   25         /// </summary>

   26         /// <param name="entity">Entity to be saved.</param>

   27         void Save(T entity);

   28 

   29         /// <summary>

   30         /// Delete <paramref name="entity"/> on next commit of the unit of work.

   31         /// </summary>

   32         /// <param name="entity">Entity to be deleted.</param>

   33         void Delete(T entity);

   34     }

   35 }

Conclusions

In this post we have done a lot of nuts and bolts work.  The amount of setup required may seem daunting, but as stated earlier, the third party tools and libraries will pay dividends in the long-run. 

In the next post, we will create a Post entity, create a concrete implementation of IRepository<Post> using NHibernate, map Post to a database using Fluent NHibernate, and test our persistence model.


kick it on DotNetKicks.com