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:
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.
You can get the complete source code here.
I commented on your earlier Fluent NHibernate post about DI. Thanks for this post however I’m still confused about the decoupling as your PersonRepository is bound to NHibernate so you couldnt swap in DB4O easily.
Maybe I’m missing something?
Hi Jon, thanks for your comments!
I probably had to name my PersonRepository NHPersonRepository. Then it would make more sense. I will see if I can plug Db4o in the example later today, as a proof of concept for Dependency Injection. 😉
Well, I actually replaced Nhibernate with Db4o quite easily. I renamed PersonRepository to NHPersonRepository and created a Db4oPersonRepository added the Db4oSession stuff.
I had to plumb the Global.asax though.. and I had some discrepancies between the NHibernate Session and the Db4O Session. But I did not have to touch the Controllers and the Views. So that is a good thing.
You might want to see this in terms of DI performance – http://weblogs.asp.net/gunnarpeipman/archive/2010/09/21/unity-castle-windsor-structuremap-ninject-who-has-best-performance.aspx
Cool. Thanks
I’ve been reading a bit more about DI and NHibernate and I have seen a comment that NHhibernate uses Castle.Windsor as its default IOC. Fancy doing a post about wiring up a MVC 3 app, NHibernate and Castle.Windsor?
Hm, I already thought of that but take a look at the documentation on their site! It’s ancient! But I could give it a shot, for the sake of it..
Or you could try and we could share code 🙂
I know its more mature than others but I thought as it uses it by default and I also might look at using Castle ActiveRecord it would be a good combination. I might not use ActiveRecord and therefore look at Ninject or Munq or other IOC but for now I thought I’d try the above. Will let you know how I get on. Also documentation is not that great I find or too bloated for just simple examples.
Excellent thanks.
I spent the last few days trying to build NHibernate, Byte.Castle, Fluent NHibernate and Windsor in a solution but it wasn’t working out. Somewhere along the line there was a version mismatch dependency.
In the end I created a solution added a package reference via NuGet and got it all compiled. I then tried to update all references to the latest thinking it was bound to break but it worked.
This has been a learning curve which is good as I enjoy learning although not sure how keen I am to swap out Windsor if I decide to use another IOC. Not exaclty easy stuff this!
On a seperate design issue I was wondering if I could get your thoughts. If I am injecting interfaces into
controller constructors to resolve a ProductsRepository class to
IProductsRepository in a ProductsController, if later on I then need to make
a check for something in one of the Actions against orders I would then have
to create a new instance of the class eg/OrderRepo orderRepo = new
OrderRepo. At that point I am now bound to that class rather than the
interface. In this case would you recommend inserting a IOrdersRepository
into the controller constructor, resolve the class with Windsor and then it
can be used in the Action I need? This is probably not a great example as the model should have a relationship but say if you had a IWebSiteSettings repository and you needed it in one action, would you still pass it into the constructor?
I think I would pass it into the constructor, but if there are many dependent classes it might become ugly. Couldn’t the IProductsRepository have a method that gets the number of Orders of that product or so? Then you wouldn’t need to add an extra IOrderRepo to the controller constructor. Something along these lines: https://github.com/robconery/Kona/blob/master/Kona.Web/Repositories/IStoreRepository.cs.
Hi, Just curious… what if I wanted to store all my nhibernate Mappins, Config etc. within my repository layer alongside my database configuration, create my modules within my domainservice layer then DI inject from my ASP.NET MVC app, how would I configure my ISession? I do not want to let my web app know about NHibernate… my entities are in a seperate project which is accessed by the web app, repo layer and domain service?
Hi Haroon, you can create an action filter for the session, or you can use HTTP modules, like this: