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.Flu开发者_JAVA百科sh() as the last line of my NHibernateRepository.Save() method, but I'm not happy with that.
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.
精彩评论