S#arp Architecture

  1. Unzip the SharpArchitecture release zip which will include the example project; this will create the following folders:


    • bin: Contains all of the assemblies used by SharpArch and the Northwind sample code,
    • src: Contains the NorthwindSample and SharpArch sample code,
    • VisualStudioTemplate: This was discussed previously.

  2. Open the VS 2008 solution file at <unzip location>\src\NorthwindSample\Northwind.sln


  3. Modify the connection string in Northwind.Web/NHibernate.config to point to a Northwind database. (It's currently configured for working with SQL Server 2005.) If you do not have Northwind readily available, you can download one from Microsoft’s SQL Server Community and Samples. This will also work with a SQL Server Express database (2005 or 2008). If you decide to use a SQL Server 2008 database you should also edit the 'dialect' section to 'NHibernate.Dialect.MsSql2008Dialect'


  4. Modify the connection string in <unzip location>\src\NorthwindSample\app\Northwind.Wcf.Web\NHibernate.config to point the above a Northwind database


  5. Modify the connection string in <unzip location>\src\NorthwindSample\tests\Northwind.TestsUsingDevelopmentDatabase\Hibernate.cfg.xml to point the above a Northwind database


  6. Compile the solution.


  7. Open NUnit 2.5, go to File / Open Project and open <unzip location>\src\NorthwindSample\tests\Northwind.Tests\bin\Debug\Northwind.Tests.dll and run the tests. They should all pass.


  8. In VS 2008, click F5 (after making sure that Northwind.Web is set as the start up project) to open http://localhost:####/ to see all of the project elements in action including controller injection of data access objects and NHibernate lazy loading.


  9. Use the links from the homepage to view other actions such as listing data, performing lazy loading actions, and running through full CRUD of managing employees, with validation.



Examining the Project Tiers

The Northwind example project is identical in structure to a project generated with the Visual Studio project template. While a number of folders exist for the sake of organizing the solution resources, it is the solution itself which is of primary interest when discussing what defines a S#arp Architecture project. Before digging into some of the more interesting aspects of the individual project layers, let’s take a high level look at a S#arp Architecture project’s overall solution structure. The following diagram shows each project layer in the solution as a box. The direction of dependencies is illustrated indicated, accordingly.

The folder structure that the Northwind solution is organized within attempts to give order to the solution and provide a solid approach to meet your programming needs throughout the life of the project. The folder structure, which is also reflective of that generated by the Visual Studio project generator, discussed later, is shown below. Only the purpose of the folders themselves are described here, as the projects themselves are discussed next.

/NorthwindSample – Contains Northwind.sln and subfolders. /app - Contains the core project layers: /Northwind.ApplicationServices /Northwind.Core /Northwind.Data /Northwind.Web /Northwind.Web.Controllers

/build - Empty folder for housing build related artifacts.

/db - Contains database schema information; e.g., the potential result of scaffolding and/or NHibernate's schema exports.

/docs - Project specific documents if you can believe it.

/lib - Contains the deployable solution items for the application.

/logs - Output location for log files.

/tests – Contains any test projects: /Northwind.Tests /Northwind.TestsUsingDevelopmentDatabase (not generated with VS template)

/tools /lib - Contains the solution items for the tests project and all other non-deployable assemblies. /CrudScaffolding - Customizable CRUD, scaffolding generation code.

While the generated folder structure makes it convenient to organize project related artifacts such as dependencies, database scripts, and docs, it is the solution itself which is of most interest. So let’s now take a light look at each project layer, focusing on specified areas of interest in each. While there are many more details of each layer discussed in the tutorial discussed later, what are discussed here are points of interest and descriptions of the projects themselves.

Northwind.Core: The Domain Layer and the “M” in MVC



This class library contains all of the domain objects along with interfaces for any custom repositories. This should be seen as the heart of the application.

Concerning Custom Collections

Without the proper approach, custom collections can be tricky with NHibernate. As NHibernate can only communicate with interfaces when loading a collection onto an object, it’s not possible to trivially bind to e.g. MyCustomerCollection which implements an IList. Instead, it’s simplest to bind a collection loaded by NHibernate directly to an IList and then to use extension methods, as described below, to extend the collection’s functionality with custom methods.

Also note, by looking at Customer.Orders, that collections bound by NHibernate should be initialized to a new list within the constructor and have a protected setter on the property itself. This serves two benefits:

  • The collection will never be null. Because the collection is initialized during construction and cannot be set directly, checking for a null value is unnecessary; this avoids any “null object reference” exceptions and keeps the code clean.

  • If NHibernate loads the collection onto the object, it will keep track of the reference to the collection. Accordingly, the reference to the collection itself should not be replaced to avoid problems. It’s fine to use methods such as Clear() to manipulate the collection, but it shouldn’t be replaced altogether; therefore, having the setter be protected takes a step to ensure this.

Northwind.Core.OrdersExtensions is an example of adding a custom method to a NHibernate bound collection; e.g., IList. This removes the complexity of other alternatives to managing custom collection with NHibernate. (Some more complicated alternatives, which are compatible with .NET 2.0 and do not require extension methods, are described at http://devlicio.us/blogs/billy_mccafferty/archive/2007/12/03/custom-collections-with-nhibernate-part-i-the-basics.aspx.)

Northwind.Web.Controllers: The “C” in MVC



This layer contains all of the controller classes which handle HTTP requests before returning a view. It also contains a route registration class, RouteRegistrar.cs, for mapping routes, which is invoked from Global.asax. With S#arp Architecture, there are two key points to note in the controllers layer: controllers depend only on service object interfaces, and database transactions are managed with a transaction attribute. (Transactions may be managed manually but are greatly simplified with the use of the transaction attribute.)

Dependency Injection of Service Objects

A controller class should never have a direct dependency on a service object; e.g., a data access object. Instead, controller classes should only depend on service object interfaces. A dependency injection mechanism is used to inject the concrete instances into the controller at runtime. S#arp Architecture uses the mature, dependency injection library Castle Windsor (http://www.castleproject.org/container/) for handling this responsibility. To maintain a clean separation to the dependency injection mechanism, the controller classes are unaware what tool is performing the dependency injection; they only need to specify what dependencies are required via the constructor parameters; i.e., the Northwind.Web.Controllers assembly has no reference to the Castle Windsor library. As an example, the Northwind.Web.Controllers/CategoriesController.cs class defines the needed dependency, in this case IRepository, within the constructor. Windsor handles figuring out the appropriate concrete object to pass to the constructor at runtime. The primary benefits include promotion of a loosely coupled design and facilitation of easy unit testing with test doubles.

The snippet below demonstrates defining a controller’s dependencies via its constructor:



public class CategoriesController : Controller {

public CategoriesController( IRepository categoryRepository ) {

this.categoryRepository = categoryRepository;

}

private readonly IRepository categoryRepository;

}


Transaction Management

A challenge with ASP.NET MVC is wrapping multiple data manipulation activities into a single transaction within an action method. A possible solution is to programmatically start the transaction at the beginning of the action method and to commit/rollback the transaction at the end of the action method. The drawbacks to this include making the controller aware of the data access mechanism (we’d rather it be completely agnostic) and introducing data communication logic into the controllers layer. This latter point breaks the separation of concerns that we work so hard to maintain. To accommodate transactions while keeping the controllers layer data access agnostic, an ASP.NET MVC action filter attribute is provided to open a transaction at the beginning of an action method and to commit/rollback the transaction at the end of the transaction. An example usage is found above the method Northwind.Web.Controllers.CategoriesController.Create(). Note that by default you must use a transaction attribute above any controller method which will cause changes to the database. Furthermore, for best performance, it is recommended to use a transaction attribute above every method which interacts with the database.

The following shows an example of using the transaction attribute on a controller action:



Transaction public ActionResult Create(string categoryName) {

Category category = new Category(categoryName);

category = categoryRepository.SaveOrUpdate(category);

return View(category);

}

The transaction attribute is provided within the SharpArch.Web library. Although the transaction attribute is very handy, it is not required for use. At times, you may want to manage the transaction via a unit of work or within a service layer. So alternatively to using the Transaction attribute, every IRepository exposes an IDbContext with the following methods:

  • CommitChanges to flush all pending changes to the DB,
  • BeginTransaction to begin a new transaction,
  • CommitTransaction to commit the transaction, and
  • RollbackTransaction to…well, you can probably figure it out.

Why are the controllers in a separate assembly?

Deciding to put the controllers into a physically separate assembly was a very deliberate decision. For a more thorough discussion of this, please see http://devlicio.us/blogs/billy_mccafferty/archive/2009/01/09/an-argument-for-moving-asp-net-mvc-controllers-to-a-separate-assembly.aspx.



Northwind.ApplicationServices: The Coordination Layer

This initially empty class library contains all of the objects which make up the service layer of the application. These services are typically used by the Controllers layer to coordinate application level logic. Note that these services should not necessarily be interpreted as being web services. Note also that there is a difference between “Domain Services” and “Application Services.” While determining exactly what goes into the application services, and where to draw the line between them and your controllers and your domain, is beyond the scope of this document (for now), I encourage you to read Martin Fowler’s Patterns of Enterprise Application Architecture which goes into good detail with respect to the inclusion of a service layer. Also on the reading list must be Eric Evan’s Domain Driven Design; or for a quicker introduction to the subject of various service types, read DDD: Services and Services in Domain-Driven Design.

Do I really need an Application Services layer?

The Application Services layer should be leveraged when needed, based on the size and requirements of the project. For smaller projects, you may not find much benefit in this layer and may even consider removing it altogether. For larger projects, it is instrumental in keeping the Controllers layer clean. You should discuss with your team at the beginning of any project how the Application Services layer will be used throughout development.

Northwind.Data: The Data Layer



When compared to the article that was the predecessor to S#arp Architecture, NHibernate Best Practices with ASP.NET (see “NBP” in the references Appendix), the updated architectural foundation removes much complexity while being much more extensible; e.g., there's no DaoFactory in S#arp Architecture and it's much simpler to add new Repositories and extend them with custom methods when compared to the guidance given in the article. (Note also that in this updated architecture, DAOs are now known as “Repositories.”) To make it even easier, no action needs to be taken to support “out of the box” data access functionality for any persistent domain object. For example, to have full Repository support for a Category object, you’d simply create a new Repository instance without having to develop a custom “CategoryRepository” class.

But there are times when you’ll need to add additional capabilities to the default Repository behavior; such as adding a custom Repository method. Look at Northwind.Core/ISupplierRepository.cs to see the interface of a custom Repository for doing just that. The implementation of this custom Repository is Northwind.Data/SupplierRepository.cs. These classes simply inherit from IRepository and Repository, respectively, to include the “out of the box” Repository functionality augmented with the new, custom Repository method.

In the incredibly rare (and discouraged) circumstance wherein your object requires an assigned ID, then you can instead inherit from RepositoryWithTypedId. Look at Northwind.Core/ICustomerRepository.cs as an example of this. The implementation of the custom Repository class is Northwind.Data/CustomerRepository.cs. Notice that this class inherits from RepositoryWithTypedId because Customer has an ID type other than int. This particular Repository was included to demonstrate an example of supporting an object with an assigned ID. (Please note that assigned IDs are the spawn of the devil and should be avoided.)

Northwind.Tests: The Unit Testing Layer



This class library contains all of the unit tests for testing the layers of your custom application. Browse these tests to see examples of how the various other layers are tested. You’ll see that there is a separate folder for testing each layer of the application.

Of particular interest are the tests within Northwind.Tests/Northwind.Data. Almost all of these tests leverage SQLite for running database tests against an in-memory database. This greatly speeds the unit tests and removes the need to keep a development database in synch with the unit tests. Obviously, you’ll also want to make sure that your NHibernate mappings are compliant with the “live” database. The unit test at Northwind.Tests/Northwind.Data/NHibernateMaps/MappingIntegrationTests.cs ensures that this is the case. The mapping tester isn’t completely comprehensive, but it certainly helps! (This integration test is automatically included when using the S#arp Architecture Visual Studio template to create your own project.)

Northwind.TestsUsingDevelopmentDatabase

This testing library has been provided to demonstrate how to develop unit tests against a “live” development database. As demonstrated in the Northwind.Tests library, it is recommended to use SQLite for data communication tests. But if you feel more comfortable testing against a persistent database, or have a very complicated scenario to test, then this class library should serve to be a good example for you. This project is not automatically generated and included when using the Visual Studio project template.

Northwind.Web: The “V” in MVC

This is the web layer of the sample application which ties everything together via configuration and exposes the presentation pages.

Items of particular interest are the Global.asax.cs class and the component registration class, /CastleWindsor/ComponentRegistrar.cs.

Hosting WCF Services via IIS

An example of doing this will be coming before the final 1.0 release of S#arp Architecture.



ScrewTurn Wiki version 2.0.36. Some of the icons created by FamFamFam.