2016-01-13 8 views
10

Innerhalb einer ASP.NET MVC-Anwendung erhalte ich die folgende Fehlermeldung für eine meiner Controller-Methoden, die meine Entity Framework-Kontext verwendet.Warum wird keine zweite Operation im EF Kontext zu verhindern scheint

Eine zweite Operation wurde in diesem Kontext gestartet, bevor eine vorherige asynchrone Operation abgeschlossen wurde. Verwenden Sie 'abwarten', um sicherzustellen, dass alle asynchronen Vorgänge abgeschlossen sind, bevor Sie eine andere Methode in diesem Kontext aufrufen. Es ist nicht garantiert, dass alle Instanzmitglieder Thread-sicher sind.

Ich bin mir bewusst, dass Sie keine Abfragen parallel ausführen können, und alles scheint richtig erwartet zu werden. Wenn ich das Programm debuggen und einige der von EF zurückgegebenen Daten schrittweise überprüfe und überprüfe, funktioniert es wahrscheinlich, weil dies die Abfragen zum Abschluss bringt.

BEARBEITEN Wenn ich einen Haltepunkt bei der Nullprüfung in der Controller-Methode platzieren und die Daten von shipmentDetail untersuchen, wird die Ausnahme NICHT ausgelöst.

Hier ist ein snippit des Codes:

Controller-Methode:

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

Create Methode:

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

ich nicht ganz sicher bin, ob es wegen der ist Abfrage im Controller gemacht, oder wegen der Abfragen in der Schleife, die nicht c sind ompleting verursacht dieses Verhalten. Gibt es etwas, das ich nicht verstehe, wenn die Anfragen aufgrund der Faulheit von EF tatsächlich gemacht/zurückgegeben werden oder wie async/wait in dieser Situation funktioniert? Ich habe eine Menge anderer Methoden & Controller, die async EF-Aufrufe machen und haben nicht zuvor in diesem ausgeführt. mit Ninject als mein IoC-Container

EDIT

ist mein Kontext in meinen Controller injiziert. Hier ist seine Konfiguration innerhalb von NinjectWebCommon der RegisterServices Methode:

kernel.Bind<Context>().ToSelf().InRequestScope(); 
+0

ich vermuten, dass Ihr Fehler von woanders kommt, sollte dieser Code in Ordnung sein. A) Ist Ihre 'db' mit anderen Ansichten/View-Modellen geteilt? B) Bist du mit einem Debugger durchgegangen, um zu sehen, ob es noch würfelt? – CodingGorilla

+0

A) Nein, es wird nicht geteilt, es wird in den Controller injiziert und nur dort verwendet, dies sind die einzigen 2 Operationen, die den 'db'-Kontext für diese HTTP-Anfrage verwenden. B) Die Verwendung eines Debuggers löst nicht aus, wenn ich die von EF zurückgegebenen Daten überprüfe (ich erwähnte dies in der Frage), andernfalls tut es das. – JNYRanger

+0

Können Sie erweitern, wie es injiziert wird? Wird es aus einem IoC-Container injiziert? Wenn ja, wie ist Ihre IoC-Registrierung konfiguriert? – CodingGorilla

Antwort

6

verzögertes Laden vermeiden, wenn sie mit Entity Framework mit async. Laden Sie stattdessen die Daten, die Sie zuerst benötigen, oder verwenden Sie Include(), um sicherzustellen, dass die Daten, die Sie benötigen, mit der Abfrage geladen werden.

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

Aktuelle Stand der Async Unterstützung

... Async Unterstützung Entity Framework hinzugefügt wurde (in dem EntityFramework NuGet Paket) in der Version 6.er Sie können zu Seien Sie vorsichtig zu vermeiden, faul Laden, wenn asynchron, obwohl, weil Lazy Loading immer synchron ausgeführt wird. ...

(Hervorhebung von mir)

auch:

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

Verwandte Themen