首页 > 解决方案 > EF 和 IHostedService 的多个实例

问题描述

我在我的 DI 容器中注册了多个 IHostedService (BackgroundService) 实例。

services.AddHostedService<ResourceMatchingMessageListeningService>();
services.AddHostedService<ResourceMatchingMessageListeningService2>();
services.AddHostedService<ResourceMatchingMessageListeningService3>();
services.AddHostedService<ResourceMatchingMessageListeningService4>();
services.AddHostedService<ResourceMatchingMessageListeningService5>();

每个服务侦听不同的 Azure 服务总线队列。收到消息时,它会通过 EF Core 写入数据库。如果我运行一个服务,它工作正常,只要我运行 2 个或更多,我就会收到错误:

在前一个操作完成之前,在此上下文上开始了第二个操作。这通常是由使用相同 DbContext 实例的不同线程引起的。

我假设出现此错误是因为 EF Core 不是线程安全的,并且托管服务都在不同的线程中运行。

我厌倦了通过将 EF 的服务生命周期设置为瞬态来解决此问题),但我仍然遇到相同的错误。

services.AddDbContext<MyDataContext>(options => 
            options.UseSqlServer(connectionString, sqlServerOptions => 
            sqlServerOptions.CommandTimeout(120)),
            ServiceLifetime.Transient, ServiceLifetime.Transient);

对这里的潜在解决方案有什么建议吗?

标签: c#asp.netazureentity-frameworkazureservicebus

解决方案


您需要为每个托管服务创建一个新的服务范围,然后从该范围请求您的 DbContext。

using var scope = services.CreateScope();
var context = scope.ServiceProvider.GetService<MyDataContext>();

您可能希望为您处理的每条消息创建一个服务范围。甚至可能有一个单独的范围服务来处理每条消息的处理。

不幸的是,该实现开始看起来像一个服务定位器反模式。


推荐阅读