I am using NHibernate in an MVC C# application with MySQL. I am trying to have multiple users access the session. I have been using .InRequestScope()
on my session but i am still getting:
System.ObjectDisposedException: Session is closed! Object name: 'ISession'. at NHibernate.Impl.AbstractSessionImpl.ErrorIfClosed() *
...or DataReader errors when i have my colleagues all navigate to the same page that accesses a Service at the same time.
My IMasterSessionSource injection
Bind<IMasterSessionSource>().To<GeneralMasterSessionSource()
.InRequestScope();
My IContentService is where my mappings are getting serviced
//ContentService Bingings
Bind<IContentService>().To<ContentService>().InRequestScope();
Bind<ISession>()
.ToMethod(
context =>
context.Kernel.Get<IMasterSessionSource>()
.ExposeConfiguration()
.BuildSessionFactory()
.OpenSession()
)
.WhenInjectedInto<IContentService>()
.InRequestScope();
ContentService
public interface IContentService
{
IQueryable<Question> Questions{ get; }
}
public class ContentService : IContentService
{
private readonly ISession _session;
public ContentService(ISession session)
{
_session = session;
}
public IQueryable<Question> Questions
{
get { return _session.Query<Question>(); }
}
}
DetailsService
public interface IDetailsService
{
IEnumerable<Question> PullQuestions();
}
public class DetailsService : IDetailsService
{
private readonly IContentService _contentService;
public GeneralService(IContentService contentService)
{
_contentService = contentService;
}
public IEnumerable<Question> PullQuestions()
{
var result = _contentService.Questions;
return result;
}
}
CONTROLLER
public class Test: Controller
{
private readonly IContentService _contentService;
private readonly IGeneralService _generalService;
public CollegeController(IContentService contentService, IDetailsService detailsService)
{
_contentService = contentService;
_detailsService = detailsService;
}
public ActionResult Index()
{
{
var model = new HomePageContent
{
Questions = _detailsService.PullQuestions().ToList();
};
}
}
}
MODEL
public class HomePageContent
{
public IEnumerable<Question> Questions { get; set; }
}
VIEW
foreach(var question in Model.Questions){
@Html.Raw(question.Question)
}
So for a single user visiting that page. All works fine. But when mutliple users visist the same page each get the errors:
{"There is already an open DataReader associated with this Connection which must be closed first."} {"There is already an open DataReader associated with this Connection which must be closed first."} {"No current query in data reader"} {"No current query in data reader"} {"There is already an open DataReader associated with this Connection which must be closed first."} {"Session is closed!\r\nObject name: 'ISession'."}
I already added InRequestScope. I even added this implementation: NHibernate, and odd "Session is Closed!" errors
but I am still getting Sessions are closed! errors. I even tried to create a new Kernel.Get if the session was closed, but the problem is that the error sometimes occurs even when the session is open. Please help! I am at wits end with this issue, and I can't seem to find the solution anywhere. I almost think it's impossible for NHibernate to handle more than one session at once.
UPDATE
Maybe there's a way to wait for disposed session before opening new?
Stack Trace
[ObjectDisposedException: Session is closed! Object name: 'ISession'.] NHibernate.Impl.AbstractSessionImpl.ErrorIfClosed() +192
NHibernate.Impl.AbstractSessionImpl.CheckAndUpdateSessionStatus() +55 NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression) +171
NHibernate.Linq.DefaultQueryProvider.PrepareQuery(Expression expression, IQuery& query, NhLinqExpression& nhQuery) +226
NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression) +80 NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression) +74 Remotion.Linq.QueryableBase1.GetEnumerator() +193 System.Collections.Generic.List
1..ctor(IEnumerable1 collection) +432 System.Linq.Enumerable.ToList(IEnumerable
1 source) +70
Gcus.PublicGeneralSite.Data.Core.Service.General.DetailsService.FindItems(String item, String controller) in c:\Users\wd\Desktop\master\Gcus.PublicGeneralSite.Data.Core\Service\General\DetailsService.cs:724 Gcus.Com.Web.Controllers.CoursesController.Details(String category, String item) in c:\Users\wd\Desktop\master\Gcus.Com.Web\Controllers\CoursesController.cs:213 lambda_method(Closure , ControllerBase , Object[] ) +366
System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +87
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary2 parameters) +603
2 parameters) +93
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary
System.Web.Mvc.Async.ActionInvocation.InvokeSynchronousActionMethod() +97 System.Web.Mvc.Async.AsyncControllerActionInvoker.b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState) +53
System.Web.Mvc.Async.WrappedAsyncResult2.CallEndDelegate(IAsyncResult asyncResult) +137
1.End() +187
System.Web.Mvc.Async.WrappedAsyncResultBase
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +136
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) +76
System.Web.Mvc.Async.AsyncInvocationWithFilters.b__3d() +164 System.Web.Mvc.Async.<>c__DisplayClass46.b__3f() +549 System.Web.Mvc.Async.<>c__DisplayClass33.b__32(IAsyncResult asyncResult) +75
System.Web.Mvc.Async.WrappedAsyncResult1.CallEndDelegate(IAsyncResult asyncResult) +79
1.End() +187
System.Web.Mvc.Async.WrappedAsyncResultBase
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +136
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult) +76
System.Web.Mvc.Async.<>c__DisplayClass2b.b__1c() +114 System.Web.Mvc.Async.<>c__DisplayClass21.b__1e(IAsyncResult asyncResult) +306
System.Web.Mvc.Async.WrappedAsyncResult1.CallEndDelegate(IAsyncResult asyncResult) +75
1.End() +176
System.Web.Mvc.Async.WrappedAsyncResultBase
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +72
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +60
System.Web.Mvc.Controller.b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState) +70
System.Web.Mvc.Async.WrappedAsyncVoid1.CallEndDelegate(IAsyncResult asyncResult) +135
1.End() +176
System.Web.Mvc.Async.WrappedAsyncResultBase
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +72
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +51
System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +66 System.Web.Mvc.Controller.b__15(IAsyncResult asyncResult, Controller controller) +60
System.Web.Mvc.Async.WrappedAsyncVoid1.CallEndDelegate(IAsyncResult asyncResult) +98
1.End() +176
System.Web.Mvc.Async.WrappedAsyncResultBase
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +72
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +51 System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +60
System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +60
System.Web.Mvc.MvcHandler.b__5(IAsyncResult asyncResult, ProcessRequestState innerState) +70
System.Web.Mvc.Async.WrappedAsyncVoid1.CallEndDelegate(IAsyncResult asyncResult) +135
1.End() +176
System.Web.Mvc.Async.WrappedAsyncResultBase
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +72
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +51
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +60 System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +59
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +399 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +137
I finally figured it out. Much appreciation to @Oskar Berggren for at least being avid on understanding my dilemma.
The problem was that I, in fact, was sharing one session all along.
here is where i am binding an open session to ContentService:
Here is where i am calling the same session in ContentService
Here is where the problem is. I am calling the SAME session in another service that is being used elsewhere
This is not thread safe, because that one open session is getting reused. Each service should have its own session.
so i created binding for DetailService with its own session like so....
And instead of calling _contentService in that service i added the session to its constrictor
then just ran queries directly using Session.Query();
no more Session is closed errors, no more DataReader Errors, and finally a working product.
I'm unfamiliar with ninject, which I suspect is involved in the problem here.
If you cannot figure out how to make that handle the sessions properly, you may have a look at NHibernate's own handling of contextual sessions: http://nhibernate.info/doc/nhibernate-reference/architecture.html#architecture-current-session