c# - .NET Core 3.1 BackgroundService - 使用 RabbitMQ 并使用 EntityFrameCore 插入
问题描述
我目前正在编写一个后台服务,它从队列中读取消息并将这些值插入到 mssql 数据库中。我正在使用 entityframecore 将值插入到上下文中。
现在我遇到了上下文问题。我不断收到错误:
InvalidOperationException:在前一个操作完成之前在此上下文上启动了第二个操作。不保证任何实例成员都是线程安全的。Microsoft.EntityFrameworkCore.Internal.ConcurrencyDetector.EnterCriticalSection()
现在我知道这是异步的问题,但仍然......
我通过在开始时定义一个新范围来解决这个问题。但我不确定这是否是要走的路......这是我目前的代码:
consumer.Received += async (ch, ea) =>
{
using (var scope = _scope.BeginLifetimeScope())
{
var context = scope.Resolve<DatabaseContext>();
var content = Encoding.UTF8.GetString(ea.Body.ToArray());
var message = JsonConvert.DeserializeObject<RabbitMQMessageType>(content);
switch (message.Type)
{
case "config":
await HandleConfigMessage(message.Body, context);
break;
case "measurement":
await HandleMeasurementMessage(message.Body, context);
break;
case "log":
await HandleLogMessage(message.Body);
break;
}
_channel.BasicAck(ea.DeliveryTag, false);
}
};
您可以看到我只是将上下文传递给其他方法和 .Add() 实体。这是要走的路吗?
谢谢您的帮助!
亲切的问候
解决方案
实体框架不支持对单个DbContext
. 如果要使用多个线程与数据库通信,则必须创建多个 DbContext 实例。请参阅 MSDN
所以,简而言之 DbContext 不是线程安全的,这就是为什么在 DI 容器中注册 DbContext 的建议方法是使用瞬态生命周期:
services.AddDbContext<YourDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString(Constants.YourConnectionString)),
ServiceLifetime.Transient);
推荐阅读
- reactjs - 如何使用 Redux 在前端实现身份验证?
- java - Java 8 可选映射并执行不同的功能
- r - 使用 R 中的 readxl 包从 excel 文件中的某些行开始读取特定列
- python - 如何删除数组中的部分文本?
- pyspark - 计算 pyspark.sql 中与爆炸列匹配的记录数?
- javascript - 内容下载时导航空闲
- reactjs - 如何把它变成一个函数
- yocto - 添加/编辑 .bbappend 文件时应如何处理增加包修订?
- visual-studio - 在 Visual Studio 中,如何有效地使用 NuGet 包源代码
- vim - Vim 映射 Cntrl-i 在正常和插入之间切换