-1

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.

Nick Albrecht
  • 16,607
  • 10
  • 66
  • 101
  • 1
    I think the issue is more to do with how to dispose the connection, you should also dispose it in the finalizer.... [link](http://stackoverflow.com/a/18336995/1139099) – harishr Mar 14 '15 at 11:04
  • I was about to post a reply that I have verified that the call to `DisposeAndClearAll()` does cascade down into all items in the container, which would include my `UnitOfWork`, and that would dispose of the `Session`, which would close the connect. Then I thought better, went and tested it again, and found out you're right. Apparently `DisposeAndClearAll()` in StructureMap does NOT propagate through to ChildContainers, and `DisposeChildContainer()` wasn't disposing items within the container either. If you want to quickly stick an answer on this question I'll accept it as answered. – Nick Albrecht Mar 16 '15 at 17:06

1 Answers1

0

Please dispose off all the open connection, that is generally the reason for pool limit reached...

also implementing IDisposable correctly is not as simple as it seems... below is the sample implementation that I am using (copied it from the answers on SO)

using System;

namespace AlgoSys.Common.SharedUtils
{
    public abstract class Disposable : IDisposable
    {
        private bool _disposed;

        // Dispose() calls Dispose(true)
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        // NOTE: Leave out the finalizer altogether if this class doesn't 
        // own unmanaged resources itself, but leave the other methods
        // exactly as they are. 
        ~Disposable()
        {
            // Finalizer calls Dispose(false)
            Dispose(false);
        }

        // The bulk of the clean-up code is implemented in Dispose(bool)
        protected virtual void Dispose(bool disposing)
        {
            if(_disposed) return;

            if (disposing)
            {
                OnDispose();
            }


            _disposed = true;
        }

        protected abstract void OnDispose();
    }
}

great that you tested it before commenting... putting the comment as answer.

harishr
  • 17,807
  • 9
  • 78
  • 125