2015-01-28 8 views
5

Bene, il mio problema è che chiamare attende tabella.ExecuteAsync (...) nella tabella di archiviazione di Azure inserisce i dati richiesti, ma non finisce mai (non restituisce TableResult). Stesso caso con le operazioni InsertOrUpdate e Update. Ho anche provato diverse tabelle con un numero diverso di proprietà - lo stesso problema.Tabelle di archiviazione di Azure: attende table.ExecuteAsync (InsertOperation) viene eseguito, ma non termina mai

Quando chiamo table.Execute (...) - tutto funziona correttamente per ogni tipo di operazione.

Ecco il mio codice - semplice come quello:

chiamata esterna (si è posto in MVC controller in azione asincrona):

List<Task<ServiceResult<Boolean?>>> addPostTasks = new List<Task<Common.ServiceResult<bool?>>>();    
foreach (var userStream in userStreams) 
{ 
    Task<ServiceResult<Boolean?>> addPostTask = postsStorageSvc.AddImagePost(...); 
    postsAddImagePostTasks.Add(addPostTask); 
} 
Task.WaitAll(addPostTasks.ToArray()); 

Metodo chiamato:

public async Task<ServiceResult<Boolean?>> AddImagePost(...) 
{ 
ServiceResult<Boolean?> result = new ServiceResult<bool?>(null); 
try 
{ 
    PostTableEntity newPost = new PostTableEntity(streamId.ToString(), Guid.NewGuid().ToString(), creatorId, date, htmlText);    
    TableOperation insertOperation = TableOperation.Insert(newPost); 
    //Following line never ends! 
    TableResult tableResult = await this._storageTableBootstrapper.Table.ExecuteAsync(insertOperation);     
    //Following line works perfect - but is not ASYNC 
    TableResult tableResult = this._storageTableBootstrapper.Table.Execute(insertOperation); 
} 
catch (Exception ex) 
{ 
    result.Result = false; 
    result.Errors.Add("AzurePostsStorageService Unexpected error: " + ex.Message); 
} 
return result; 
} 
+0

Come stai chiamando questo metodo? –

+0

Cosa intendi? Questo blocco di codice è in modalità asincrona, sto aggiornando la mia domanda per mostrare le linee circostanti. –

+0

Mostra la firma del metodo e come la chiami. Lo stai forse bloccando usando 'Task.Result' o' Task.Wait'? –

risposta

9

Il problema è qui:

Task.WaitAll(addPostTasks.ToArray()); 

Il tuo metodo asincrono cerca di schierare in sé di nuovo alla Contesto di sincronizzazione ASP.NET, bloccato perché è stata avviata una chiamata di blocco utilizzando Task.WaitAll.

Invece, è necessario seguire il asincrono tutta la strada modello e utilizzare Task.WhenAll, e su quel await:

await Task.WhenAll(addPostTasks.ToArray); 

Stephan Cleary elabora su questo nel suo blog (che @NedStoyanov aggiunto):

un altro punto importante: un contesto di richiesta ASP.NET è non legato ad uno specifico thread (come contesto UI è), ma fa solo consentire un thread alla volta. Questo aspetto interessante non è ufficialmente documentato ovunque AFAIK, ma è menzionato nell'articolo MSDN su SynchronizationContext.

+2

Buone informazioni sul contesto ASP, buono a sapersi. –

4

Questo è un classico deadlock causato da questa riga:

Task.WaitAll(addPostTasks.ToArray()); 

Prova a cambiarlo:

await Task.WhenAll(addPostTasks.ToArray()); 

Fondamentalmente le Task.WaitAll blocca il filo richiesta ed è in grado di eseguire il proseguimento del Tasks iniziata da await table.ExecuteAsync(...). Un'altra alternativa è utilizzare ConfigureAwait(false) nelle attività interne per evitare di passare a SynchronizatonContext.

await table.ExecuteAsync(...).ConfigureAwait(false); 

È possibile utilizzare ConfigureAwait(false) ogni volta che non si richiede per passare alla originale SynchronizationContext. Nel tuo caso, credo che tu possa farlo con tutto quello che ti aspetti mentre sei sul server e non dovrebbe importare se il codice dopo await viene eseguito nel pool di thread o meno.

veda questo articolo per maggiori informazioni: msdn.microsoft.com/enus/magazine/jj991977.aspx

+0

La tua risposta ha lo stesso significato di quella sopra, ma comunque tu dove prima Yuval Itzchakov ha fornito più informazioni. –

+0

Sì, la sua risposta era migliore. Ho imparato anche qualcosa. –

+0

OK, per essere chiari e capire meglio il caso. ** Consiglieresti di usare ".ConfigureAwait (false)" su tutte le nostre operazioni asincrone che sono all'inizio dello stack di esecuzione ** (come table.ExecuteAsync (...) o anche i nostri metodi/operazioni asincroni)? –