2015-01-28 8 views
5

Nun, mein Problem ist, dass Aufruf table.ExecuteAsync erwarten (...) auf Azure Storage Tabelle nicht die angeforderten Daten einfügen, aber nie beendet (gibt TableResult nicht zurück). Gleicher Fall mit den Operationen InsertOrUpdate und Update. Ich habe auch verschiedene Tabellen mit unterschiedlicher Anzahl von Eigenschaften ausprobiert - gleiches Problem. Wenn ich aufrufen table.Execute (...) - alles funktioniert gut für jede Art von Operation.Azure Storage Tables: erwarten table.ExecuteAsync (InsertOperation) führt, aber nie beendet

Hier ist mein Code - einfach:

Outer Aufruf (in MVC-Controller in Asynchron-Aktion gesetzt wird):

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()); 

Methode genannt:

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

Wie rufen Sie diese Methode? –

+0

Was meinst du? Dieser Codeblock ist in async Methode, ich aktualisiere meine Frage, um die umgebenden Linien zu zeigen. –

+0

Zeigen Sie die Methodensignatur und wie Sie sie aufrufen. Blockierst du es vielleicht mit 'Task.Result' oder' Task.Wait'? –

Antwort

9

Das Problem ist hier:

Task.WaitAll(addPostTasks.ToArray()); 

Ihre Asynchron-Methode versucht, sich auf den Rücken Marschall ASP.NET-Synchronisierungskontext, der blockiert ist, weil Sie einen blockierenden Anruf unter Verwendung von Task.WaitAll initiiert haben.

Stattdessen müssen Sie die async den ganzen Weg Muster folgen und verwenden Task.WhenAll und await dazu:

await Task.WhenAll(addPostTasks.ToArray); 

Stephan Cleary dazu in seinem Blog-Post erarbeitet (die @NedStoyanov hinzugefügt):

ein weiterer wichtiger Punkt: ein ASP.NET-Anforderungskontext ist nicht zu einem bestimmten Thread gebunden (wie der UI-Kontext ist), aber es macht nur erlauben ein Thread auf einmal. Dieser interessante Aspekt ist nicht offiziell dokumentiert überall AFAIK, aber es ist in meinem MSDN-Artikel über SynchronizationContext erwähnt.

+2

Gute Informationen über ASP-Kontext, gut zu wissen. –

4

Dies ist ein Klassische deadlock verursacht durch diese Linie:

Task.WaitAll(addPostTasks.ToArray()); 

versuchen, es zu ändern:

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

im Grunde die die Task.WaitAll blockiert den Anforderungsthread und es ist nicht in der Lage der Fortsetzung der Tasks durch await table.ExecuteAsync(...) initiiert auszuführen. Eine andere Alternative besteht darin, ConfigureAwait(false) für Ihre internen Aufgaben zu verwenden, um das Wechseln von SynchronizatonContext zu vermeiden.

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

können Sie verwenden ConfigureAwait(false), wenn Sie nicht auf den ursprünglichen SynchronizationContext wechseln müssen. In deinem Fall glaube ich, dass du das mit allen warten kannst, da du auf dem Server bist und es sollte egal sein, ob der Code nach await im Thread Pool ausgeführt wird oder nicht.

Lesen Sie diesen Artikel für weitere Informationen: msdn.microsoft.com/enus/magazine/jj991977.aspx

+0

Ihre Antwort hat die gleiche Bedeutung wie oben, aber wie auch immer Sie zuerst waren, Yuval Itzchakov hat weitere Informationen zur Verfügung gestellt. –

+0

Ja, seine Antwort war besser. Ich habe auch etwas gelernt. –

+0

OK, also klar sein und den Fall besser verstehen. ** Würden Sie empfehlen, ".ConfigureAwait (false)" für all unsere asynchronen Operationen zu verwenden, die sich am Anfang des Ausführungsstapels ** befinden (wie table.ExecuteAsync (...) oder sogar unsere eigenen asynchronen Operationen/Methoden)? –