Ядро Entity Framework: вторая операция, начатая в этом контексте до завершения предыдущей операции

Я работаю над ASP.Net проект Core 2.0 с использованием Entity Framework Core

<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.1" />
  <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.0"/>

и в одном из моих методов списка я получаю эту ошибку:

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()

Это мой метод:

    [HttpGet("{currentPage}/{pageSize}/")]
    [HttpGet("{currentPage}/{pageSize}/{search}")]
    public ListResponseVM<ClientVM> GetClients([FromRoute] int currentPage, int pageSize, string search)
    {
        var resp = new ListResponseVM<ClientVM>();
        var items = _context.Clients
            .Include(i => i.Contacts)
            .Include(i => i.Addresses)
            .Include("ClientObjectives.Objective")
            .Include(i => i.Urls)
            .Include(i => i.Users)
            .Where(p => string.IsNullOrEmpty(search) || p.CompanyName.Contains(search))
            .OrderBy(p => p.CompanyName)
            .ToPagedList(pageSize, currentPage);

        resp.NumberOfPages = items.TotalPage;

        foreach (var item in items)
        {
            var client = _mapper.Map<ClientVM>(item);

            client.Addresses = new List<AddressVM>();
            foreach (var addr in item.Addresses)
            {
                var address = _mapper.Map<AddressVM>(addr);
                address.CountryCode = addr.CountryId;
                client.Addresses.Add(address);
            }

            client.Contacts = item.Contacts.Select(p => _mapper.Map<ContactVM>(p)).ToList();
            client.Urls = item.Urls.Select(p => _mapper.Map<ClientUrlVM>(p)).ToList();
            client.Objectives = item.Objectives.Select(p => _mapper.Map<ObjectiveVM>(p)).ToList();
            resp.Items.Add(client);
        }

        return resp;
    }

Я немного потерян, особенно потому, что он работает, когда я запускаю его локально, но при развертывании на моем промежуточном сервере (IIS 8.5) он получает эту ошибку, и он работал нормально. Ошибка начала появляться после увеличения максимальной длины одной из моих моделей. Я также обновлен максимальная длина соответствующей модели представления. И есть много других методов, которые очень похожи и они работают.

у меня была работа Hangfire, но эта работа не использует ту же сущность. Это все, что я могу считать важным. Есть идеи, что могло быть причиной этого?

Спасибо за помощь

4 ответов


исключение означает, что _context используется двумя потоками одновременно; либо двумя потоками в одном запросе, либо двумя запросами.

ваш _context объявлен static, может быть? Этого не должно быть.

или ты называешь GetClients несколько раз в одном запросе из другого места в вашем коде?

возможно, вы уже делаете это, но в идеале, вы будете использовать внедрение зависимостей для DbContext, что означает, что вы будете использовать AddDbContext in ваш стартап.cs, и ваш конструктор контроллера будет выглядеть примерно так:

    private readonly MyDbContext _context; //not static

    public MyController(MyDbContext context) {
        _context = context;
    }

если ваш код не такой, покажите нам, и, возможно, мы сможем помочь дальше.


Я не уверен, что вы используете IoC и инъекцию зависимостей для решения вашего DbContext, где бы он ни использовался. Если вы используете собственный IoC из .NET Core,обязательно зарегистрируйте DbContext как переходный. Do

services.AddTransient<MyContext>();

или

services.AddDbContext<MyContext>(ServiceLifetime.Transient);

вместо

services.AddDbContext<MyContext>();

AddDbContext добавляет контекст как область видимости, что может вызвать проблемы при работе с несколькими потоками.

и асинхронный / ждут операции может вызвать такое поведение при использовании асинхронных лямбда-выражений.

добавление его в качестве переходного также имеет свои недостатки. Вы не сможете вносить изменения в некоторую сущность по нескольким классам, использующим контекст, потому что каждый класс получит свой собственный экземпляр вашего DbContext.


я столкнулся с той же проблемой, но причина не была ни одной из перечисленных выше. Я создал задачу, создал область внутри задачи и попросил контейнер получить службу. Это сработало хорошо, но затем я использовал вторую службу внутри задачи, и я забыл также попросить ее в новую область. Из-за этого 2-я служба использовала DbContext, который уже был удален.

                Task task = Task.Run(() =>
                {
                    using (var scope = serviceScopeFactory.CreateScope())
                    {
                        var otherOfferService = scope.ServiceProvider.GetService<IOfferService>();
                        // everything was ok here. then I did: 
                        productService.DoSomething(); // (from the main scope) and this failed because the db context associated to that service was already disposed.
                        ...

                    }
                }

Я должен был сделать это:

var otherProductService = scope.ServiceProvider.GetService<IProductService>();
otherProductService.DoSomething();

мне удалось заставить его работать снова. Это не имеет большого смысла, но это сработало:

  1. удалить Hangfire из запуска (я создавал свою работу там)
  2. удалена база данных hangfire
  3. перезапустить сервер

Я буду исследовать дальше позже, но метод, который я вызвал с помощью hangfire, получает DBContext, и это возможная причина.