All'interno di un'applicazione ASP.NET MVC Ricevo il seguente messaggio di errore per uno dei metodi del controller che utilizza il contesto Entity Framework.Perché non compare per impedire la seconda operazione sul contesto EF
Una seconda operazione è iniziata in questo contesto prima di una precedente operazione asincrona completata. Utilizzare 'attendi' per assicurarsi che tutte le operazioni asincrone siano state completate prima di chiamare un altro metodo in questo contesto. Non è garantito che tutti i membri di istanza siano thread-safe.
Sono consapevole che non è possibile eseguire query in parallelo e tutto sembra essere in attesa correttamente. Se eseguo il debug del programma e passo e ispeziono alcuni dei dati restituiti da EF, allora funziona, probabilmente perché questo impone il completamento delle query.
EDIT Se metto un punto di interruzione al momento del check nulla nel metodo di controllo e controllare i dati del shipmentDetail
l'eccezione non viene generata.
Ecco uno snippit del codice:
Metodo controller:
[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 Metodo:
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;
}
io non sono del tutto sicuro se è a causa della query eseguita nel controller o a causa delle query eseguite nel ciclo che non sono c completando questo comportamento. C'è qualcosa su cui non capisco quando le query sono effettivamente fatte/restituite a causa della pigrizia di EF, o di come async/await funziona in questa situazione? Ho un sacco di altri metodi di controllo & che effettuano chiamate EF asincrona e non l'ho mai visto prima.
EDIT
mio contesto viene iniettato nel mio controller utilizzando Ninject come il mio contenitore CIO. Ecco la sua configurazione interna del metodo di RegisterServices NinjectWebCommon:
kernel.Bind<Context>().ToSelf().InRequestScope();
Ho il sospetto che il vostro errore è venuta da qualche altra parte, questo codice dovrebbe andare bene. A) Il tuo 'db' è condiviso con altre viste/modelli di vista? B) Lo hai scavalcato con un debugger per vedere se getta ancora? – CodingGorilla
A) No non viene condiviso, viene iniettato nel controller e utilizzato solo lì, queste sono le uniche 2 operazioni che utilizzano il contesto 'db' per questa richiesta http. B) L'uso di un debugger non getta se controllo i dati restituiti da EF (ho menzionato questo nella domanda), altrimenti lo fa. – JNYRanger
Puoi approfondire come viene iniettato? Viene iniettato da un contenitore IoC? In tal caso, come viene configurata la registrazione IoC? – CodingGorilla