我已经获得了一个旧的WinForms应用程序来更新和改进。我正在尝试使用SimpleInjector添加DI。我习惯了.Net MVC,但这是我第一次使用WinForms。
该应用程序使用了很多BackGround worker。我的理解是,这是WinForms特有的,每个后台工作者都会创建一个新线程。
我认为我的问题是,当我想使用EF6将数据保存到数据库时,由于多线程,SaveChanges方法无法保存。
My SimpleInjector容器设置如下
_container = new Container();
_container.Options.DefaultScopedLifestyle = new ThreadScopedLifestyle();
// Register DbContext
_container.Register<DbContext, MyDbContext>(Lifestyle.Scoped);
当我在dbContext上调用SaveChanges时,得到的结果为0,表示没有记录保存到数据库中。在我的调试器中,我得到一个错误,说DbContext已经被处理掉了。如果在保存之前发生这种情况,它解释了为什么从SaveChanges返回0。不幸的是,之前的开发人员捕获了每个异常,因此应用程序正在尝试处理每个错误,这使得故障排除变得困难并导致意外行为。
我期望为每个线程创建一个新的DbContext,并且SaveChanges将保存每个线程中所做的更改,以便在一个上下文中发生的事情不会影响其他线程中的其他DbContexts。
当我从数据库中读取数据时,我在每个方法中手动创建一个新的DbContext。是否有可能当使用块完成时它正在处理DbContext?
using (var newDbContext = new MyDbContext())
{
return newDbContext.Set<TableA>().First(x => x.Id == id);
}
我希望如果我正确配置了SimpleInjector,我也不需要这样做。
我在这个阶段有点迷失,并认为我可能没有正确理解文档,任何建议将不胜感激。提前谢谢。
答案 0 :(得分:2)
我期待为每个线程创建一个新的DbContext
这不是TheadScopedLifestyle
的工作原理。使用ThreadScopedLifestyle
,在显式启动的Scope
的上下文中将有一个注册实例,并且此范围是特定于线程的。这意味着一个线程可以拥有该服务的许多实例,因为线程可以存活很长时间,而Scope
通常只能存活很短的时间。
ThreadScopedLifestyle
的典型用法如下:
void MethodThatRunsInABackGroundThread()
{
using (ThreadScopedLifestyle.BeginScope(container))
{
var service = container.GetInstance<ISomeService>();
service.DoWork();
}
}
当您在活动范围外解析Scoped
个实例(或包含范围实例的某些对象图)时,Simple Injector将抛出异常。