Внедрение зависимостей DbContext в консольное приложение .Net Core: вторая операция началась в этом контексте до завершения предыдущей операции - PullRequest
0 голосов
/ 03 мая 2019

Я реализовал проект на .NET Core 2.2, который состоит из 1 консольного приложения и 1 библиотеки классов.Консольное приложение - это, по сути, потребитель, который подписывается на некоторые темы и обрабатывает поступающие сообщения. Библиотека классов - это слой базы данных, где у меня есть хранилище.Проблема заключается в том, что иногда я получаю сообщение об ошибке «System.InvalidOperationException: секундная операция, запущенная в этом контексте до завершения предыдущей операции. Любые члены экземпляра не гарантируют поточно-ориентированную защиту», когда происходит взаимодействие с базой данных.

Я искал похожие проблемы, но не мог найти решение, которое бы решило мою проблему.Я попытался зарегистрировать DbContext и IRepository как Scoped и Transient, но все еще продолжаю получать ошибку.Это неправильно, как я пытаюсь зарегистрировать DbContext?

Это мой код в Consumer.cs

class Consumer
{
    static readonly IConfigurationRoot _configuration;
    static readonly IServiceProvider _serviceProvider;
    static readonly IRepository _repository;

    static Consumer()
    {
        _configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .Build();

        _serviceProvider = new ServiceCollection()
            .AddSingleton(_configuration)
            .AddTransient<IRepository, Repository>()
            .AddDbContext<QueueContext>(options => options.UseNpgsql(_configuration.GetConnectionString("Queue")), ServiceLifetime.Transient)
            .BuildServiceProvider();

        _repository = _serviceProvider.GetService<IRepository>();
    }

    static void Main(string[] args)
    {
        ...

        RunPoll(here some parameters);
    }

    private static void RunPoll(here some parameters)
    {
        ...

        consumer.OnMessage += async (_, msg) => await ProcessMessageAsync(consumer, msg);

        ...
    }

    private static async Task ProcessMessageAsync(here some parameters)
    {
        ...

        var message = _repository.GetQueueMessage(msg.Value.Id); // On this line I get exception

        if (message == null)
        {
            message = await _repository.AddQueueMessageAsync(msg.Value.Id); // On this line I get exception
        }

        while(message.NumTries < msg.Value.MaxNumAttempts)
        {
            message = await _repository.UpdateQueueMessageTriesAsync(message); // On this line I get exception too
        }

        ...
    }
}

Это мой код в Respository.cs

public class Repository : IRepository
{
    private readonly QueueContext _db;

    public Repository(QueueContext db)
    {
        _db = db;
    }

    public QueueMessage GetQueueMessage(long id)
    {
        var message = (from qm in _db.QueueMessages
                       where qm.Id == id
                       select qm).FirstOrDefault();

        return message;
    }

    public async Task<QueueMessage> AddQueueMessageAsync(long id)
    {
        var message = new QueueMessage
        {
            Id = id,
            StartDate = DateTime.Now,
            LastTryDate = DateTime.Now,
            NumTries = 0
        }

        _db.QueueMessages.Add(message);
        await _db.SaveChangesAsync();

        return message;
    }

    public async Task<QueueMessage> UpdateQueueMessageTriesAsync(QueueMessage message)
    {
        if (message != null)
        {
            message.NumTries += 1;
            message.LastTryDate = DateTime.Now;

            _db.QueueMessages.Update(message);
            await _db.SaveChangesAsync();
        }

        return message;
    }
}

Это мой код в IRepository.cs

public interface IRepository
{   
    QueueMessage GetQueueMessage(long id);
    Task<QueueMessage> AddQueueMessageAsync(long id);
    Task<QueueMessage> UpdateQueueMessageTriesAsync(QueueMessage message);
}

1 Ответ

0 голосов
/ 04 мая 2019

Это:

_serviceProvider.GetService

не является инъекцией зависимости. DI - это когда вы определяете конструктор (или другой метод), принимающий IRepository. Тогда у вас может быть экземпляр Consumer с нестатическими методами, и хранилище соответствующим образом создается при создании Consumer (или при вызове метода).

...