Project Example: ASP.NET MVC + SubSonic Architecture

So I've thrown up a couple of posts over the past couple of months regarding our use of SubSonic to provide the DAL in association with some ASP.NET MVC sites and was waylaid in my original intent to throw up a post summarizing the architecture we're using for the effort. Well I've finally gotten around to it.  Recall that in his fake it till you need it post, Dave provided a window on our architecture that I'll build upon here.

Media_httpbriannoylew_edknr

Example MVC Architecture
In the diagram above, Dave's original concept is shown on the left for reference with my breakout to the right, similarly color coded for consistency.

The UI:

No surprises here.  ASP.NET MVC drives the show from the front end with JQuery, Dojo, or both providing the shiny bits in the browser for the users.  And since we love our unit tests (and are making strides in one of the projects to be TDD), the separation of concerns/tiers within ASP.NET MVC allows us to unit test our controllers thoroughly.

The Domain:

The domain of our architecture is actually evolving.  Our first iteration of this architecture worked with both domain objects and POCOs (plain old CLR/C# objects) in the domain layer.  I've included the MVC Model in the domain as well because, with some exceptions, it is holding the data required to successfully render a View...an argument can be made that it is UI as well, but that is beyond the scope of this post.   As illustrated above, a POCO is simply a data transfer mechanism while the domain object may combine one or more POCOs in new and interesting ways to be rendered by a view. Keeping domain objects and POCOs separated allows us to unit test Model and domain object logic while still letting us "fake" all of the repository and data interaction. Later iterations of this architecture take a more DDD approach, eliminating POCOs entirely due to their tendency to push the schema up the architecture, relying instead on the IRepository to return domain objects to the Controller or Model without the middleman.  Either way, there is sufficient abstraction to fake and unit test robustly.

The Repository:

This is where Dave left us off in his original post...the ISomethingRepository. Interface based repositories do all kinds of good stuff for the architecture most notably encouraging DI/IOC patterns that allow faking of repository behavior until we actually have a bona fide need to test against a live database.  One developer can unit test his Model and Controller against:
public class FakeSomethingRepository : ISomethingRepository
And later on we'll flip the Castle Windsor switch and hit:
public class SqlSomethingRepository : ISomethingRepository
when the system goes live. The repository layer implementation classes are the only place where facts about the data source and the domain layer are known in the same place.  And since these classes have responsibility for data CRUD in the application, unit testing is critical and supported by the nice separation in this architecture once again.

The DAL:

This is where SubSonic takes over.  We simply point it at our database, generate a suite of DAL classes, and off we go.  In our first iteration, the tendency for SubSonic to like to work against tables proved challenging from a domain driven perspective, but as it turns out we were handed an existing schema that we were bound to anyway.  Plenty of Sql Server Views solved most problems. So a typical repository method exercising the SubSonic DAL might look something like:
 /// <summary>
 /// Gets the customer by id performing a deep load of roles.
 /// </summary>
 /// <param name="customerId">The customer id.</param>
 /// <returns></returns>
 public UDSH.Domain.Customer GetCustomerById(int customerId)
 {
            //this passes back a user with all contained collections
            Domain.Customer result = null;

            //get the user using subsonic query
            result = DB.Select().From<Customer>().
                        Where(Customer.Customer_IdColumn).IsEqualTo(customerId).
                        ExecuteSingle<Customer>();

            if (result != null)
            {
                //attach roles
                result.Roles = GetRolesForUser(result.CustomerId);
            }

            return result;
 }
There is acutally a little more to it than that...the call to SubSonic in our live code acutally includes a call to a custom recursive function that converts a SubSonic type to a domain object on the fly.

Summary:

Thus far, this archtecture has worked out very well in our agile environment, allowing front end developers and those responsible for mid-tier and back end coding to work relatively independently without running over each other.  At the same time, it allows us to thoroughly unit test all practical areas of the application with excellent code coverage, guaranteeing quality in the finished product.  And the MVC + JQueyr or Dojo combo on the front end allows us to do some very shiny things in the UI for the user's benefit. Despite the convenience of using of a code generator for the DAL, it's likely we'll be moving away from the use of SubSonic in the future...simply to many issues start popping up with even moderately large or complex data schemas.  The heavy dependence of stored procs to do even elementary cross joins with WHERE clauses and annoying issues with DISTINCT, among other things, have moved us to look elsewhere.  That said, development has proceeded smoothly and our sites built in this manner with this technology stack run fast and right.