Operazioni asincrone con ADO.NET 2.0

di Marco Leoncini, in ASP.NET 2.0, ADO.NET,

Alcune operazioni, come l'esecuzione di complesse query su database, possono richiedere molto tempo, bloccando così l'esecuzione dell'applicazione fino al loro termine.

ADO.NET supporta l'esecuzione di operazioni asincrone mediante l'implementazione dei metodi BeginExecuteNonQuery, BeginExecuteReader e BeginExecuteXmlReader ed i complementari EndExecuteNonQuery, EndExecuteReader e EndExecuteXmlReader, esposti dalla classe SqlCommand (System.Data.SqlClient).

Il metodo BeginExecuteReader inizia l'esecuzione asincrona di uno statement Transact-SQL o di una stored procedure, lasciando libero il processo principale di proseguire nell'esecuzione di altre operazioni.
Terminata l'esecuzione dello statement è necessario richiamare il metodo EndExecuteReader per recuperare l'oggetto SqlDataReader.
Eseguire il metodo EndExecuteReader in anticipo rispetto alla conclusione del comando comporta il blocco dell'oggetto SqlCommand. Per determinare il termine dell'operazione asincrona possiamo scegliere fra eseguire il polling o utilizzare un metodo di callback, ma nel caso sia necessario eseguire più operazioni asincrone contemporaneamente è necessario affidarsi al cosiddetto Wait models.

È possibile realizzare tale modello di programmazione mediante l'uso della classe WaitHandle (System.Threading), di cui otteniamo un'istanza leggendo la proprietà AsyncWaitHandle dell'oggetto IAsyncResult, restituito dai metodi BeginExecuteNonQuery, BeginExecuteReader e BeginExecuteXmlReader.

In questo script vedremo come utilizzare il metodo BeginExecuteReader abbinato al modello WaitAny.

Creiamo una nuova classe e per simulare l'esecuzione di operazioni lunghe sospendiamo temporaneamente l'esecuzione della query tramite WAITFOR:

private const string firstQuery = "WAITFOR DELAY '0:0:10'; SELECT NAME FROM NAME WHERE ID=3";
private const string secondQuery = "WAITFOR DELAY '0:0:45'; SELECT NAME FROM NAME WHERE ID=5";
private const string thirdQuery = "WAITFOR DELAY '0:0:20'; SELECT NAME FROM NAME WHERE ID=1";

Dichiariamo un campo di tipo StringCollection dove salveremo i risultati non appena saranno restituiti:

private StringCollection returnStringCollection = new StringCollection();

Successivamente creiamo e apriamo una connessione che insieme a firstQuery utilizzeremo per inizializzare una nuova istanza della classe SqlCommand:

SqlConnection firstConnection = GetConnection();
firstConnection.Open();
SqlCommand firstCommand = new SqlCommand(firstQuery, firstConnection);

Per iniziare l'operazione asincrona, eseguiamo quindi il metodo BeginExecuteReader sull'istanza di SqlCommand appena creata:

IAsyncResult firstReseult = firstCommand.BeginExecuteReader();

Il metodo ritorna immediatamente attendendo solo il tempo necessario a trasferire al database lo statement ed i parametri, che avviene in modo sincrono.
Leggendo la proprietà AsyncWaitHandle di firstReseult recuperiamo un'istanza della classe WaitHandle che utilizzeremo per determinare la fine del processo asincrono appena iniziato:

WaitHandle firstWaitHandle = firstReseult.AsyncWaitHandle;

Ripetiamo le precedenti operazioni per le query rimanenti, inserendo ogni istanza della classe WaitHandle ottenuta in un array che successivamente passeremo al metodo statico WaitHandle.WaitAny.

WaitHandle[] waitHandles = new WaitHandle[] { firstWaitHandle, secondWaitHandle, thirdWaitHandle };

Il metodo WaitHandle.WaitAny restituisce l'indice dell'istanza WaitHandle che segnala la conclusione della rispettiva operazione asincrona:

index = WaitHandle.WaitAny(waitHandles, 60000, false);

Ad operazione conclusa, richiamiamo il metodo EndExecuteReader per ottenere così i risultati dell'esecuzione dello statement:

SqlDataReader firstReader = firstCommand.EndExecuteReader(firstReseult);

Allo script è allegato il codice ampiamente commentato che mostra nel dettaglio ogni singolo passaggio.

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi