15

In an MVC / WebAPI environment I would use InRequestScope to bind the DbContext.

However, I am now on a Console application / Windows service / Azure worker role (doesn't really matter, just there's no Web request scope), which periodically creates a number of Tasks that run asynchronously. I would like each task to have its own DbContext, and since tasks run on their own thread, I tried binding DbContext using InThreadScope.

Unfortunately, I realize that the DbContext is not disposed when a task is finished. What actually happens is, the thread returns to the Thread Pool and when it is assigned a new task, it already has a DbContext, so DbContexts stay alive forever.

Is there a way InThreadScope can be used here or should I use some other scope? How can ThreadScope be used when threads are returning from ThreadPool every now and then?

zafeiris.m
  • 4,339
  • 5
  • 28
  • 41
  • You noticed that the [Per Thread Lifestyle is Considered Harmful](https://stackoverflow.com/questions/14591422/why-is-perthreadlifetimemanager-used-in-this-example). – Steven Apr 15 '14 at 11:14
  • @Steven Yes, I see. So how to implement custom scope (or other solution)? – zafeiris.m Apr 15 '14 at 11:30
  • 1
    You should not use a scope at all. Use a factory to create the DbContext (which is basically a *unit of work*) - and pass it around as necessary. If the software stays as simple as you describe it, you could also use a named scope (defined by the Task and bind DbContext `InNamedScope`). But that is not future proof for example when you want to create DbContext outside of a task or when you want to have multiple (sequential) DbContext inside a single task,... etc – BatteryBackupUnit Apr 15 '14 at 11:36
  • I tend to disagree with @BatteryBackupUnit on this, but it depends on your application what the best approach is. IMO 'right' solution is to explicitly start a 'scope' per operation, although I don't know how to do that in Ninject. If written about when to use a factory and when to inject the UoW itself, [here](https://stackoverflow.com/questions/10585478/one-dbcontext-per-web-request-why). The answer talks about web apps, but this is applicable to any application that handles requests of some sort. – Steven Apr 15 '14 at 11:47
  • @Steven, i completely agree, but i also think that once you've used "Method Injection" for a while a pattern should emerge automagically on how you should abstract it best. Not the perfect answer for now but a way to get to better code mid-term to long term ;-). We are storing the `DbContext` in a thread-local so we don't need method-injection. This works perfectly for us (as described here: http://stackoverflow.com/questions/21674590/how-to-use-ninject-in-a-multi-threaded-windows-service-to-get-new-instances-of-a/21676963#21676963). – BatteryBackupUnit Apr 15 '14 at 11:53
  • @BatteryBackupUnit: One interesting quote from your anser 21674590 is "Once all operations are done, we release the DbContext and reset the ThreadLocal.Value.". By doing this you created your own 'scope': i.e. the lifetime of the DbContext is clearly defined and ends at the end of the request. – Steven Apr 15 '14 at 11:59
  • 2
    @Steven I agree 100%. Just to clarify it for other readers: Ninject features a concept of "scope". Binding "in" a scope tells ninject when to create an instance and when to reuse one. We did not use that kind of scope. Also i would not exactly say that we couple it to the request. We've got WCF requests and we've got events comming from hardware devices. Some of the WCF requests or events may instruct us to do several things which may require several unit of works, sometimes even async or at a later point (like scheduled or what not). Sometimes operations requiring unit of work may be nested. – BatteryBackupUnit Apr 15 '14 at 12:55
  • @BatteryBackupUnit: Seems we're on the same wavelength here. Since you know most about Ninject, would you like to answer the question? Perhaps giving the OP the possible options there are. You'll get my +1. – Steven Apr 15 '14 at 13:02
  • @BatteryBackupUnit and Steven so is there any solution ??!! ^_^ – Wahid Bitar May 22 '16 at 14:15
  • 1
    @WahidBitar yes: 1) use a factory to create a UnitOfWork, pass it around, and dispose it at the end, 2) use a factory to create a UnitOfWork, and use something like a ["TaskLocal"](http://blog.stephencleary.com/2013/04/implicit-async-context-asynclocal.html) to access it without having to pass it around. – BatteryBackupUnit May 26 '16 at 21:19

1 Answers1

2

If you decide to go on with custom scope, the solution is:

public sealed class CurrentScope : INotifyWhenDisposed
{
    [ThreadStatic]
    private static CurrentScope currentScope;

    private CurrentScope()
    {
    }

    public static CurrentScope Instance => currentScope ?? (currentScope = new CurrentScope());

    public bool IsDisposed { get; private set; }

    public event EventHandler Disposed;

    public void Dispose()
    {
        this.IsDisposed = true;
        currentScope = null;
        if (this.Disposed != null)
        {
            this.Disposed(this, EventArgs.Empty);
        }
    }
}

Binding:

Bind<DbContext>().To<MyDbContext>().InScope(c => CurrentScope.Instance)

And finally:

using (CurrentScope.Instance)
{
    // your request...
    // you'll get always the same DbContext inside of this using block
    // DbContext will be disposed after going out of scope of this using block
}
Jan Muncinsky
  • 4,282
  • 4
  • 22
  • 40