使用 NInject 在生成的线程中确定 NHibernate ISession 的范围
好的,这是场景。我有一个 ASP.NET 站点,它定期生成一个后台线程来完成一些工作。该线程的执行由一个 JobRunner 组成,它循环访问 IJobs 列表并对每个 IJobs 调用 Execute()。 JobRunner 和每个 IJob 都是由 NInject 创建的。一些 IJobs 依赖于 IRepository
问题是:当各种 IJobs 进行处理(涉及保存到 IRepository)时,数据永远不会被持久化,因为 ISession.Flush() 永远不会被调用。每个 IJob 都不知道它所使用的 IRepository 的实现。同样,JobRunner 对它正在运行的 IJobs 的实现一无所知。对于 Web 应用程序的其余部分,它工作正常,因为 ISession.Flush() 在 Application_EndRequest 中被调用。
我尝试将 ISession 作为 JobRunner 的构造函数参数,以便在所有 IJobs 处理完成时可以在其上调用 Flush() ,但它似乎获得与 IJobs 不同的 ISession (调用 session.GetHashCode() 返回不同的值对于 JobRunner,但对于所有 IJobs 都是相同的)。我将 NInject 配置为基于 HttpContext(如果有)来确定 ISession 的范围,否则使用 CurrentThread。我认为,由于 JobRunner 位于单独的线程上,它将获得一个作用域为 CurrentThread 的 ISession,并且由于所有 IJobs 都在与 JobRunner 相同的线程上运行,因此它们都应该获得相同的 ISession,但事实并非如此。
所以我的问题是,有没有更好的方法来完成我想做的事情?有人知道为什么我会为同一线程上的不同请求获得不同的 ISession 实例吗?
现在我有一个解决方法 - 我将 session.Flush() 作为 NHibernateRepository.Save() 方法的最后一行,但我对此并不满意。
Ok, here's the scenario. I have an ASP.NET site that periodically spawns a background thread to do some jobs. the thread's execution consists of a JobRunner that iterates through a list of IJobs and calls Execute() on each one. JobRunner and each IJob is created by NInject. A couple of the IJobs have a dependency to IRepository<ModelType>. The implementation of IRepository I'm using is for NHibernate, so it has a constructor argument for ISession. Up till now, I've had NInject return an ISession from a ISessionFactory, scoped to each Request (InRequestScope).
Here's the problem: when the various IJobs do their processing (which involves Saving to the IRepository) the data never gets persisted because ISession.Flush() never gets called. Each IJob doesn't know anything about the implementation of the IRepository it's using. Likewise, the JobRunner doesn't know anything about the implementation of the IJobs it's running. For the rest of the web application, it's working fine because ISession.Flush() gets called in the Application_EndRequest.
I tried putting ISession as a constructor argument to the JobRunner so that I could call Flush() on it when all IJobs are done processing, but it appears to be getting a different ISession than the IJobs (calling session.GetHashCode() returns different values for JobRunner, but for all the IJobs it's the same). I configured NInject to scope ISession based on HttpContext if there is one, otherwise use CurrentThread. I figured that since JobRunner is on a separate thread it will get an ISession scoped to CurrentThread, and since all IJobs are run on the same thread as JobRunner, they should all get the same ISession, but they're not.
So my question is, is there a better way to do what I'm trying to do? Anyone know why I would be getting a different instance of ISession for different requests on the same thread?
For now I have a workaround - I put session.Flush() as the last line of my NHibernateRepository.Save() method, but I'm not happy with that.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
好吧,我找到了解决方案。我的 JobRunner 对象在 Global.asax 的 Application_Start 方法中实例化,因此保存该线程 ID 而不是后台线程 ID。
我创建了一个包装类,它采用一个类型并使用 NInject 创建一个实例,每次后台线程开始处理时,它都会使用该包装类来获取 JobRunner 的实例。这会在正确的线程上创建它,这使我能够获得与 IRepository 相同的 ISession,这样我就可以在所有 IJobs 完成后调用 session.Flush() 。
也许有一个更优雅的解决方案,但在那之前,这种方法效果很好。
well I found the solution. my JobRunner object was being instantiated in the Application_Start method of Global.asax, and as such held that thread ID instead of the background thread ID.
I created a wrapper class that takes a type and uses NInject to create an instance, and every time the background thread comes around to start processing, it uses the wrapper class to get an instance of JobRunner. that creates it on the proper thread which allows me to get the same ISession as my IRepository so I can call session.Flush() after all IJobs have completed.
maybe there is a more elegant solution, but until then, this works well.