On a yet-to-be-released side project of mine, I decided to use Fluent NHibernate, StructureMap, and ASP.NET MVC. It took me awhile to get everything to play together nicely, so I documented the steps I took in case anyone out there was interested in using in a similar setup.

Step 1: Set up StructureMap

First, I created the StructureMapControllerFactory class (taken from the MvcContrib project):

I then added the following line to the Application_Start() function in Global.asax.cs so that StructureMap would inject dependencies whenever an ASP.NET MVC controller was instantiated:

Step 2: Set up Fluent NHibernate

Next, I created a static function for creating an ISessionFactory (this code may look very different depending on your database and project setup):

Step 3: Hook up Fluent NHibernate with StructureMap

Then, I updated my Application_Start() function in Global.asax.cs so that StructureMap would be aware of how to instantiate an NHibernate ISessionFactory and ISession:

Now, whenever StructureMap needs to create an ISessionFactory, it calls the CreateSessionFactory() method defined in Step 2. Since ISessionFactory is expensive to create, I have configured StructureMap to create it as a Singleton so that it will only be created once per application.

Similarly, whenever StructureMap needs to create an ISession, it will create/retrieve an ISessionFactory instance and call its OpenSession() method. This is scoped at the HttpContext level, which means that at most, one ISession will be created by StructureMap per web request.

Step 4: Clean up

Finally, in order to ensure that we aren’t leaking ISessions on every web request, I added the following line to my Application_EndRequest function to properly dispose of the ISession StructureMap may have created during that web request:

The setup described above works on my machine with the following versions:

  • ASP.NET MVC 2
  • StructureMap 2.6.1
  • Fluent NHibernate 1.0.0.594

26 responses to Setting up ASP.NET MVC with Fluent NHibernate and StructureMap

  1. You could ofcourse have used my BoC project to save you some time ;-) :
    http://code.google.com/p/webdotnet/

    You’d just have to write a provider for StructureMap, which would take very little time (or use MS Unity, as that is the IoC container already supported)

  2. Isn’t that code still leaking ISessions? I mean, the sessions are only being cleaned up at the end of the application but the cleanup should happen at the end of each request…

    • Kevin Pang said:

      No, Application_EndRequest is fired at the end of every web request. I think you’re confusing it with the Application_End method, which is fired at the end of the application.

  3. Dsmacks said:

    Nice article, any chance of some source code to download?

  4. Jefferson said:

    Kevin, Great post. I’ve been looking for a more recent post about StructureMap. Many of the posts that I’ve found on the web are a few years old, and although are still applicable, many use the deprecated ForRequestedType. I’ve been trying to find some more recent posts as well that talks about some of the more advanced features of StructureMap. This one hit home for me and a project I’m developing at work.

    Thanks again,
    Jefferson

  5. subskii said:

    I’ve wanted to move away from another IoC provider and migrate to StructMap for some time now. I thought I should let you know your well written yet simple to follow post convinced to make the change tonight.

    Thanks so much for documenting this Kevin!

  6. subskii said:

    Hi Kevin

    How to actually get the HttpContextScoped ISession in my controller?

    • Kevin Pang said:

      Require an ISession as a parameter in your controller’s constructor and StructureMap (if it’s been set up correctly) will automatically inject it for you.

      For instance:

      private ISession session;

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

      • subskii said:

        Thanks!

      • Zeda said:

        I got an error “No parameterless constructor defined for this object” when I create my controller’s constructor with the parameter ISession. Anything wrong? Also, where do you specify the assembly file of say the IRepository? In the web.config or global.asax? Can you email me the set up in web.config or global.asax for the structuremap part?

        Thanks ton!

  7. Mike said:

    I like how you have this setup, except that I’m not injecting it into my controllers, I’m injecting it into my repository. And by the time the ISession gets to my repository, it’s closed. I don’t want to ahve to setup every controller to have an ISession that pass down to the repository.

    Thoughts?

  8. Mike said:

    Well, nevermind. Just after i posted the comment i figured one piece out. I hvae my repository setup as a singleton in my mvc app by structuremap. so of course, when it comes around to the calling of a method, the injected ISession has been closed and disposed.

    ForSingletonOf().Use(x => x.GetInstance());
    .......
    private ISession Session;
    public CustomerRepository(ISession session) {
    Session = session;
    }
    public Customer GetCustomer(int CustomerNumber) {
    var customer = Session.Linq().FirstOrDefault(x => x.CustomerNumber == CustomerNumber);


    So How do i get the session back into the repository without having to put a parameter on each method? Or is that what needs to be done?

  9. Mike said:

    it chopped the code:
    ForSingletonOf *CustomerRepository* ().Use *CustomerRepository* ();

    • Matt S. said:

      @Mike: Either don’t scope your repositories, or scope them to the HttpContext. Then, their contructors will get the necessary ISession just fine. I see no reason to scope repositories as singletons.

  10. Robert said:

    How have you set up unit tests for this system? If the data access layer has the NHibernate calls, but the session is created in the httpcontext, how do you create unit tests for the data access layer? I assume you would inject the session in the data access layer constructors, but it seems like you’d need to move the session creation out of the ObjectFactory.Initialize and put it in each TestSetup?

    • Kevin Pang said:

      You’re right in that if you want to unit test your data access layer using this setup, your unit tests will have to be responsible for NHibernate session management.. What I’ve done in my project is create a DatabaseTest base class that handles this in each TestSetup. It’s a little bit of extra work and code duplication, but it hasn’t bothered me so far.

      For unit tests on classes that utilize the data access layer, you won’t want to be connecting to a live database anyways so you can simply stub/mock out your repositories and not have to worry about creating NHibernate sessions.

      • Robert said:

        Can you post the code for your DatabaseTest base class and how it’s used in your TestSetup/TestFixtureSetup? We have an environment where our legacy database has a lot of business logic in triggers and so on, so we need integration tests that actually hit the database, so I would love to see how you handle database integration testing.

        • Kevin Pang said:

          Here’s my DatabaseTest class:

          public class DatabaseTest
          {
          protected ISessionFactory sessionFactory;
          protected ISession session;

          public DatabaseTest()
          {
          sessionFactory = CreateSessionFactory();
          }

          public void SetUp()
          {
          session = sessionFactory.OpenSession();
          }

          public void TearDown()
          {
          if (session != null && session.IsOpen)
          session.Close();
          }
          }

          I have to manually call SetUp() and TearDown() from the setup/teardown routines in any classes that inherit from this (I ran into a problem using the SetUp and TearDown attributes in DatabaseTest because NUnit seemed to not call them if I also had functions in the child class with SetUp and TearDown attributes).

          This ensures that before each test is run I have a clean ISession to use and that it’s properly disposed of after each test is run.

          • Kevin Pang said:

            Here’s a sample unit test using the DatabaseTest class:

            public class UserRepositoryTests : DatabaseTest
            {
            [Test]
            public void Test_Get_By_User_Id()
            {
            var userRepository = new UserRepository(session);

            var user = userRepository.GetByUserId(1);

            Assert.IsNotNull(user);
            }
            }

  11. Luka said:

    Hi,
    I am constantly getting Session is closed error!

  12. Juan Francisco said:

    Hello, where do we should put the entry for “InsertConnectionString”?

    • Kevin Pang said:

      You put your connection string name where “InsertConnectionString” is in my code example. The connection string should be defined in a .config file (e.g. web.config or app.config).

  13. Lee Brandt said:

    Nice Post!

  14. Darshan said:

    Loved It! Saved my time!
    Thank you.