1

Edit

I would like to try to do what Remo Gloor has recommended

  1. Create a SessionFactoryProvider derived for Provider that retruns a SessionFactory using the code in OnApplicationStarted
  2. Create a binding for SessionFactory using the new provider and put it in SingletonScope
  3. Create a SessionProvider derived from Provider that gets the SessionFactory injected in the constructor and retuns a new session using GetCurrentSession of the factory.
  4. Create a binding for ISession to the above provider with activation and deactivation actions that open, transmit, rollback, and close the session (basiclly the code from Application_BeginRequest, EndRequest). Decalre the binding as in request scope.
  5. Remove Application_BeginRequest, EndRequest.
  6. Bind the repo using Bind().To();

I am looking for a tutorial that hits on these points with a file that I can download and play around with. If it uses lots of generics you needs to be pretty detailed as generics still get me.


Hi

I am trying to do session per request with my nhibernate.

I done this in my global.aspx

using System;
using System.Web.Mvc;
using System.Web.Routing;
using Demo.WebUI.Models.NinjectModules;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using NHibernate.Context;
using Ninject;
using Ninject.Modules;
using Ninject.Web.Mvc;


namespace Demo.WebUI
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : NinjectHttpApplication
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new {controller = "Account", action = "Login", id = UrlParameter.Optional} // Parameter defaults
                );
        }

        public static ISessionFactory SessionFactory { get; private set; }

        protected override void OnApplicationStarted()
        {
            AreaRegistration.RegisterAllAreas();
            RegisterRoutes(RouteTable.Routes);

            SessionFactory = Fluently.Configure()
                .Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("test")))
                .Mappings(m => m.FluentMappings.AddFromAssemblyOf<Demo.Framework.Data.NhibernateMapping.UserMap>())
                .ExposeConfiguration(x => x.SetProperty("current_session_context_class", "web"))
                .ExposeConfiguration(BuidSchema)
                .BuildSessionFactory();
        }


        protected void Application_BeginRequest(object sender, EventArgs e)
        {
            ISession session = SessionFactory.OpenSession();
            session.BeginTransaction();
            CurrentSessionContext.Bind(session);
        }

        protected void Application_EndRequest(object sender, EventArgs e)
        {
            ISession session = CurrentSessionContext.Unbind(SessionFactory);

            if (session != null)
            {
                try
                {
                    session.Transaction.Commit();
                }
                catch (Exception)
                {
                    session.Transaction.Rollback();
                }
                finally
                {
                    session.Close();
                    session.Dispose();
                }
            }
        }


        protected override IKernel CreateKernel()
        {
            var modules = new INinjectModule[]
                              {
                                  new ServiceModule(),
                                  new RepoModule()
                              };

            return new StandardKernel(modules);
        }

        private static void BuidSchema(NHibernate.Cfg.Configuration config)
        {
            new NHibernate.Tool.hbm2ddl.SchemaExport(config).Create(false, true);
        }
    }
}

In my RepoModule I have

Bind<IUserRepo>().To<UserRepo>().WithConstructorArgument("session",MvcApplication.SessionFactory.GetCurrentSession());

This will throw a error because ninject will create the kernal before OnApplicationStarted() gets started and before Application_Begin starts to bind it.

So what should I do?

Edit

This is what I found in some tutorial.

  public static ISessionFactory SessionFactory { get; private set; }

        public MvcApplication()
        {
            SessionFactory = CreateSessionFactory();
        }

        private static ISessionFactory CreateSessionFactory()
        {
            return Fluently.Configure()
            .Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("test")))
            .Mappings(m => m.FluentMappings.AddFromAssemblyOf<Demo.Framework.Data.NhibernateMapping.UserMap>())
            .ExposeConfiguration(x => x.SetProperty("current_session_context_class", "web"))
            .ExposeConfiguration(BuidSchema)
            .BuildSessionFactory();
        }

My binding

  Bind<IUserRepo>().To<UserRepo>();
    Bind<ISession>().ToMethod(x => MvcApplication.SessionFactory.GetCurrentSession());

So I first create the session factory on constructor load then I bind it to the Isession instead of passing it in as a parameter.

The only thing that I am not sure with the global aspx is if it will keep calling the constructor up everytime and recreating the SessionFactory what is bad. So I am not sure if I need to check if it exists first.

chobo2
  • 83,322
  • 195
  • 530
  • 832

4 Answers4

2

Your implementation is fine but not a good solution as you do manual control of the session lifecycle. The actual way this should be done is to let Ninject decide when the session is created, opened, closed and disposed.

E.g. imagine actions where you don't need any session. Or a larger project where you have several databases and sessions to split the load. In these situations you don't want all the possible sessions be created for each action as this means an avoidable overhead. You rather want that only those are created that are required for the current action.

To do so several changes are required:

  1. Create a SessionFactoryProvider derived for Provider that retruns a SessionFactory using the code in OnApplicationStarted
  2. Create a binding for SessionFactory using the new provider and put it in SingletonScope
  3. Create a SessionProvider derived from Provider that gets the SessionFactory injected in the constructor and retuns a new session using GetCurrentSession of the factory.
  4. Create a binding for ISession to the above provider with activation and deactivation actions that open, transmit, rollback, and close the session (basiclly the code from Application_BeginRequest, EndRequest). Decalre the binding as in request scope.
  5. Remove Application_BeginRequest, EndRequest.
  6. Bind the repo using Bind<IUserRepo>().To<UserRepo>();
Remo Gloor
  • 32,665
  • 4
  • 68
  • 98
  • I see what you mean. Do you have any tutorials on how to do these? I am still new to nhibernate and ninject. It took me a couple days to figure out how to get where I am now and not sure where to begin with making a SessionFactoryProvider and the rest of the steps. Also how muhc generics would these solutions use(I am trying to avoid them right now as I got enough on my plate to learn and I hate to see solutions right now where the entire file seems to just use generics) – chobo2 Jan 17 '11 at 19:48
  • Well I guess until someone can show me a tutorial (preferably with a source code that I can download). I am going to keep it as I have as I just can't figure out how to make the changes you recommended. – chobo2 Jan 20 '11 at 00:18
2

I recently blogged about using nhibernate in an asp.net mvc application with a repository pattern. This project provides an example of using nhibernate & ninject. Here are a few links:

http://blog.bobcravens.com/2010/07/using-nhibernate-in-asp-net-mvc/

http://blog.bobcravens.com/2010/06/the-repository-pattern-with-linq-to-fluent-nhibernate-and-mysql/

http://blog.bobcravens.com/2010/09/the-repository-pattern-part-2/

http://blog.bobcravens.com/2010/11/using-ninject-to-manage-critical-resources/

I think that we have a similar architecture. Take a look at the posts and let me know if you have any questions.

BTW, you can download this project at http://gpsnerd.codeplex.com

Bob

rcravens
  • 8,320
  • 2
  • 33
  • 26
  • Well I come up with just recently. I think this pretty much covers what Remo was saying I should do. I am not sure if it does step 4 though. http://stackoverflow.com/questions/4771564/my-transaction-is-closed-by-the-time-it-gets-to-my-repo-what-am-i-doing-wrong – chobo2 Jan 23 '11 at 04:45
  • Bob. Please do not refer to "Using Ninject To Manage Critical Resources" anymore as it's the standard behavior of Ninject now. – Remo Gloor Jan 24 '11 at 09:27
  • @remo - You are probably right. I am never certain what version everyone is using. The article mentions the latest version includes this patch. I will update the article with a more prominent notice. Thanks again for all your work on ninject. – rcravens Jan 24 '11 at 13:32
1

Wrap the SessionFactory initialization code in a singleton, that will initialize and configure the sessionfactory once when you access the "Instance" property on it. Use this in BeginRequest instead of current code.

Felice Pollano
  • 32,832
  • 9
  • 75
  • 115
  • Can you please show me how to do this? I am not sure how to make a singeton and then use the instance property. – chobo2 Jan 16 '11 at 17:57
  • well I found this here on SO:http://stackoverflow.com/questions/310691/nhibernate-good-complete-working-helper-class-for-managing-sessionfactory-sessi – Felice Pollano Jan 16 '11 at 18:03
  • I will check it out. I came up with this so I am not sure if what your suggesting is better(see edit). – chobo2 Jan 16 '11 at 19:03
  • As Diego told you, since you are use ( properly ) contextual sessions, injecting the session is not necessary. – Felice Pollano Jan 16 '11 at 19:14
0

You're using a current session context, you don't have to inject the session!

Inject the SessionFactory instead, then use GetCurrentSession() to obtain an ISession.

After that change, you can use Felice's solution.

Diego Mijelshon
  • 52,548
  • 16
  • 116
  • 154
  • I don't get it. Then won't I have to always go GetCurrentSession() in all my repos? – chobo2 Jan 16 '11 at 19:26
  • Yes. If that's not what you want, why bother with session contexts at all? Also, an additional benefit is that you could give them a `Singleton` lifestyle in your IoC. – Diego Mijelshon Jan 16 '11 at 20:43