0
votes

I'm setting up my MVC project so that I resolve my ISession's on a PerWebRequest basis.

Here's what I have so far:

In my Castle Windsor Setup I register my ISession using a factory method:

Component.For<ISession>().UsingFactoryMethod(ctx => MsSql2008SessionFactory.OpenSession()).LifestylePerWebRequest()

In my Global.asax Application_Start() I Bind my ISession to NHibernate's CurrentSessionContext each time a request begins:

BeginRequest += delegate{
            CurrentSessionContext.Bind(
                     MsSql2008SessionFactory.OpenSession());
                       };

EndRequest += delegate{
             var session = MsSql2008SessionFactory
                             .SessionFactory
                               .GetCurrentSession();
              if (session != null)
              {
                session.Dispose();
              }
             CurrentSessionContext
                     .Unbind(MsSql2008SessionFactory
                         .SessionFactory);
        };

The first time I make a request to a page everything works fine. The second time I make a request to a page I get an exception stating:

Session is closed! Object name: 'ISession'.

What am I not doing correctly?

2
You should be using a WindsorInstaller to wire all this upCode Jammr
BeginRequest and EndRequest are not guaranteed to execute on the same thread eitherCode Jammr
As well everything you do with Nhibernate should be wrapped in a transactionCode Jammr
one other thing to note when dealing with CurrentSessionContext. Things get tricky of you don't check to see if it is already bound before unbinding.Code Jammr

2 Answers

2
votes

This is how I do things may work for you. I use Fluent Nhibernate just in case some of the config doesn't jive.

public interface INHibernateSessionFactoryHelper
{
    ISessionFactory CreateSessionFactory();
}


public class NhibernateSessionFactoryHelper
{
    private static readonly string ConnectionString =
        ConfigurationManager.ConnectionStrings["SqlConnectionString"].ToString();

    public static ISessionFactory CreateSessionFactory()
    {
        return Fluently.Configure()
            .ProxyFactoryFactory("NHibernate.Bytecode.DefaultProxyFactoryFactory, NHibernate")
            .Mappings(m => m.FluentMappings.AddFromAssemblyOf<EntityMap>())
            .Database(
                MsSqlConfiguration.MsSql2008.ConnectionString(ConnectionString).AdoNetBatchSize(1000))
            .Cache(
                c =>
                c.ProviderClass<SysCacheProvider>().UseSecondLevelCache().UseQueryCache().UseMinimalPuts())
            .ExposeConfiguration(c => c.SetProperty(Environment.GenerateStatistics, "true")
                                          .SetProperty(Environment.SessionFactoryName, "My Session Factory")
                                          .SetProperty(Environment.CurrentSessionContextClass, "web"))
            .Diagnostics(d => d.Enable().OutputToFile(@"c:\temp\diags.txt"))
            .BuildSessionFactory();
    }
}

Then my Windsor installer looks like this

public class NHibernateInstaller:IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            Component.For<ISessionFactory>().Instance(NhibernateSessionFactoryHelper.CreateSessionFactory()));
        container.Register(Component.For<ISessionManager>().ImplementedBy<SessionManager>().LifestylePerWebRequest());
    }
}

I have omitted the code for the SessionManager I use. Let me know if you would like it

UPDTAE: Here is the code I use for managing sessions and transactions( I found pieces of this scattered about the Internet but it all worked well without too much modification. ISessionManager is wired up per my previous example and injected in to the constuctor of my Services.

public interface ISessionManager : IDisposable
{
    ISession Session { get; set; }
    ISession GetSession();
}

public class SessionManager : ISessionManager
{
    private readonly ISessionFactory _sessionFactory;
    private TransactionScope _scope;
    public SessionManager(ISessionFactory sessionFactory)
    {
        _sessionFactory = sessionFactory;
    }

    #region ISessionManager Members

    public ISession Session { get; set; }

    public ISession GetSession()
    {
        if (Session == null)
        {
            Session = _sessionFactory.OpenSession();
            if (!CurrentSessionContext.HasBind(_sessionFactory))
            {
                _scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions {IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted});
                Session.BeginTransaction(IsolationLevel.ReadCommitted);
                CurrentSessionContext.Bind(Session);
            }
        }

        Session = _sessionFactory.GetCurrentSession();
        Session.FlushMode = FlushMode.Never;
        return Session;
    }


    public void Dispose()
    {
        if (CurrentSessionContext.HasBind(_sessionFactory))
        {
            CurrentSessionContext.Unbind(_sessionFactory);
        }
        try
        {
            Session.Transaction.Commit();
            _scope.Complete();
            _scope.Dispose();
            Session.Flush();
        }
        catch (Exception)
        {
            if (Session.Transaction != null && Session.Transaction.IsActive)
            {
                Session.Transaction.Rollback();
            }
            throw;
        }
        finally
        {
            Session.Close();
            Session.Dispose();
        }
    }

    #endregion
}

Example Constructor:

private readonly ISessionManager _sessionManager;
private readonly ISession _session;
 public UserService(ISessionManager sessionManager)
    {

        _sessionManager = sessionManager;
        _session = sessionManager.GetSession();

     }
2
votes

The answer to this turned out to be quite simple.

The repository that I was injecting my ISession into had a Singleton lifestyle.

This meant that the ISession that had been injected on the first request was also being used for the subsiquent requests (because my repository class was only being created at the start of the application) and was thus already disposed.