简体   繁体   中英

.NET Core 3.1 BackgroundService - Consume RabbitMQ and insert using EntityFrameCore

I'm currently writing a background service which reads messages from a queue and inserts these values into a mssql database. I'm using entityframecore to insert the values into the context.

Now I'm having an issue with the context. I keep getting the error:

InvalidOperationException: A second operation started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe. Microsoft.EntityFrameworkCore.Internal.ConcurrencyDetector.EnterCriticalSection()

Now I know this is an issue with async, but still...

I fixed this by defining a new scope at the beginning. But I'm not sure if this is the way to go... Here is my code currently:

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);
                }
            };

You can see that I just pass the context to the other methods and.Add() entities. Is this the way to go?

Thanks for the help!

Kind regards

The Entity Framework does not support concurrent operation on a single DbContext . If you want to use multiple threads to communicate with your database then you have to create multiple DbContext instance. See MSDN
So, in short the DbContext is not thread-safe, that's why the suggested way to register your DbContext in your DI container is to use Transient lifecycle:

services.AddDbContext<YourDbContext>(options =>  
  options.UseSqlServer(Configuration.GetConnectionString(Constants.YourConnectionString)),
  ServiceLifetime.Transient);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM