In this post I said something about dependency injection and that we all should, well, inject dependencies. Why? To make our applications loosely coupled. In an ASP.NET MVC 3 application, I don't want my Views to know what is in my persistence layer. Hell, I don't even want my Controllers to have a notion. And I want to be able to change the Entity Framework with Nhibernate or DB4o.

And since I have this obsession with Nhibernate lately, this post is again about Nhibernate. And Ninject.

Wire up Nhibernate in ASP.NET MVC 3

A Nhibernate Session is very cheap and does not require too many resources. So, we're setting up a session per web request, in Global.asax. The session opens when the request begins and closes when the request ends. I already blogged about that here. This also how Ayende demonstrates this in the Tekpub series.
Global.asax is also the place where we wire up Ninject. Download Ninject.Web.Mvc and Ninject from here rather than from Github, because strange things happen if you don't.

Now, take a look at my very bloated Global.asax:

using Ninject;
using Ninject.Web.Mvc;
using System.Reflection;
using NHibernate;
using NHibernate.Context;
using NHibernate.Cfg;
using System.IO;
using HibernatingRhinos.Profiler.Appender.NHibernate;
namespace Concepts.Web
{
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
// visit http://go.microsoft.com/?LinkId=9394801
public class MvcApplication : NinjectHttpApplication
{
/// <summary>
/// Create the Nhibernate Sessionfactory
/// </summary>
public static ISessionFactory SessionFactory = CreateSessionFactory();
public MvcApplication()
{
this.BeginRequest += new EventHandler(MvcApplication_BeginRequest);
this.EndRequest += new EventHandler(MvcApplication_EndRequest);
}
void MvcApplication_EndRequest(object sender, EventArgs e)
{
CurrentSessionContext.Unbind(SessionFactory).Dispose();
}
void MvcApplication_BeginRequest(object sender, EventArgs e)
{
CurrentSessionContext.Bind(SessionFactory.OpenSession());
}
private static ISessionFactory CreateSessionFactory()
{
var cfg = new Configuration().Configure(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "nhibernate.config"));
NHibernateProfiler.Initialize();
return cfg.BuildSessionFactory();
}
/// <summary>
/// Ordinary Global.asax stuff
/// </summary>
/// <param name="filters"></param>
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//important for Ninject to set this:
routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.ico(/.*)?" });
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
/// <summary>
/// Ninject Kernel loads
/// </summary>
/// <returns></returns>
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
return kernel;
}
/// <summary>
/// Creates the controllerfactory (I think)
/// </summary>
protected override void OnApplicationStarted()
{
base.OnApplicationStarted();
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
}
}

Sorry for that.

So, when we issue a webrequest, a Nhibernate Session is established. A Session in Nhibernate is the same as a Unit of Work. It's also comparable with the Linq to SQL's datacontext.
Now let's create a PersonRepository interface:

using System.Web;
using Concepts.Core;

namespace Concepts.Web
{
    public interface IPersonRepository
    {
        IQueryable<Person> GetPersons();
    }
}

And implement the interface with Nhibernate:

using System.Web;
using NHibernate;
using Concepts.Core;

namespace Concepts.Web
{
    public class PersonRepository :IPersonRepository
    {
        private ISession _session;
        public PersonRepository(ISession session)
        {
            _session = session;
        }
        public IQueryable<Person> GetPersons()
        {
            return _session.CreateCriteria<Person>().List<Person>().AsQueryable();
        }
    }
}

Now the Dependency Injection trick. We'll use Ninject to bind the IPersonRepository to our PersonRepository, and to bind the ISession to the method GetCurrentSession from Global.asax:

using System.Web;
using Ninject.Modules;
using NHibernate;

namespace Concepts.Web
{
    public class ConceptsNinjectModule : NinjectModule
    {
        public override void Load()
        {
            this.Bind<IPersonRepository>().To<PersonRepository>();
            this.Bind<ISession>().ToMethod(x => MvcApplication.SessionFactory.GetCurrentSession());
        }
    }
}

And now we can inject our HomeController with the IPersonRepository.. ! When we fire up our controller methods, Ninject sees that we implemented the PersonRepository, which uses Nhibernate. And this, ladies and gentlemen, is so cool, it hurts.

namespace Concepts.Web.Controllers
{
public class HomeController : Controller
{
private IPersonRepository _repo;
public HomeController(IPersonRepository repository)
{
_repo = repository;
}
[TransactionFilter]
public ActionResult Index()
{
var persons = this._repo.GetPersons();
foreach (var p in persons)
{
Response.Write(p.GivenName + "<br />");
}
return View();
}
}
}

You can get the complete source code here.