Introduction
We noted in a
previous part the
ISession object from NHibernate is our
Unit of Work. What that means in practical terms, is that in the context of a web request we want to have just one. Also every web request will have a different instance. Then when the web request ends we will dispose of the session thus flushing all the changes to the database.
Lifestyles
In Windsor the
sharing of objects is called
lifestyle. If you recall, when we were registering controllers we specified that their lifestyle is Transient. That means that the instance is never shared, and is not bound to any context. Every time we request a transient component we get a new instance. Also transient components that were explicitly
Resolved have to be explicitly
Released, since Windsor has no idea when their lifetime should end.
In a previous part when we registered
ISessionFactory and
ISession we didn't specify any lifestyle. If the lifestyle is not defined, the default of singleton will be used. Singleton means that there is going to be just a single instance in the entire container, for as long as the container is alive (which means - entire lifetime of the application, since that's how long we use the container).
For singleton components an instance is created upon the first request for the component, and then reused for every subsequent request. It is destroyed only when the container gets
Disposed.
This is exactly what we want for
ISessionFactory. That's one of the first things you learn about NHibernate -
ISessionFactory is big, heavyweight, thread-safe, and you only should ever have one per database.
That's great - all fine there.
That's however as far as we can get for what we want from
ISession. When it's a singleton our changes will never be flushed, hence they'll get lost, instead of getting persisted at the end of request. Also
ISession is not thread safe so we'll be exposed to multiple bugs if multiple requests try to access it. Also as we get more and more requests, its internal cache will grow and grow, getting slower with every request until we run out of memory. To fix this we have to change its lifestyle to
PerWebRequest.
The PerWebRequest lifestyle
To change the
ISession lifestyle to be per web request, we need to specify that in the registration. So we need to change it to the following:
Kernel.Register(
Component.For<ISession>()
.UsingFactoryMethod(k => k.Resolve<ISessionFactory>().OpenSession())
.LifestylePerWebRequest()
);
Now Windsor will call our factory method once in every web request where it needs an
ISession instance and then reuse this instance in the scope of that web request. When a new web request comes along, the factory method will be called again, asking
ISessionFactory to
OpenSession for that new web request, and so on.
Releasing components
Some contexts, like web request have a well defined ends that Windsor can detect. Therefore Windsor knows when to release the per web request objects and it will do it without requiring any action from you. That’s not the case for all lifestyles however. This brings us to the
Release method.
A rather detailed discussion about releasing components can be found in
this blog post. It is highly recommended that you read it
Importance of lifestyles
Getting lifestyles
right when using Windsor (or any other container) is one of the most important aspects of working with a container, and one that has has big impact on your application. Pay attention to what lifestyle you assign to your components. There's no hard and fast rule on which one you should chose so think how the components will be used.
Summary
One of the most important concepts regarding Inversion of Control containers is the lifetime or lifestyle of the components that are registered within them, which this section discussed. Ensure you understand the concepts, because they are fundamental to using Windsor. Another important part of any IoC container is managing dependencies, which you can read about in
Part Eight - Satisfying Dependencies.