5

What's the best scoping to use for a DbContext implementation that gets instantiated via Ninject dependency resolver during execution of a Quartz.Net job implementation? If I used thread scope, will the same instance of DbContext get served if the same thread in Quartz's thread pool is used to execute the job multiple times?

I would like a scope that means I get one (and only one) new instance of the DbContext each time the job is fired.

Simon Green
  • 1,131
  • 1
  • 10
  • 28
  • Can you confirm if the accepted solution has worked well? I'm looking into doing something similar – Nick Patsaris Oct 24 '14 at 12:27
  • 1
    Yes it's certainly a vast improvement over what I had before. Initially I was just using RequestScope for everything, but that was producing a new DBContent every time it had to be injected into any dependency required by the Quartz job implementation. The only downside now is, I get a single DBContext instance when the Quartz Job implementation is instantiated, but if I ever call DependencyResolver.Current.GetService() within the job's implementation code, ninject will create another new instance of DBContext for the service instance returned (if that service also depends on it) – Simon Green Oct 25 '14 at 06:10

1 Answers1

6

Yes, i would advise against using InThreadScope. When a thread-pool thread is used, there will be leakage.

Furthermore, there's nothing built-in into ninject like a "QuartzScope", so you'll have to create your own solution. let's start with the instantiation of the job. That's covered by this stackoverflow answer and, more extensively, by the source code of this nuget package.

Now one possible solution is to extend the JobFactory to manage the creation of the DbContext and inject it into the job and all its dependencies (as an inherited ConstructorArgument parameter). However, that has two drawbacks: Always creates a DBContext (whether the job needs it or not), and you need to track DBContext instances so you can .Dispose() of them in the IJobFactory.ReturnJob(IJob) method (p.ex. by a Dictionary<IJob, DBContext or the likes).

The much easier way is to use .InCallScope (included in Ninject.Extensions.NamedScope) for the DbContext binding. This will create one DbContext instance per kernel.Get<FooJob>().

If you need to have different scopes for your DbContext - depending on where you use them, p.Ex. inside a Job and inside your ASP.NET MVC stuff, you might want to look at Ninject Conditional Self bind to change scope (For Task-scheduler) not working properly?

Community
  • 1
  • 1
BatteryBackupUnit
  • 12,934
  • 1
  • 42
  • 68
  • Hi there, thanks for the reply. Unfortunately, there isn't a .InCallScope() method. I have .InThreadScope, .InRequestScope and .InTransientScope. Or, I have to do it manually with .InScope - but this is where I need the help! – Simon Green Aug 29 '14 at 07:10
  • Also, do I have to worry about manually disposing of the DbContext at the end of the job? – Simon Green Aug 29 '14 at 07:10
  • I've just discovered that .InCallScope() comes with the Ninject.Extensions.NamedScope Nuget package - for the benefit of future readers – Simon Green Aug 29 '14 at 08:00
  • sorry for leaving that out. I've edited the answer to include that information. – BatteryBackupUnit Aug 29 '14 at 08:30
  • 1
    Seems to work great, thanks. I use InCallScope when instantiating my DbContext in a Quartz job, and InRequestScope otherwise. I use the When() method in the binding to test for HttpContext.Current, to tell if I'm in a Quartz worker thread or an HTTP Request worker thread – Simon Green Aug 29 '14 at 12:06
  • Using `HttpContext.Current` to determine which scope to use is pretty neat. – BatteryBackupUnit Aug 29 '14 at 12:12