Yes. this is an issue related to how i ask Castle Windsor to resolve my ISession, but i have reread the code like 5 times, and can’t still figure out what is wrong with it.
Below is my rather standard NHibernate facility, except for the last 2 components which I have registered:
public class NHibernateFacility : AbstractFacility
{
protected override void Init()
{
var config = new Configuration().Configure();
Kernel.Register(
Component.For<ISessionFactory>()
.UsingFactoryMethod((kernel, context) => config.BuildSessionFactory()),
Component.For<ISession>()
.UsingFactoryMethod((kernel, context) => kernel.Resolve<ISessionFactory>().OpenSession())
.LifestylePerWebRequest(),
Component.For<IStatelessSession>()
.UsingFactoryMethod((kernel, context) => kernel.Resolve<ISessionFactory>().OpenStatelessSession())
.LifestylePerWebRequest(),
Component.For<StatefulSessionWrapper>().LifestylePerWebRequest(),
Component.For<StatelessSessionWrapper>().LifestylePerWebRequest()
);
}
}
The StatefulSessionWrapper/StatelessSessionWrapper serve as a … wrapper for ISession/IStateless session like this:
public class StatefulSessionWrapper : ISessionWrapper
{
public StatefulSessionWrapper(ISession session)
{
this.Session = session;
}
private readonly ISession Session;
#region ISessionWrapper Members
public ITransaction BeginTransaction()
{
return Session.BeginTransaction();
}
public ITransaction BeginTransaction(IsolationLevel isolationLevel)
{
return Session.BeginTransaction(isolationLevel);
}
public ITransaction Transaction { get { return Session.Transaction; } }
public bool IsConnected
{
get { return Session.IsConnected; }
}
public bool IsOpen
{
get { return Session.IsOpen; }
}
#endregion
}
This way, I can use a single action filter, which only handles the transaction part of the NHibernate Session:
public class NHibernateActionFilter<T> : Castle.MonoRail.Framework.IFilter where T:ISessionWrapper
{
private readonly T NHibernateSession;
public NHibernateActionFilter(T session)
{
if (session != null)
NHibernateSession = session;
else
throw new NullReferenceException("Session is null");
}
#region IFilter Members
public bool Perform(ExecuteWhen exec, IEngineContext context, IController controller, IControllerContext controllerContext)
{
if (exec == ExecuteWhen.BeforeAction)
{
NHibernateSession.BeginTransaction();
return true;
}
if (exec == ExecuteWhen.AfterAction)
{
if (NHibernateSession.Transaction == null || !NHibernateSession.Transaction.IsActive)
return false;
if (context.LastException != null)
{
NHibernateSession.Transaction.Rollback();
return false;
}
else
{
NHibernateSession.Transaction.Commit();
return true;
}
}
return false;
}
#endregion
}
And use it simply as this:
[Filter(ExecuteWhen.Always, typeof(NHibernateActionFilter<StatefulSessionWrapper>), ExecutionOrder = 1)]
[Filter(ExecuteWhen.BeforeAction, typeof(AuthenticationFilter), ExecutionOrder = 2)]
[Layout("Default"), Rescue("Default")]
public abstract class NHibernateController : SmartDispatcherController
{
public NHibernateController(ISession session)
{
this.NHibernateSession = session;
}
protected readonly ISession NHibernateSession;
..................
The only problem?
This is the rescue page. See the exception details below
ObjectDisposedException
Message: Session is closed! Object name: ‘ISession’.
StackTrace: at NHibernate.Impl.AbstractSessionImpl.ErrorIfClosed()
in p:\nhibernate-core\src\NHibernate\Impl\AbstractSessionImpl.cs:line
207 at
NHibernate.Impl.AbstractSessionImpl.CheckAndUpdateSessionStatus() in
p:\nhibernate-core\src\NHibernate\Impl\AbstractSessionImpl.cs:line 199
at NHibernate.Impl.SessionImpl.BeginTransaction() in
p:\nhibernate-core\src\NHibernate\Impl\SessionImpl.cs:line 1456 at
ADAutoTotal.Monorail.StatefulSessionWrapper.BeginTransaction() in
C:\Dropbox\Projects\ADAutoTotal\ADAutoTotal.Monorail\StatefulSessionWrapper.cs:line
23 at
ADAutoTotal.Monorail.NHibernateActionFilter`1.Perform(ExecuteWhen
exec, IEngineContext context, IController controller,
IControllerContext controllerContext) in
C:\Dropbox\Projects\ADAutoTotal\ADAutoTotal.Monorail\NHibernateActionFilter.cs:line
31 at
Castle.MonoRail.Framework.Controller.ProcessFilter(ExecuteWhen when,
FilterDescriptor desc) in
C:\Dropbox\Projects\Monorail\castleproject-MonoRail-98c93ac\castleproject-MonoRail-98c93ac\MR2\src\Castle.MonoRail.Framework\Controller.cs:line 2099 at
Castle.MonoRail.Framework.Controller.ProcessFilters(IExecutableAction
action, ExecuteWhen when) in
C:\Dropbox\Projects\Monorail\castleproject-MonoRail-98c93ac\castleproject-MonoRail-98c93ac\MR2\src\Castle.MonoRail.Framework\Controller.cs:line 2054 at
Castle.MonoRail.Framework.Controller.RunBeforeActionFilters(IExecutableAction
action, Boolean& cancel) in
C:\Dropbox\Projects\Monorail\castleproject-MonoRail-98c93ac\castleproject-MonoRail-98c93ac\MR2\src\Castle.MonoRail.Framework\Controller.cs:line 1953 at
Castle.MonoRail.Framework.Controller.RunActionAndRenderView() in
C:\Dropbox\Projects\Monorail\castleproject-MonoRail-98c93ac\castleproject-MonoRail-98c93ac\MR2\src\Castle.MonoRail.Framework\Controller.cs:line 1622
So, it’s obvious that the NHibernateActionFilter gets a closed session. But according to me, it shouldn’t. Halp.
Well, it turns out that i forgot to add to my action filter their proper lifestyles, therefore letting Windsor making them singleton…