views:

563

answers:

3

Is there anyway to verify if a Session has been disposed of by NHibernate?

I have a wrapper class on Session that has it's own Finalizer and IDispoable implementation however if the Session gets disposed before I handle it myself in my class I end up receiving an ObjectDisposedException.

I really don't wish to wrap my clean up code with

try {
...
}
catch (ObjectDisposedException) { }

But I'm not really sure of any other way. The Session.IsOpen and Session.IsActive properties do not seem to offer any reliable information for me to acknowledge the session has been disposed of.

For full source you can view it on Assembla.

A: 

I always thought best practice with NHibernate was "session per request" meaning that it should only live inside the 'using' scope.

using(Session session = new Session())
{
}

I'd suggest trying to prevent two people from disposing the session/conversation. If you control the creation of sessions you could wrap it in your own ISession impl that performs it's own IsAlreadyDisposed() check to prevent the exception. Still, considering that effort vs "expected exception" and the original code doesn't look so bad.

I'd also suggest watching out with your finaliser implementation. The "Session.Is().InTransaction()" goes Session->Transaction and the session might be null by the time the finaliser gets round to it. Navigating a managed relationship at finaliser time isn't guaranteed to work.

Quibblesome
The only place I get the exception from is on .Reconnect when the Session has been disposed of by NH already, for some reason when it's disposed it can still have Session.IsOpen = true. That's one of the most absurd things I've seen to have it's Open property remain true even after disposal.
Chris Marisic
I use NH's SessionFactory to create the session I'm not sure how I could have it use a custom session class other than downloading the source code and modifying it. However if I just wanted to do that I'd just make it when Dispose() is called on the session that IsOpen returns false.
Chris Marisic
"Session has been disposed of by NHibernate already"? In what scenario does that occur? It's been a while since I played with NHibernate but I don't remember it ever disposing of a session itself.
Quibblesome
What is your session strategy anyhow? Are you using 1 session throughout the entire app or 1 session per request?
Quibblesome
1 session per HttpSession, I'm using aspect orientated programming to allow me to group multiple actions into a single transaction. Which works out to generally 1 transaction per request which is more efficient than creating a new session every request, it's the successor to the session per request.
Chris Marisic
I have a blog post on this topic: http://dotnetchris.wordpress.com/2009/01/27/conversation-per-business-transaction-using-postsharp-and-ioc/ when I get this exception is during application teardown at the end of my unit tests which is where im trying to resolve this for presently.
Chris Marisic
Have you tried omitting the finaliser? To be frank you shouldn't really use finalisers to "auto" clean up managed code, that's what dispose is for.
Quibblesome
A: 

"That's one of the most absurd things I've seen to have it's Open property remain true even after disposal"

Why would an object you already have disposed contain reliable information about it's state?. You shouldn't try to use a disposed session, i don't know where nhibernate is disposing your session either, are you sure you are not disposing it yourself?.

Fredy Treboux
My goal is to dispose of it myself but it seems atleast during my unit tests it always gets disposed of before my object, if it's not disposed I want to rollback its transaction if it's in one, otherwise explicitly call close then dispose. But the problem is the object gives no way to tell if it was
Chris Marisic
+1  A: 

Ok, just taked a peek at your code. I don't know if this is exactly the issue, but you are calling End() from the conversation dispose method, which in turn tries to reconnect and disposes the session.. if you have eplicitly called End() before this you will get what you get, avoid that call. I think you shouldn't worry about rolling back the transaction before the session dispose as this is implicitly done. Just taken a quick look, but i think i really like your implementation.

Fredy Treboux
You are right that it occurs when I try to reconnect since at the end of my unit tests where i get the disposed exception the session is always isopen = true, isconnected = false. i just don't understand why the isopen property would be true when the underlying connection is disposed
Chris Marisic
Maybe you're right and I just shouldn't care since it always seems like it's getting disposed of anyway, did you check out my blog on the whole business conversation per transaction pattern? http://dotnetchris.wordpress.com/2009/01/27/conversation-per-business-transaction-using-postsharp-and-ioc/
Chris Marisic