NeoSketo NeoSketo - 3 months ago 9
C# Question

Session is closed Object name: 'ISession'. at NHibernate.Impl.AbstractSessionImpl.ErrorIfClosed() - How to stop the session from closing prematurely

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.QueryableBase
1.GetEnumerator() +193
System.Collections.Generic.List
1..ctor(IEnumerable
1 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, IDictionary
2 parameters) +603

System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext
controllerContext, ActionDescriptor actionDescriptor, IDictionary
2
parameters) +93

System.Web.Mvc.Async.ActionInvocation.InvokeSynchronousActionMethod()
+97 System.Web.Mvc.Async.AsyncControllerActionInvoker.b__39(IAsyncResult
asyncResult, ActionInvocation innerInvokeState) +53

System.Web.Mvc.Async.WrappedAsyncResult
2.CallEndDelegate(IAsyncResult
asyncResult) +137

System.Web.Mvc.Async.WrappedAsyncResultBase
1.End() +187

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.WrappedAsyncResult
1.CallEndDelegate(IAsyncResult
asyncResult) +79

System.Web.Mvc.Async.WrappedAsyncResultBase
1.End() +187

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.WrappedAsyncResult
1.CallEndDelegate(IAsyncResult
asyncResult) +75

System.Web.Mvc.Async.WrappedAsyncResultBase
1.End() +176

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.WrappedAsyncVoid
1.CallEndDelegate(IAsyncResult
asyncResult) +135

System.Web.Mvc.Async.WrappedAsyncResultBase
1.End() +176

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.WrappedAsyncVoid
1.CallEndDelegate(IAsyncResult
asyncResult) +98

System.Web.Mvc.Async.WrappedAsyncResultBase
1.End() +176

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.WrappedAsyncVoid
1.CallEndDelegate(IAsyncResult
asyncResult) +135

System.Web.Mvc.Async.WrappedAsyncResultBase
1.End() +176

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

Answer

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:

 Bind<IContentService>().To<ContentService>().InRequestScope();
        Bind<ISession>()
            .ToMethod(
                context =>
                    context.Kernel.Get<IMasterSessionSource>()
                        .ExposeConfiguration()
                        .BuildSessionFactory()
                        .OpenSession()
            )
            .WhenInjectedInto<IContentService>()
            .InRequestScope(); 

Here is where i am calling the same session in ContentService

 public class ContentService : IContentService
    {
        private readonly ISession _session;

        public ContentService(ISession session)
        {
            _session = session;
        }

        public IQueryable<Question> Questions
        {
            get { return _session.Query<Question>(); }
        }
    }

Here is where the problem is. I am calling the SAME session in another service that is being used elsewhere

public class DetailsService : IDetailsService
    {
        private readonly IContentService _contentService; //BAD


        public GeneralService(IContentService contentService)
        {
            _contentService = contentService; //BAD
        }

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....

 Bind<IDetailsService>()
                .To<DetailsService>()
                .InRequestScope();

            Bind<ISession>()
                .ToMethod(
                    context =>
                    {
                        var lockObject = new object();

                        lock (lockObject)
                        {
                            return context.Kernel.Get<IMasterSessionSource>()
                                .ExposeConfiguration()
                                .BuildSessionFactory()
                                .OpenSession();
                        }
                    }
                )
                .WhenInjectedInto<IDetailsService>()
                .InRequestScope();

And instead of calling _contentService in that service i added the session to its constrictor

    private readonly ISession Session;

    public DetailsService(ISession session)
    {
        Session = session;
    }

then just ran queries directly using Session.Query();

no more Session is closed errors, no more DataReader Errors, and finally a working product.

Comments