I'm having problem trying to get a correctly handled lifetime of my unit of work ( think it's an issue with my UoW anyway) for an MVC app using NHibernate. There is a chance for multithreading so it also needs to account for that. I decided to try and let NHibernate manage the connection instead of doing it in my Dependency Injector (StructureMap) but now I'm hitting problems with the Connection Pool limit being reached.
I've simplified some of this for posting the code but hopefully it will help to see what I'm missing...
NHibernate Config
var cfg = new Configuration()
.DataBaseIntegration(x =>
{
x.ConnectionStringName = "ApplicationConnectionStringName";
x.Dialect<CustomMsSql2008Dialect>(); //Inherits from MsSql2008GeographyDialect
x.IsolationLevel = IsolationLevel.RepeatableRead;
x.BatchSize = 100;
})
.CurrentSessionContext<WebSessionContext>()
.Cache(c =>
{
c.Provider<SysCacheProvider>();
c.UseQueryCache = true;
});
Unit Of Work
public class NHibernateUnitOfWork : INHibernateUnitOfWork
{
private ITransaction transaction;
private bool isDisposed;
private readonly ISessionFactory source;
public NHibernateUnitOfWork(ISessionFactory source)
{
this.source = source;
VerifyIsNotDisposed();
if (CurrentSessionContext.HasBind(source))
{
CurrentSession = source.GetCurrentSession();
this.transaction = CurrentSession.Transaction;
}
else
{
CurrentSession = this.source.OpenSession();
CurrentSessionContext.Bind(CurrentSession);
BeginNewTransaction();
}
}
public ISession CurrentSession { get; private set; }
public void Commit()
{
VerifyIsNotDisposed();
this.transaction.Commit();
BeginNewTransaction();
}
private void BeginNewTransaction()
{
if (this.transaction != null)
{
this.transaction.Dispose();
}
this.transaction = CurrentSession.BeginTransaction();
}
public void Rollback()
{
VerifyIsNotDisposed();
this.transaction.Rollback();
BeginNewTransaction();
}
private void VerifyIsNotDisposed()
{
if (this.isDisposed) throw new ObjectDisposedException(GetType().Name);
}
public void Dispose()
{
if (this.isDisposed) return;
this.transaction.Dispose();
CurrentSessionContext.Unbind(this.source);
CurrentSession.Dispose();
this.isDisposed = true;
}
}
request Begin and End handlers via StructureMap
public class StructureMapScopeModule : IHttpModule {
public void Dispose() {
}
public void Init(HttpApplication context) {
context.BeginRequest += (sender, e) =>
{
StructuremapMvc.StructureMapDependencyScope.CreateChildContainer();
var unitOfWork = StructuremapMvc.StructureMapDependencyScope.Container.GetInstance<IUnitOfWork>();
};
context.EndRequest += (sender, e) => {
var unitOfWork = StructuremapMvc.StructureMapDependencyScope.Container.GetInstance<IUnitOfWork>();
unitOfWork.Commit();
HttpContextLifecycle.DisposeAndClearAll();
StructuremapMvc.StructureMapDependencyScope.DisposeChildContainer();
};
}
}
Running a query to get the connection count right now gives almost 125 connections.