Подтвердить что ты не робот

Почему ожидание не может предотвратить вторую операцию в контексте EF

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

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

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

EDIT Если я положу точку останова при нулевой проверке в методе контроллера и проведу данные shipmentDetail, исключение НЕ выбрано.

Вот фрагмент кода:

Метод контроллера:

[Route("{id:int}/Deliveries")]
public async Task<ActionResult> DeliveryInfo(int id)
{
    var shipmentDetail = await db.ShipmentDetails.SingleOrDefaultAsync(s => s.Id == id);
    if (shipmentDetail == null)
        return HttpNotFound(string.Format("No shipment detail found with id {0}", id));
     var model = await DeliveryInfoModel.CreateModel(db, shipmentDetail);
    return View("DeliveryInfo", model);
}

Метод CreateModel:

public static async Task<DeliveryInfoModel> CreateModel(Context db, ShipmentDetail shipment)
{
    DeliveryInfoModel model = new DeliveryInfoModel()
    {
        ShipmentInfo = shipment
    };

    //initialize processing dictionary
    Dictionary<int, bool> boxesProcessed = new Dictionary<int, bool>();
    List<DeliveryBoxStatus> statuses = new List<DeliveryBoxStatus>();

     for (int i = 1; i <= shipment.BoxCount; i++ )
        {
            boxesProcessed.Add(i, false);
        }

        //work backwards through process

        //check for dispositions from this shipment
        if(shipment.Dispositions.Count > 0)
        {
             foreach (var d in shipment.Dispositions)
            {
                DeliveryBoxStatus status = new DeliveryBoxStatus()
                {
                    BoxNumber = d.BoxNumber,
                    LastUpdated = d.Date,
                    Status = d.Type.GetDescription().ToUpper()
                };

                statuses.Add(status);
                boxesProcessed[d.BoxNumber] = true;
            }
        }

        //return if all boxes have been accounted for
        if (boxesProcessed.Count(kv => kv.Value) == shipment.BoxCount)
        {
            model.BoxStatuses = statuses;
            return model;
        }

        //check for deliveries
        if(shipment.Job_Detail.Count > 0)
        {
            foreach (var j in shipment.Job_Detail.SelectMany(d => d.DeliveryInfos))
            {
                DeliveryBoxStatus status = new DeliveryBoxStatus()
                {  
                    BoxNumber = j.BoxNumber,
                    LastUpdated = j.Job_Detail.To_Client.GetValueOrDefault(),
                    Status = "DELIVERED"
                };

                statuses.Add(status);
                boxesProcessed[j.BoxNumber] = true;
            }
        }

    //check for items still in processing & where
    foreach (int boxNum in boxesProcessed.Where(kv => !kv.Value).Select(kv => kv.Key))
    {
       //THIS LINE THROWS THE EXCEPTION
        var processInfo = await db.Processes.Where(p => p.Jobs__.Equals(shipment.Job.Job__, StringComparison.InvariantCultureIgnoreCase) && p.Shipment == shipment.ShipmentNum && p.Box == boxNum)
                                .OrderByDescending(p => p.date)
                                .FirstOrDefaultAsync();

       //process returned data
       //...
    }

    model.BoxStatuses = statuses;

    return model;
}

Я не совсем уверен, что это из-за запроса, сделанного в контроллере, или из-за запросов, сделанных в цикле, которые не завершают это поведение. Есть ли что-то, что я не понимаю, когда запросы действительно сделаны/возвращены из-за EF лень, или как async/await работает в этой ситуации? У меня есть много других методов и контроллеров, которые делают асинхронные вызовы EF и не выполнялись ранее.

ИЗМЕНИТЬ

Мой контекст вводится в мой контроллер, используя Ninject в качестве моего контейнера IoC. Здесь его config внутри метода NinjectWebCommon RegisterServices:

kernel.Bind<Context>().ToSelf().InRequestScope();
4b9b3361

Ответ 1

Избегайте ленивой загрузки при использовании async с Entity Framework. Вместо этого либо загрузите нужные данные, либо используйте Include(), чтобы убедиться, что нужные вам данные загружены с запросом.

https://msdn.microsoft.com/en-gb/magazine/dn802603.aspx

Текущее состояние поддержки Async

... Async поддержка была добавлена ​​в Entity Framework (в EntityFramework NuGet пакет) в версии 6. Вы должны быть осторожны, чтобы избежать ленивых загрузка при работе асинхронно, хотя, поскольку ленивая загрузка всегда выполняется синхронно....

(Акцент мой)

также:

https://entityframework.codeplex.com/wikipage?title=Task-based%20Asynchronous%20Pattern%20support%20in%20EF.#ThreadSafety