2014-08-28 14 views
10

Sto usando Dapper 1.31 da Nuget. Ho questo molto semplice frammento di codice,token di cancellazione su Dapper

string connString = ""; 
string query = ""; 
int val = 0; 
CancellationTokenSource tokenSource = new CancellationTokenSource(); 
using (IDbConnection conn = new SqlConnection(connString)) 
{ 
    conn.Open(); 
    val = (await conn.QueryAsync<int>(query, tokenSource.Token)).FirstOrDefault(); 
} 

Quando premo F12 su QueryAsync, mi punta a

public static Task<IEnumerable<T>> QueryAsync<T> 
    (
     this IDbConnection cnn, 
     string sql, 
     dynamic param = null, 
     IDbTransaction transaction = null, 
     int? commandTimeout = null, 
     CommandType? commandType = null 
    ); 

Non c'è CancellationToken sulla sua firma.

Domande:

  • Perché il frammento completamente edificabile assumendo che non v'è alcun errore del compilatore su tutta la soluzione?
  • Perdonami perché non riesco a verificare se chiamare tokenSource.Cancel() annullerebbe il metodo perché non so come generare query sql a esecuzione prolungata. Lo strumento .Cancel() annullerà davvero il metodo e genera OperationCancelledException?

Grazie!

+0

'param' dinamica avrà praticamente nulla. Quello che stai facendo è un po 'come passare un token di cancellazione come parametro a 'Console.WriteLine (string, params object [])'. Solo perché puoi passarlo non significa che la funzione supporti la cancellazione. –

risposta

19

Si sta passando il token di cancellazione come oggetto parametro; quello non funzionerà.

I primi metodi asincroni in dapper non espongono un token di cancellazione; quando ho provato ad aggiungerli come parametro opzionale (come sovraccarico separato, per evitare di rompere gli assiemi esistenti), things got very confused with "ambiguous method" compilation problems. Di conseguenza, ho dovuto esporlo tramite un'API separata; entrare CommandDefinition:

val = (await conn.QueryAsync<int>(
    new CommandDefinition(query, cancellationToken: tokenSource.Token) 
).FirstOrDefault(); 

Questo passa quindi la cancellazione-token lungo la catena a tutti i luoghi previsti; è il lavoro del provider ADO.NET in realtà utilizzare, ma; sembra funzionare nella maggior parte dei casi. Si noti che può comportare un SqlException anziché un OperationCancelledException se l'operazione è in corso; questo di nuovo dipende dal provider ADO.NET, ma ha molto senso: potresti aver interrotto qualcosa di importante; si presenta come un problema di connessione critico.

Per quanto riguarda le domande:

Perché il frammento completamente edificabile assumendo che non v'è alcun errore del compilatore su tutta la soluzione?

Perché ... è C# valido, anche se non fa quello che ti aspetti.

Perdonami perché non riesco a verificare se la chiamata a tokenSource.Cancel() annullerebbe davvero il metodo perché non so come generare query sql a esecuzione lunga. .Cancel() annulla davvero il metodo e lancia OperationCancelledException?

Specifico del provider ADO.NET, ma sì, di solito funziona. Come esempio di "come generare query sql a esecuzione lunga"; il comando waitfor delay sul server SQL è un po 'utile qui, ed è quello che uso nei test di integrazione.

+1

Questa è una grande risposta dell'autore stesso. Grazie Marc per l'API alternativa! Bene, sto bene con la cattura di 'SqlException' piuttosto che' OperationCancelledException', gestirò la logica qui. Grazie ancora! – Pedigree

+1

@Pedigree I * think * Ho anche capito come farlo funzionare correttamente anche nell'API primaria. –

+0

Ho un'altra domanda marc e non so se questo è ancora nell'oscilloscopio, perché hai impostato '.ConfigureAwait (false)' su * linea 78 * di [file: SqlMapperAsync.cs] (https: // github.com/StackExchange/dapper-dot-net/blob/master/Dapper%20NET45/SqlMapperAsync.cs)? Cosa significa veramente? Grazie. – Pedigree

1

È possibile correggere SqlMapper.cs in Dapper lib aggiungendo queste righe:

internal IDbCommand SetupCommand(IDbConnection cnn, Action<IDbCommand, object> paramReader) 
    { 
     var cmd = cnn.CreateCommand(); 

#if ASYNC 
     // We will cancel our IDbCommand 
     CancellationToken.Register(() => cmd.Cancel()); 
#endif 

ricostruire il proprio lib Dapper e godere :)