Stiamo lavorando su un'applicazione Web MVC di grandi dimensioni con più archivi di backup, incluso un database SQL Server a cui si accede tramite Entity Framework 6.0. Usiamo operazioni asincrone ovunque possiamo, ma ripetiamo ripetutamente - nelle implementazioni iniziali - scenari in cui inavvertitamente iniziamo una seconda operazione asincrona sullo stesso contesto EF (utilizziamo lo stesso contesto per tutte le operazioni EF), che lancia un fa eccezione.
Non sono nuovo nello sviluppo di applicazioni aziendali in C #, ma sono piuttosto nuovo in EF e stavo pensando a possibili modi per comunicare che un determinato metodo repo deve essere await
ed immediatamente anziché potenzialmente incluso in una Task.WhenAll()
o await
ed dopo un altro metodo. Qualcuno ha considerato questo?
Alcuni pseudo-codici per scopi di discussione:
// we know that our CURRENT implementation of ICarRepo will utilize EF
// this declaration is in a backend-agnostic library
public interface ICarRepo
{
Task<ICar> GetAsync(int carID);
}
// in our EF project
public class CarRepoEF: ICarRepo
{
public async Task<ICar> GetAsync(int carID)
{
return await DataContext.Cars.SingleOrDefaultAsync(c => c.ID == carID);
}
}
Il nostro attuale approccio consiste semplicemente nel fornire commenti in scenari in cui possiamo attivare un metodo repo asincrono e continuare prima di await
ing il risultato:
// not EF
var driverTask = driverRepo.GetAsync(driverID);
//...other repo methods, logic, object instantiation, etc
// EF, await it immediately
var car = await carRepo.GetAsync(carID);
var driver = await driverTask;
Usiamo DI ovunque (incluso DataContext in un ambito di richiesta) quindi se volessimo comunicarlo ai consumatori dovremmo farlo attraverso l'interfaccia backend-agnostica, il che mi fa pensare che questa sia forse una scusa da scemo (perché l'interfaccia del repository comunica una limitazione dell'attuale implementazione dell'interfaccia?). Nello specifico, stavo considerando di inserire Task
in una classe personalizzata che comunicherebbe che non può gestire più di uno alla volta (singleton ???), o che estende l'attività stessa per comunicare lo stesso e ha interfacce che frontalmente le operazioni EF restituisci questi invece di un semplice Task
.
Dovrei rinunciare a cercare di ingegnerizzare una soluzione a questo quasi-problema? C'è un cambiamento architettonico più fondamentale che potrebbe far sparire questo problema di cui non sono a conoscenza?
Modifica
Dopo ulteriori ricerche, ho trovato una domanda SO che si occupa di questo problema ( anche usando lo stesso framework DI) e una delle risposte ha introdotto l'idea di usare una fabbrica per creare contesti.