会话已关闭对象名称:'ISession'。在 NHibernate.Impl.AbstractSessionImpl.ErrorIfClosed() - 如何阻止会话过早关闭

Posted

技术标签:

【中文标题】会话已关闭对象名称:\'ISession\'。在 NHibernate.Impl.AbstractSessionImpl.ErrorIfClosed() - 如何阻止会话过早关闭【英文标题】:Session is closed Object name: 'ISession'. at NHibernate.Impl.AbstractSessionImpl.ErrorIfClosed() - How to stop the session from closing prematurely会话已关闭对象名称:'ISession'。在 NHibernate.Impl.AbstractSessionImpl.ErrorIfClosed() - 如何阻止会话过早关闭 【发布时间】:2016-11-30 12:30:36 【问题描述】:

我在带有 mysql 的 MVC C# 应用程序中使用 NHibernate。我正在尝试让多个用户访问会话。我一直在使用.InRequestScope() 在我的会话中,但我仍然得到:

System.ObjectDisposedException:会话已关闭!对象名称:'ISession'。在 NHibernate.Impl.AbstractSessionImpl.ErrorIfClosed() *

...或当我让我的同事都导航到同时访问服务的同一页面时出现 DataReader 错误。

我的 IMasterSessionSource 注入

Bind<IMasterSessionSource>().To<GeneralMasterSessionSource()
                            .InRequestScope();

我的 IContentService 是为我的映射提供服务的地方

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

内容服务

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>(); 
        
    

详细信息服务

 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;
        

控制器

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();
                ;
            
        
    

型号

 public class HomePageContent
    
        public IEnumerable<Question> Questions  get; set; 
    

查看

foreach(var question in Model.Questions)
@html.Raw(question.Question)

所以对于访问该页面的单个用户。一切正常。但是当多个用户访问同一个页面时,每个人都会收到错误:

"已经有一个打开的 DataReader 与此 Connection 关联,必须先关闭。" “已经有一个打开的 DataReader 与此 Connection 关联,必须先关闭它。” “数据阅读器中没有当前查询” “数据阅读器中没有当前查询” “已经有一个打开的 DataReader 与此 Connection 关联,必须先关闭它。” "会话已关闭!\r\n对象名称:'ISession'。"

我已经添加了 InRequestScope。我什至添加了这个实现: NHibernate, and odd "Session is Closed!" errors

但我仍然收到会话已关闭!错误。如果会话关闭,我什至尝试创建一个新的 Kernel.Get,但问题是即使会话打开,有时也会发生错误。请帮忙!我对这个问题束手无策,我似乎无法在任何地方找到解决方案。我几乎认为 NHibernate 不可能同时处理多个会话。

更新

也许有办法在打开新会话之前等待已处理的会话?

堆栈跟踪

[ObjectDisposedException:会话已关闭!对象名称:'ISession'。] NHibernate.Impl.AbstractSessionImpl.ErrorIfClosed() +192 NHibernate.Impl.AbstractSessionImpl.CheckAndUpdateSessionStatus() +55 NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression 查询表达式)+171 NHibernate.Linq.DefaultQueryProvider.PrepareQuery(表达式 表达式、IQuery& 查询、NhLinqExpression& nhQuery) +226 NHibernate.Linq.DefaultQueryProvider.Execute(表达式表达式) +80 NHibernate.Linq.DefaultQueryProvider.Execute(表达式表达式) +74 Remotion.Linq.QueryableBase1.GetEnumerator() +193 System.Collections.Generic.List1..ctor(IEnumerable1 collection) +432 System.Linq.Enumerable.ToList(IEnumerable1 源) +70 Gcus.PublicGeneralSite.Data.Core.Service.General.DetailsS​​ervice.FindItems(字符串 项目,字符串控制器)在 c:\Users\wd\Desktop\master\Gcus.PublicGeneralSite.Data.Core\Service\General\DetailsS​​ervice.cs:724 Gcus.Com.Web.Controllers.CoursesController.Details(字符串类别, 字符串项)在 c:\Users\wd\Desktop\master\Gcus.Com.Web\Controllers\CoursesController.cs:213 lambda_method(闭包, ControllerBase, Object[]) +366 System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase 控制器,Object[] 参数)+87 System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext 控制器上下文,IDictionary2 parameters) +603 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary2 参数)+93 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 System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +187 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, 对象标签)+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 System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +187 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, 对象标签)+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 System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +176 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, 对象标签)+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 System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +176 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, 对象标签)+72 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, 对象标签)+51 System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +66 System.Web.Mvc.Controller.b__15(IAsyncResult asyncResult,控制器控制器)+60 System.Web.Mvc.Async.WrappedAsyncVoid1.CallEndDelegate(IAsyncResult asyncResult) +98 System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +176 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, 对象标签)+72 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, 对象标签)+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 System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +176 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, 对象标签)+72 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, 对象标签)+51 System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +60 System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult 结果)+59 System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +399 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +137

【问题讨论】:

NHibernate 对于多个并发会话当然没有问题。事实上,它旨在准确处理这种情况。然而,它不能处理对 single 会话的并发访问。会话不是线程安全的。您似乎确实意识到了这一点,因为您谈到了 InRequestScope() 等,这听起来应该可以解决问题。与 NHibernate 相比,这似乎是 ninject(或您如何使用它)的问题。 也许您没有为 MVC 正确设置 NInject? ***.com/questions/24928070/… 我已正确设置。我正在使用 NInject.MVC5 并将它们注入到正确的控制器中。问题似乎出在同一会话有两个请求时。不知何故,一个人可能不得不等到连接关闭。但我不确定。我简直不敢相信这这么难。 让我重复一遍:NHibernate 旨在处理多个并发线程、会话和连接。确实会发生错误,但这在 NHibernate 中不太可能成为问题。但是,必须遵循的 NHibernate 规则(简单地说)是单个会话实例和从会话加载的任何数据一次只能从 1 个线程使用。 你是在使用 System.Transactions/ambient 事务,还是只使用 session.BeginTransaction()? 【参考方案1】:

我终于明白了。非常感谢@Oskar Berggren 至少热衷于理解我的困境。

问题在于,事实上,我一直在共享一个会话。

这是我将打开的会话绑定到 ContentService 的地方:

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

这是我在 ContentService 中调用同一个会话的地方

 public class ContentService : IContentService
    
        private readonly ISession _session;

        public ContentService(ISession session)
        
            _session = session;
        

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

这就是问题所在。我正在其他地方使用的另一个服务中调用 SAME 会话

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


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

这不是线程安全的,因为一个打开的会话正在被重用。 每个服务都应该有自己的会话。

所以我用它自己的会话为 DetailService 创建了绑定,就像这样......

 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();

我没有在该服务中调用 _contentService,而是将会话添加到了它的 constrictor

    private readonly ISession Session;

    public DetailsService(ISession session)
    
        Session = session;
    

然后直接使用 Session.Query(); 运行查询

没有更多的 Session is closed 错误,没有更多的 DataReader 错误,终于可以工作了。

【讨论】:

【参考方案2】:

我对 ninject 不熟悉,我怀疑它与这里的问题有关。

如果您不知道如何正确处理会话,您可以查看 NHibernate 自己的上下文会话处理:http://nhibernate.info/doc/nhibernate-reference/architecture.html#architecture-current-session

【讨论】:

所以事实证明问题不是会话... MySQL 似乎在其他线程上过早地关闭了会话。但我仍然不知道为什么,也无法在任何地方找到解决方法。

以上是关于会话已关闭对象名称:'ISession'。在 NHibernate.Impl.AbstractSessionImpl.ErrorIfClosed() - 如何阻止会话过早关闭的主要内容,如果未能解决你的问题,请参考以下文章

Nhibernate in asp,net ISession 帮助

如何将 [] 索引应用于“ISession”类型的表达式?

Castle Windsor、Fluent Nhibernate 和 Automapping Isession 关闭问题

为啥 ISession 保存不插入?

尝试在空对象上调用接口方法“android.media.session.ISessionController android.media.session.ISession.getController(

session的关闭