【发布时间】:2017-02-19 07:42:22
【问题描述】:
我正在使用基于 WPF 的应用程序并使用 Autofac 来解决 Entityframework 的 DbContext 的依赖关系。我使用下面的代码注册了我的数据模块。
public class DataModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<DataContext>()
.As<IDbContext>()
.WithParameter("nameOrConnectionString", "DefaultConnectionString")
.InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(Repository<>))
.As(typeof(IRepository<>))
.InstancePerLifetimeScope();
}
}
这在正常情况下使用时工作正常,但在使用 TPL 时,由于同时调用存储库,它会创建错误,指出“ExecuteReader 需要打开且可用的连接。连接的当前状态是打开的。”
在 Web 应用程序中,可以使用 InstancePerRequest 解决每个请求的依赖关系,但在 WPF 中,我需要解决每个线程请求的依赖关系。有没有办法解决这个问题?
我查看了 InstancePerRequest 总结或 autofac,它声明此方法仅用于 Web 请求:
// Summary:
// Share one instance of the component within the context of a single web/HTTP/API
// request. Only available for integration that supports per-request dependencies
// (e.g., MVC, Web API, web forms, etc.).
更新:
这是我用来获取数据的简单异步方法:
private async void OnLoadClientDetail()
{
long clientId = SelectedClient != null ? SelectedClient.Id : 0;
var listOfCollection = await _collectionService.GetCollectedCollectionAsync(clientId);
CollectionList = new ObservableCollection<CollectedCollection>(listOfCollection);
}
这里 OnLoadClientDetail 绑定到组合框的选择更改事件。当用户频繁更改选择时,此方法将被多次调用。 _collectionService 被注入视图模型并定义了 InstancePerLifetimeScope。那么如何才能为所有这些调用获得不同的范围呢?
【问题讨论】:
-
为什么每个线程都需要一个实例?
-
@MaKCbIMKo 实际上有多个线程访问同一个 SQL 表,由于该表被锁定,我得到异常“ExecuteReader 需要一个打开且可用的连接。连接的当前状态是打开的。”跨度>
-
这正是
InstancePerLifetimeScope的用途。您将逻辑工作单元包装在生命周期范围内并从该范围解析。这样可以确保每个工作单元都有自己的DataContext,从而防止跨线程或操作共享实例。 -
解决方案是不注入服务,而是从作用域中解析并调用它。
-
每个线程都应该有自己的对象图。此对象图可以由跨线程共享的对象组成,但应用程序代码不应将服务传递给其他线程。这应该封装在 Composition Root 中。
标签: c# wpf multithreading entity-framework autofac