【问题标题】:Multithreading issue with Autofac in WPF applicationWPF 应用程序中 Autofac 的多线程问题
【发布时间】: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


【解决方案1】:

据我所知,您通过Constructor Injection 注入_collectionService 实例,在不同的事件处理程序之间共享它。

在这里使用Method Injection 可能会更好,这样您就可以根据需要在每次调用时获取实例,并在方法之前解决它:

builder.Register(c =>
{
    var result = new MyObjectType();
    var dep = c.Resolve<TheDependency>();
    result.SetTheDependency(dep);
    return result;
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-17
    • 1970-01-01
    相关资源
    最近更新 更多