I've been given an old WinForms app to update and improve. I am trying to add DI using SimpleInjector. I'm used to .Net MVC but this is my first time working with WinForms.
The application uses a lot of BackGround workers. My understanding is that this is specific to WinForms and each Background worker creates a new thread.
I think my problem is that when I want to save data to the DB using EF6 the SaveChanges method isn't able to save because of the multiple threads.
My SimpleInjector container is set up as follows
_container = new Container();
_container.Options.DefaultScopedLifestyle = new ThreadScopedLifestyle();
// Register DbContext
_container.Register<DbContext, MyDbContext>(Lifestyle.Scoped);
When I call SaveChanges on my dbContext I get a result of 0, which indicates that no records were saved to the database. In my debugger I get an error saying that the DbContext has been disposed. If this is happening before the save it explains why a 0 is returned from SaveChanges. Unfortunately the previous developer caught every exception so the application is trying to handle every error and this is making troubleshooting difficult and leading to unexpected behavior.
I am expecting a new DbContext to be created for each thread and that SaveChanges will save the changes made in each thread, so that what happens in one context won't affect other DbContexts in other threads.
When I am reading from the database I manually create a new DbContext in each method. Is it possible that when the using block has completed it is disposing the DbContext ?
using (var newDbContext = new MyDbContext())
{
return newDbContext.Set<TableA>().First(x => x.Id == id);
}
I'm hoping that if I have SimpleInjector configured correctly I won't need to do this either.
I'm a little lost at this stage and think I might not be understanding the documentation correctly, any advise would be greatly appreciated. Thanks in advance.
I am expecting a new DbContext to be created for each thread
This is not how TheadScopedLifestyle
works. With the ThreadScopedLifestyle
, there will be one instance of your registration within the context of an explicitly started Scope
and this scope is thread-specific. This means that one thread can have many instances of that service, since a thread can live for a long time, while a Scope
will typically only live for a short amount of time.
A typical use for ThreadScopedLifestyle
is the following:
void MethodThatRunsInABackGroundThread()
{
using (ThreadScopedLifestyle.BeginScope(container))
{
var service = container.GetInstance<ISomeService>();
service.DoWork();
}
}
When you resolve Scoped
instances (or some object graph that contains scoped instances) outside an active scope, Simple Injector will throw an exception.