Fluent NHibernate, auto mappings, ASP.NET MVC 3, and Castle Windsor

The title of this article is so long, I briefly considered using an acronym. Unfortunately, FNHAMASPDNMVC3CW doesn’t communicate much except to the nerdiest of nerds.

This is the third article in a series on using Fluent NHibernate with auto mappings. The first one demonstrated its basic functionality in a console application, and the second one showed how to convert the first one into an ASP.NET MVC 3 application. This article will cover how to use Castle Windsor for dependency injection, which is important for unit testing. I won’t include any unit tests in this article, but will lay the foundation that will make unit testing possible for my next article.

Much of the code below is directly from the Castle Windsor documentation, which really is exceptional.

Here’s what the completed project will look like:

Once again, create a new ASP.NET MVC 3 web application in Microsoft Visual Studio 2010 and use the empty project template. This time, call your project CastleFluentNHibernateMvc3. Next, right click on the project in the Solution Explorer and choose Manage NuGet Packages… Search the online gallery for Fluent NHibernate and install it. We also need Castle Windsor, so search for that and install it too.

EDIT 12/18/2012: You can get the source code on GitHub.

Once you’ve installed the packages, copy the Controllers, Models and Repositories folders from our previous project to our new project. Also, copy the Views/Home folder to our new project. Make sure you change the namespace in each file accordingly.

The first thing we need is a Windsor controller factory. The Windsor controller factory overrides two methods of the default MVC controller factory and is central to how Castle Windsor resolves controller dependencies. Create this class in a new Windsor directory at the root level of the project:

namespace CastleFluentNHibernateMvc3.Windsor
{
    public class WindsorControllerFactory : DefaultControllerFactory
    {
        private readonly IKernel kernel;

        public WindsorControllerFactory( IKernel kernel )
        {
            this.kernel = kernel;
        }

        public override void ReleaseController( IController controller )
        {
            kernel.ReleaseComponent( controller );
        }

        protected override IController GetControllerInstance( RequestContext requestContext, Type controllerType )
        {
            if (controllerType == null)
            {
                throw new HttpException( 404, string.Format( "The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path ) );
            }

            return (IController)kernel.Resolve( controllerType );
        }
    }
}

Next, we need to tell MVC to use the Windsor controller factory instead of the default one. To do that, we’ll add a couple of methods to the MvcApplication class, which resides in the Global.asax.cs file at the root of the project:

namespace CastleFluentNHibernateMvc3
{
    public class MvcApplication : System.Web.HttpApplication
    {
        private static IWindsorContainer container;

        private static void BootstrapContainer()
        {
            container = new WindsorContainer()
                .Install( FromAssembly.This() );

            var controllerFactory = new WindsorControllerFactory( container.Kernel );

            ControllerBuilder.Current.SetControllerFactory( controllerFactory );
        }

        // RegisterGlobalFilters and RegisterRoutes methods go here...

        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters( GlobalFilters.Filters );
            RegisterRoutes( RouteTable.Routes );

            BootstrapContainer();
        }

        protected void Application_End()
        {
            container.Dispose();
        }
    }
}

Now, we need to tell Windsor about our controllers, including where they reside and how to configure them. In other words, we’ll “register” our controllers with the Windsor “container.” We do this using an “installer.” Create this class in your Windsor directory:

namespace CastleFluentNHibernateMvc3.Windsor
{
    public class ControllersInstaller : IWindsorInstaller
    {
        public void Install( IWindsorContainer container, IConfigurationStore store )
        {
            container.Register( Classes.FromThisAssembly()
                                .BasedOn<IController>()
                                .LifestyleTransient() );
        }
    }
}

Next, create a new class named PersistenceFacility in your Windsor directory, and move the CreateSessionFactory, CreateDbConfig, CreateMappings and UpdateSchema methods of our NHibernateSessionPerRequest class there:

namespace CastleFluentNHibernateMvc3.Windsor
{
    public class PersistenceFacility : AbstractFacility
    {
        protected override void Init()
        {
            Kernel.Register(
                Component.For<ISessionFactory>()
                    .UsingFactoryMethod( CreateSessionFactory ),
                Component.For<ISession>()
                    .UsingFactoryMethod( OpenSession )
                    .LifestylePerWebRequest() );
        }

        private static ISession OpenSession( IKernel kernel )
        {
            return kernel.Resolve<ISessionFactory>().OpenSession();
        }

        // CreateSessionFactory, CreateDbConfig, CreateMappings and UpdateSchema methods go here...
    }
}

In the Init method, we’re telling Castle Windsor what to do when it encounters a dependency on ISessionFactory or ISession. If we ask for an ISession, it will resolve the dependency using the OpenSession method. Notice that this method needs an ISessionFactory, which Castle Windsor will resolve by calling CreateSessionFactory.

We’re also telling Castle Windsor that an ISession instance should be bound to a web request. Since we aren’t specifying a lifestyle for ISessionFactory, the default value of singleton will be used. In other words, only one session factory will be instantiated during the lifetime of our app, and it will hang around in memory until our app dies. This is basically the same thing we did before with our custom HTTP module, except the dependencies will only be resolved when needed. We can verify this by placing breakpoints in the OpenSession and CreateSessionFactory methods and running the app.

Now, we need to register our persistence facility with the Windsor container. Again, we do this using an installer. Create this class in your Windsor directory:

namespace CastleFluentNHibernateMvc3.Windsor
{
    public class PersistenceInstaller : IWindsorInstaller
    {
        public void Install( IWindsorContainer container, IConfigurationStore store )
        {
            container.AddFacility<PersistenceFacility>();
        }
    }
}

Next, we need to add a few more methods to our repository in order to manage NHibernate transactions: BeginTransaction, Commit and Rollback. Previously, we created a custom HTTP module to take care of these operations at the beginning and end of each web request. This time, we’ll manage each transaction ourselves, gaining more control and performance in the process. The GetAll, Get, SaveOrUpdateAll and SaveOrUpdate methods will stay the same:

namespace CastleFluentNHibernateMvc3.Repositories
{
    public interface IRepository<T>
    {
        void BeginTransaction();
        void Commit();
        void Rollback();
        // GetAll, Get, SaveOrUpdateAll and SaveOrUpdate signatures go here...
    }
}
namespace CastleFluentNHibernateMvc3.Repositories
{
    public class Repository<T> : IRepository<T>
    {
        private readonly ISession session;

        public Repository( ISession session )
        {
            this.session = session;
        }

        public void BeginTransaction()
        {
            session.BeginTransaction();
        }

        public void Commit()
        {
            session.Transaction.Commit();
        }

        public void Rollback()
        {
            session.Transaction.Rollback();
        }

        // GetAll, Get, SaveOrUpdateAll and SaveOrUpdate implementations go here...
    }
}

Notice that the repository constructor has been modified to accept an argument of type ISession. This is called dependency injection, and its benefits will become more clear when we use it in our home controller.

But first, we need to register our repositories with the Windsor container. How do we do that? Right! (You did say “use an installer,” right? Good.) Create this class in your Windsor directory:

namespace CastleFluentNHibernateMvc3.Windsor
{
    public class RepositoriesInstaller : IWindsorInstaller
    {
        public void Install( IWindsorContainer container, IConfigurationStore store )
        {
            container.Register( Classes.FromThisAssembly()
                                .Where( Component.IsInSameNamespaceAs<Repository<Store>>() )
                                .WithService.DefaultInterfaces()
                                .LifestyleTransient() );
        }
    }
}

Now, modify the home controller constructor as follows:

// Constructs our home controller
public HomeController( IRepository<Store> storeRepository )
{
    this.storeRepository = storeRepository;
}

The benefit of using dependency injection here is that we no longer have a dependency on a concrete repository. The home controller doesn’t care what the repository does with our data, as long as it implements IRepository. This way, we can change our repository methods without changing our controller actions. Later, when we write unit tests for our controller actions, we’ll be able to create an instance of the home controller using a fake repository so that our tests don’t touch our data.

Because we are no longer using a custom HTTP module to manage NHibernate transactions, we need to call the BeginTransaction method of our repository whenever we get data from or save data to the database. We also need to call the Commit method to flush the NHibernate session, and call the Rollback method if any errors occur:

// Gets all the stores from our database and returns a view that displays them
public ActionResult Index()
{
    storeRepository.BeginTransaction();

    var stores = storeRepository.GetAll();

    if ( stores == null || !stores.Any() )
    {
        storeRepository.Rollback();

        return View( "Error" );
    }
    
    try
    {
        storeRepository.Commit();

        return View( stores.ToList() );
    }
    catch
    {
        storeRepository.Rollback();

        return View( "Error" );
    }
}

// Gets and modifies a single store from our database
public ActionResult Test()
{
    storeRepository.BeginTransaction();

    var barginBasin = storeRepository.Get( s => s.Name == "Bargin Basin" ).SingleOrDefault();

    if (barginBasin == null)
    {
        storeRepository.Rollback();

        return View( "Error" );
    }

    try
    {
        barginBasin.Name = "Bargain Basin";
    
        storeRepository.Commit();

        return RedirectToAction( "Index" );
    }
    catch
    {
        storeRepository.Rollback();

        return View( "Error" );
    }
}

// Adds sample data to our database
public ActionResult Seed()
{
    // Create a couple of Stores each with some Products and Employees
    var barginBasin = new Store { Name = "Bargin Basin" };
    var superMart = new Store { Name = "SuperMart" };

    var potatoes = new Product { Name = "Potatoes", Price = 3.60 };
    var fish = new Product { Name = "Fish", Price = 4.49 };
    var milk = new Product { Name = "Milk", Price = 0.79 };
    var bread = new Product { Name = "Bread", Price = 1.29 };
    var cheese = new Product { Name = "Cheese", Price = 2.10 };
    var waffles = new Product { Name = "Waffles", Price = 2.41 };

    var daisy = new Employee { FirstName = "Daisy", LastName = "Harrison" };
    var jack = new Employee { FirstName = "Jack", LastName = "Torrance" };
    var sue = new Employee { FirstName = "Sue", LastName = "Walkters" };
    var bill = new Employee { FirstName = "Bill", LastName = "Taft" };
    var joan = new Employee { FirstName = "Joan", LastName = "Pope" };

    // Add Products to the Stores
    // The Store-Product relationship is many-to-many
    AddProductsToStore( barginBasin, potatoes, fish, milk, bread, cheese );
    AddProductsToStore( superMart, bread, cheese, waffles );

    // Add Employees to the Stores
    // The Store-Employee relationship is one-to-many
    AddEmployeesToStore( barginBasin, daisy, jack, sue );
    AddEmployeesToStore( superMart, bill, joan );
    
    storeRepository.BeginTransaction();

    try
    {
        storeRepository.SaveOrUpdateAll( barginBasin, superMart );
    
        storeRepository.Commit();

        return RedirectToAction( "Index" );
    }
    catch
    {
        storeRepository.Rollback();

        return View( "Error" );
    }
}

You can now run your application. If you get any errors, make sure you have an empty database and a valid connection string. In that case, see my previous article for instructions on setting that up. If all you see is the word “Index,” it’s because you don’t have any data in your database yet. In your browser, navigate to the Seed action of the home controller. You should then see “Index” at the top followed by a list of stores, products and employees.

Next time, we’ll look as using NUnit and Moq for unit testing. Surprisingly, it’s relatively easy! As always, let me know if you have any difficulties. Good luck!

Advertisements

7 thoughts on “Fluent NHibernate, auto mappings, ASP.NET MVC 3, and Castle Windsor

  1. juan

    Hi first at all, tell u thanks for all this amazing work that u r doing.
    Dave i´m trying to do a web site using your manual “Fluent NHibernate, auto mappings, ASP.NET MVC 3, and Castle Windsor” but i have some question.
    1) How can we configure more than one Irepository at same time?
    for example , i have IRepository and IRepository2
    when i call the homecontroller i would like to have both
    // Constructs the home controller
    public HomeController( IRepository storeRepository, IRepository2 storeRepository2 )
    {
    StoreRepository = storeRepository;
    StoreRepository2 = storeRepository2;
    }

    What do u think that will be better have 2 generic repositories or one big with all the methods that we need?

    Many thanks

    Reply
    1. Dave Post author

      Juan,

      Without knowing what the second repository is doing, I’d say you want to just have one interface to reduce code duplication. Can you give me a little more detail?

      Reply
      1. juan

        thanks for reply my post.
        the second repository will be for example for manage a custom membership provider.
        Dave if for example i have one repository calling “Store” but on my view i need to load all the “Clients” or all the products, if this general repository is based on “Store” how can i do that? I have to add this specific method to the general repository like GetAllClients() ?? what do you think?
        Many thanks for all , you are the best and your tutorial are awesome.

        Reply
    2. Dave Post author

      Juan,

      Now I see. That generic repository will work for any of your entities. Here’s how you would inject a repository for Store and a repository for Client in your home controller:

      private readonly IRepository<Store> StoreRepository;
      private readonly IRepository<Client> ClientRepository;
      
      public HomeController( IRepository<Store> storeRepository, IRepository<Client> clientRepository )
      {
          StoreRepository = storeRepository;
          ClientRepository = clientRepository;
      }
      

      When you call StoreRepository.GetAll() it will get all the Store records, and when you call ClientRepository.GetAll() it will get all the Client records. The reason is because the GetAll method is a generic method:

      public IQueryable<T> GetAll()
      {
          return Session.Query<T>();
      }
      

      See here for more info on generic methods. Hope this helps.

      Reply
  2. Eldar

    I’m curious Is it possible to move all references to NHibernate, Fluent NHibernate in a separate Unit of Work project ?

    Reply
    1. Dave Post author

      Eldar,

      The only references to NHibernate or FluentNHibernate in this project are in the Repository and PersistenceFacility classes. You could definitely move those to a separate project, but I’m not sure what you would gain from it.

      Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s