Posted by Kevin Pang on 8/17/2008 | Comment Comments (11) | Tags: ,

This post is to announce the release of Blunt Architecture, a lightweight web application framework built on the ASP.NET MVC framework.  My hope is that the Blunt Architecture project will help developers new to ASP.NET MVC get their feet wet by providing them a solid foundation to build upon.  I know that for me, having a lightweight sample project to play with always speeds up the learning curve.  As always, your comments are welcome, so please let me know what you think. :-) 

To start playing with the bits immediately, the source code is available here, or you can checkout the latest version using Subversion at http://bluntarchitecture.googlecode.com/svn/trunk/

To learn more about Blunt Architecture, read on.  The following is taken from the project documentation:

Introduction

The Blunt Architecture project is a lightweight web application framework showcasing ALT.NET best practices such as:

  • Domain driven design
  • Test driven development
  • Inversion of control / dependency injection
  • Model, view, controller

The Blunt Architecture project is based off of the S#arp Architecture project. Where the Blunt Architecture project differs is that it is meant to be used as a learning tool rather than a ready-for-production framework. Because of this, the Blunt Architecture project strives to avoid outside dependencies wherever possible. This allows the user to focus his or her attention on the concepts presented without the added distraction of also having to figure out the syntax and details of third party tools. Although this constraint causes certain tasks to be more tedious (e.g. object relational mapping, dependency injection, etc.), it should make the project more approachable to users unfamiliar with the third party libraries commonly used for simplifying the implementation of these concepts (e.g. NHibernate, StructureMap, etc.).

The overall goal of the Blunt Architecture project is to present ALT.NET best practices in the easiest manner possible while allowing the user the flexibility to plug in whatever third party libraries they wish once they are comfortable with the framework.

Project Structure

The Blunt Architecture solution is divided into five projects which will be detailed below. The web application contains only two pages: a home page:

And a customer listing page:

As stated above, this is a very bare bones project so please forgive me for the lack of a nice style sheet and pretty UI. :-)

BluntArchitecture.Controllers

This project contains the controllers used by the ASP.NET MVC framework to handle and respond to user input. Specifically, it dictates what happens whenever a URL is accessed. For example, in the HomeController class, the Index function below determines what happens when the user accesses the URL http://localhost/BluntArchitecture/Home:

This is a pretty boring function. It just sets the Title key in the ViewData dictionary which will be used by the master page to specify the title of the page, then returns the View (which will be the Index.aspx page found in the Home folder in BluntArchitecture.Web). This is all taken care for us by the ASP.NET MVC framework which you can read more about here.

The CustomerController class is a little more interesting:

You will notice here that CustomerController also has an Index function, but that it passes along an IList object to the view. This object will be used by the view to display customer information.

You will also notice that the customer controller has a private variable of type ICustomerDao, which is an interface defined in BluntArchitecture.Core that contains all the data access retrieval functions we need regarding customer information. This variable is meant to be set in the constructor of the CustomerController class, so it can be easily replaced by our unit test code (this is referred to as dependency injection). Normally, this injection would take place via a dependency injection tool such as StructureMap or Spring.NET, but in order to simplify the project we are defining a default constructor which will set the ICustomerDao object to an instance of CustomerDao, defined in BluntArchitecture.Data.

BluntArchitecture.Core

This is where we define our business objects as well as our data interfaces. Currently, the only business object is a simple Customer class:

As mentioned above, the data interfaces are also defined here. The reason we define the data interfaces here and not in BluntArchitecture.Data is to promote a separation of concerns between BluntArchitecture.Core and BluntArchitecture.Data. Because we specify the interfaces here, BluntArchitecture.Core doesn't need to depend on BluntArchitecture.Data. This has several benefits:

  • Developers are unable to sneak in data access code into the domain layer
  • The domain layer remains completely ignorant to how the data layer does its job. It only cares that the data layer implements the interfaces it needs. This allows us to switch out data layer implementation easily).
  • It allows us to use dependency injection to mock data access when testing the domain layer. This keeps our unit tests fast and dependable.

Here is our only data interface, the ICustomerDao interface which requires only one function to be implemented, GetAllCustomers:

BluntArchitecture.Data

This is where we define our data access layer. Currently, the only class defined here, CustomerDao, simply provides hardcoded results to the caller:

In a real application, this would be replaced with calls to a database or some other data store. How this is done is up to you (e.g. strong typed data sets, object relational mappers, etc.), just so long as you implement the interface. I specifically removed any decisions about data storage here to keep the solution as flexible as possible and to remove any third party specific requirements from the code (e.g. session management with NHibernate).

BluntArchitecture.Tests

This is where the unit tests go. Currently, the only unit test in place is the CustomerControllerTest. This unit test just makes sure that the Customer page can be loaded up and that it loads up the correct information from the ICustomerDao implementation. You will find a MockCustomerDao class that demonstrates how dependency injection can be used to create dependable unit tests.

BluntArchitecture.Web

This is where the front end of the application is defined. I won't go into how things work here as information regarding that can be found on [http://www.asp.net/mvc/ the official Microsoft ASP.NET MVC page].

Future Considerations

If there is enough interest in the project, I'd like to expand on this code base to show how to plug in third party libraries to speed up development (e.g. NHibernate, LINQ to SQL, Subsonic, StructureMap, Spring.NET, etc.).  Other than that I'm not sure I would want to add to the project as the motivation behind it was to keep it simple enough to function as an introductory sample.  If you have any thoughts, I'd be more than happy to hear them. :-)

Enjoyed this post? Share it with others!

Related posts

Comments

Mitch
Mitch on 8/20/2008 9:43 AM Nice post. I too have been looking at Sharp, but my current project won't let me make the jump to MVC. Possibly next time. I am interested in how you would integrate subsonic. I realize that in GetAllCustomers() you would just use a subsonic dataserivice, but would it not be a lot of overhead to proxy this into you domain classes. And how would you handle complex properies that are lazy loaded in subsonic? For example Invoice and InvoiceItems.
Thanks,
Kevin Pang
Kevin Pang on 8/20/2008 10:18 AM @Mitch

Excellent points, Mitch! Yes, it is a lot of overhead to proxy the info from the Subsonic generated classes to your object hierarchy, but it's the only way to really focus on domain driven design and avoid impedance mismatch. If you wanted to avoid this code duplication, you could use NHibernate to map directly to your domain. Personally, I find the overhead of mapping from Subsonic to the domain to not be too much of a hassle, mainly because I like having full control of how my domain objects are loaded / saved and because I'm already used to doing this mapping with strong-typed datasets.

As for lazy loading, you hit the nail on the head. That is the major drawback of using this implementation. I can't think of a very good way to get around this aside from persisting the Subsonic generated objects in your domain and accessing them when you want to load up lazy-loaded fields (ugly and goes against the whole concept of separating the domain and the data layer).

If you have any thoughts on how to get lazy loading to work in this scenario, I'd love to hear them! :-)
Mitch
Mitch on 8/21/2008 1:38 PM Thanks Kevin,

It does voilate some rules (not for the purist), but it also offers flexiblity. If the constructor takes the active record (or an interface) a business object could proxy the fields back to subsonic as they are changed. It is a lot of redundant code, but at least the model is not dictacted by the database.
Stu
Stu on 9/11/2008 3:46 AM Hello Kevin

Great post. I like what you are doing here. You say "if there is enough interest..." - would it be possible to read your thoughts on how to plug in SubSonic into this architecture please?

Thanks
Stu
Pendragon
Pendragon on 9/11/2008 6:27 AM When I open the project I get an error:
'The project file c:\develop\BluntArchitecture_1.0.0\BluntArchitecture.Web\BluntArchitecture.Web.csproj' cannot be opened.
The project type is not supported by this installation'. Do I have to do something with IIS to make this work?
Stu
Stu on 9/11/2008 6:44 AM @Pendragon
Are you opening it in Visual Studio 2008?
Pendragon
Pendragon on 9/11/2008 7:01 AM VS 2008 SP1.
I presume from your question that it's not 2008 friendly?
Jake Moon
Jake Moon on 9/11/2008 9:37 AM I also get an error when opening the solution in VS 2008: "The application for the project is not installed." This error is for the BluntArchitecture.Web project. The other projects load fine.
Kevin Pang
Kevin Pang on 9/11/2008 9:58 AM For those who are getting the "project type is not supported", it may be because the BluntArchitecture.Web is set up as a web application project type.

This did not come preinstalled on some Visual Studio packages. Check out http://webproject.scottgu.com/ for more information and see if downloading the installer fixes it.
Kevin Pang
Kevin Pang on 9/11/2008 10:01 AM @Stu

To plug in SubSonic, I would probably store the SubSonic generated DAL classes into the Data layer. I would then have mapping classes in my Data layer to handle the transitioning from my business objects to the SubSonic objects and use SubSonic to handle reading/writing to the database.

As Mitch pointed out though, this method will *not* support lazy loading, so it may not be the best approach for some. In those cases, I suggest using something like NHibernate to persist your objects.
Kevin Pang
Kevin Pang on 9/11/2008 10:17 AM Another thought for those getting the "project type is not supported". Have you installed the MVC templates? That could also be why you are getting the errors.

Add comment


 

[b][/b] - [i][/i] - [u][/u]- [quote][/quote]