I have a c# library for my web application where I am using nhibernate.
The web application has the hibernate.cfg.xml file where I set:
current_session_context_class = web
I am using a nhibernateHelper class and a httpmodule to open and close the session on a per request basis.
I now need to use this library in a console application, what should I set the current_session_context_class value to be now?
There is a "thread" option that you can use. That will bind the current session to the thread.
For more on session management in desktop applications:
What is your session management strategy for NHibernate in desktop applications?
Ayendes MSDN article on NHibernate and desktop applications:
http://msdn.microsoft.com/en-us/magazine/ee819139.aspx
I've used nHibernate for both web and console apps, but never use this particular config setting.
I did some google-ing and found this:
Contextual Sessions
Excerpts:
Out-of-the-box, NHibernate 2.0.0 comes
with several implementations of this
interface:
NHibernate.Context.ManagedWebSessionContext
-current sessions are tracked by HttpContext. However, you are
responsible to bind and unbind an
ISession instance with static methods
on this class, it never opens,
flushes, or closes an ISession itself.
NHibernate.Context.CallSessionContext
-current sessions are tracked by CallContext. You are responsible to
bind and unbind an ISession instance
with static methods of class
CurrentSessionContext .
NHibernate.Context.ThreadStaticSessionContext
-current session is stored in a thread-static variable. This context
only supports one session factory. You
are responsible to bind and unbind an
ISession instance with static methods
of class CurrentSessionContext.
NHibernate.Context.WebSessionContext - analogous to ManagedWebSessionContext above, stores
the current session in HttpContext.
You are responsible to bind and unbind
an ISession instance with static
methods of class
CurrentSessionContext.
.....
...however, there are corresponding
short names: "managed_web", "call",
"thread_static", and "web",
respectively.
Related
I have some legacy code that used to open its own Sqlconnection. And I would now like to use the SqlConnection Nhibernate creates.
But I'd rather avoid to change the code a lot (DI, adding loads of settings, ...), so, Is there a simple (convienent) way to get the current Nhibernate session?
No. What is current NHibernate session anyway?
In a web application, each http request must work with its specific NHibernate session(s).
In a desktop application, each screen will probably use one session for each of their actions.
The NHibernate session is not supposed to be used as a singleton.
You should probably use your session factory to open a new NHibernate session in your legacy code then use its CreateSQLQuery method. Your session factory should usually have a singleton lifetime.
If you bound your NHibernate sessions to some context meaningful for your application (such as the HttpContext, CallContext), you may instead get it from there. Beware of cases which may cause contexts losses (async/await configured for not restoring context, asp.net thread agility (do not cause HttpContext losses but CallContext losses), ...).
Is someone able to explain NHibernate's CallSessionContext, and contrast it to ThreadStaticSessionContext.
The best explaination I have been able to find, has been from the NHibernate documentation :
NHibernate.Context.CallSessionContext- current sessions are tracked by CallContext. You are responsible to
bind and unbind an ISession instance
with static methods of class
CurrentSessionContext.
NHibernate.Context.ThreadStaticSessionContext - current session is stored in a thread-static variable. This context
only supports one session factory. You
are responsible to bind and unbind an
ISession instance with static methods
of class CurrentSessionContext.
I am familiar with the WebSessionContext, as my usual use of NHibernate is in web applications. This time I am building a WCF service, to be hosted in IIS, and am trying to determine which implementation of ICurrentSessionContext is preferable.
I would like to know the implications of choosing one vs the other, both in this particular case (WCF service), and in general for future reference.
NHibernate 3 has a WCF-specific implementation, WcfOperationSessionContext
I am using Wcf in Sharp Architecture. I have configured my project following northwind sample using WcfSessionStorage etc. I have a method in the wcf service that gets a list of business object using Repository<>.GetAll(). I am testing the service method using WcfTestClient. When the method is called the very first time, everything works fine. However on the subsequent call, I get the following exception on the Repository<>.GetAll() method
[System.ObjectDisposedException]
Session is closed!
Object name: 'ISession'
It seems like the NHibernate session gets disposed after each call. I have got around this problem by decorating my service with the following attribute
[ServiceBehavior( InstanceContextMode = InstanceContextMode.PerCall )]
public class WcfService : IWcfService
{
}
However this means, an instance of the service will be created on each call that in turn will create a new nhibernate session etc. In my scenario there is no need of creating a new service instance per call and I think its an expensive process and not the right solution. I would like to know what is the best practice in my scenario and how to get this thing work with creating a new service instace per call.
Thanks
Nabeel
The easiest way is to create a new instance every time and it's not an expensive process, because creating a new object in .NET is like 0.00000000000000001 second (I read that on Ayande's blog or somewhere).
I use Autofac DI in my projects and I usually make ISession as container scoped (one per request). And then every class that uses (directly or indirectly) ISession has to be container scoped or lower (factory scoped == every class usage get's a new instance). If a class that uses ISession is higer scoped (session scoped == singleton) you'll run into problems that you currently have.
If your service is singleton service:
At first run the service is created, this service uses ISession, which should be container scoped, and it is on the first run.
The next request to service (service is now created) has still a reference to created ISession (which was closed on previous end request), so now it's closed.
I don't recomend using the same ISession that you'll open/close (it's not recomended in the NHibernate documentation), just use container scoped (I do and I don't have any performance issues), or you should create ISession manually in every method in your service like:
using(ISession s = ISessionFactory.OpenSession())
using(ITransaction t = .....)
....
But that isn't nice at all...
Please take a look at my answer to my own similar question: WCF/S#arpArch: underlying ISession is closed after the first call within a request.
#dmonlord is right that the creation of additional session instances within the same request is very cheap in this case.
Does anyone have any tips or best practices regarding how Autofac can help manage the NHibernate ISession Instance (in the case of an ASP.NET MVC application)?
I'm not overly familiar with how NHibernate sessions should be handled. That said, Autofac have excellent instance lifetime handling (scoping and deterministic disposal). Some related resources are this article and this question. Since you're in ASP.Net MVC land make sure you also look into the MVC integration stuff.
To illustrate the point, here's a quick sample on how you can use Autofac factory delegates and the Owned generic to get full control over instance lifetime:
public class SomeController
{
private readonly Func<Owned<ISession>> _sessionFactory;
public SomeController(Func<Owned<ISession>> sessionFactory)
{
_sessionFactory = sessionFactory;
}
public void DoSomeWork()
{
using (var session = _sessionFactory())
{
var transaction = session.Value.BeginTransaction();
....
}
}
}
The container setup to get this to work is quite simple. Notice that we don't have to do anything to get the Func<> and Owned<> types, these are made available automatically by Autofac:
builder.Register(c => cfg.BuildSessionFactory())
.As<ISessionFactory>()
.SingleInstance();
builder.Register(c => c.Resolve<ISessionFactory>().OpenSession());
Update: my reasoning here is that, according to this NHibernate tutorial, the lifetime of the session instance should be that of the "unit of work". Thus we need some way of controlling both when the session instance is created and when the session is disposed.
With Autofac we get this control by requesting a Func<> instead of the type directly. Not using Func<> would require that the session instance be created upfront before the controller instance is created.
Next, the default in Autofac is that instances have the lifetime of their container. Since we know that we need the power to dispose this instance as soon as the unit of work is done, we request an Owned instance. Disposing the owned instance will in this case immediately dispose the underlying session.
Edit: Sounds like Autofac and probably other containers can scope the lifetime correctly. If that's the case, go for it.
It isn't a good idea to use your IoC container to manage sessions directly. The lifetime of your session should correspond to your unit of work (transaction boundary). In the case of a web application, that should almost certainly be the lifetime of a web request.
The most common way to achieve this is with an HttpModule that both creates your session and starts your transaction when a request begins, then commits when the request has finished. I would have the HttpModule register the session in the HttpContext.Items collection.
In your IoC container, you could register something like HttpContextSessionLocator against ISessionLocator.
I should mention that your generic error handling should locate the current session and roll back the transaction automatically, or you could end up committing half a unit of work.
What's the simplest way to preserve a NHibernate ISessionFactory for web pages and web services?
I'll get into the Rhino Commons and Windsor this and that later. I'm looking for the basic concept.
Is this correct?
I've been trying to find guidance on how to deal with the ISessionFactory as simply as possible. I'm also looking for a solution that would work in both web pages and web services. The examples that I've seen deal with web pages and never touch the subject of web services. They start by building a Httpmodule that creates the ISessionFactory and store it in a static variable (e.g., Jeffery Palermo's HybridSessionBuilder (jeffreypalermo.com/blog/use-this-nhibernate-wrapper-to-keep-your-repository-classes-simple/) or in the Summer of NHibernate's (www.summerofnhibernate.com see StaticSessionManager in Session 13). I've also noticed that despite the fact that ISessionFactory implements IDisposable nobody seems to be disposing of it. I guess they just let the garbage collector dispose of it when the web application ends, which would occur if IIS is recycled or the web site becomes idle.
If all this is true, the simplest thing would be to create some class that has a static variable that is used to store the ISessionFactory. This class would be instantiated and used by web pages and web services. Each time the class is instantiated, I would check to make sure that the static ISessionFactory variable is not null. If it is null, I recreate it. Thus, I keep the ISessionFactory alive by having something, either a web page or web service, within the web application create an instance of the class. The fact that the ISessionFactory is in a static variable means that it is shared by every instance of the class. Since the session factory is thread safe, this is ok. As long as I don't share ISessions, I'm golden. When nobody has an instance of this common class, the static variable is no longer referenced and garbage collection will destroy of the ISessionFactory .
Is this the basic principle behind keeping the ISessionFactory alive?
I think you have it mostly figured out.
The reason no one is disposing of the session factory is that, in general, you really don't want to. Building the session factory is an extremely expensive operation that can take many seconds, so you want to hold onto it for as long as possible. The .NET runtime will actually create a pool of HttpApplications and may create/dispose of them at will. So if you can store the session factory outside of the application, at the AppDomain scope, that is preferable since the factory will endure until the domain is recycled. Declaring the session factory as static will achieve this so that's why that is done; see the MSDN docs on static classes:
A static constructor is only called
one time, and a static class remains
in memory for the lifetime of the
application domain in which your
program resides.
So, if you make the session factory container static and never explicitly dispose of it, it will remain in memory until the AppDomain is recycled, maximizing the utility of that factory instance and the performance of your application.