Luke Smith Write today, wrong tomorrow

aspnet RoleProvider woes with StructureMap and NHibernate

I just fixed a bug that has plagued me for the last 2 nights. NHibernate was throwing completely random exceptions, rolling back transactions with no real consistency other than always happening on requests made after the application had started and almost always within my RoleProvider. I couldn’t figure out what the heck was happening.

Some of the exceptions:

“Could not synchronize database state with session”

“Rollback failed - System.InvalidOperationException: This SqlTransaction has completed; it is no longer usable.”

“Commit failed - System.NullReferenceException: Object reference not set to an instance of an object.”

“Could not synchronize database state with session - NHibernate.ADOException: There was a problem converting an IDataReader to NDataReader”

“System.ObjectDisposedException: Session was disposed of or closed Object name: 'ISession'.”

I’m using StructureMap to Dependency Inject an NHibernate.ISession into my NHibernateRepositoryBase class, and inject the repository to my Service class. Because you can’t dependency inject into a AspNet RoleProvider I’m using the StructureMap ObjectFactory.GetInstance<T> to get me an instance of my IUserService. I was placing this in the constructor, setting a private field that was then accessed in all the overridden methods I am implementing.

And this was what got me.

The reason that the exceptions would happen on any requests made after the application had started was because AspNet Providers are created once per application and reused throughout the duration of the application. This meant when the instance was created it would have a reference to the NHibernate.ISession for that request, but since the ISession is closed in application_endrequest subsequent requests the RoleProvider was now referencing an ISession that was closed.

My solution was to remove the ObjectFactory.GetInstance<T> field assignments to within each method that needed the service, that way ensuring that the NHibernate.ISession for the current request would be used.

comments powered by Disqus