2013-05-16 6 views
2

Ceci est difficile. En utilisant exactement la même chaîne de requête, exactement le même code suivant:DbConnection.Open() fonctionne mais dbConnection.OpenAsync() ne fonctionne pas

using (var db = new SqlConnection(queryString)) 
{ 
    await db.OpenAsync(); 
    var results = await db.ExecuteSomethingAsync...; 
    db.Close(); 
{ 

fonctionne quand a couru à partir d'une application Windows. Il sera cependant coincé pour toujours dans await OpenAsync() lorsqu'il est exécuté à partir d'IIS Express ou d'IIS 7. Si je remplace cette ligne par db.Open() cela fonctionne cependant. Aucune suggestion?

+0

http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html – Andomar

+0

@Andomar 'await' ne bloque pas en tant que telle ... mais oui: si il y a un ** appel ** code qui appelle '.Wait()' ou '.Result', ce sera un problème –

Répondre

5

Comme d'autres l'ont mentionné, d'abord vous assurer d'avoir pas Ou Result appelle votre hiérarchie. Une chaîne de méthodes async se termine à un point d'entrée qui dépend de la structure. Dans une application UI/WebForms, il s'agit généralement d'un gestionnaire d'événements async void. Dans une application WebAPI/MVC, il s'agit généralement d'une action async.

Deux autres choses à vérifier pour ASP.NET sont:

  • Garantissez votre plate-forme cible est de 4,5 .NET.
  • Vérifiez que UseTaskFriendlySynchronizationContext est défini sur true.

Si vous avez besoin pour soutenir async dans une bibliothèque partagée sur plusieurs plates-formes, vous trouverez peut-être la bibliothèque NuGet Microsoft.Bcl.Async être utile.

4

await doit être traité avec précaution dans ASP.NET, à cause de la manière dont le contexte de synchronisation veut sérialiser le travail pour une seule requête. Le code que vous postez est probablement bien en soi - le await ne va pas bloquer. Cependant, je m'attends à ce que quelque part dans la chaîne d'appel pour cela, vous appelez .Wait() ou l'accès .Result, plutôt que await.

Il y a quelques options:

  • ne pas utiliser .Wait() ou .Result (ou similaire) du tout - au lieu, utilisez uniquement await et faire une action correctement async
  • ou , utilisez .ConfigureAwait(false) pour lui indiquer d'ignorer le contexte de synchronisation; malheureusement, cela devrait être ajouté à tous les endroits que vous await, à savoir

    await db.OpenAsync().ConfigureAwait(false); 
    var results = await db.ExecuteSomethingAsync(...).ConfigureAwait(false); 
    
  • ou, il suffit d'utiliser le code de synchronisation - dans la plupart des cas, le sql va fonctionner très rapidement - afin de pousser il async est pas nécessairement aidant autant que vous pourriez le penser; de toute évidence, cela peut varier entre les utilisations; mais un point clé à garder à l'esprit est que ASP.NET est déjà intrinsèquement enfilée - il est pas comme si l'ensemble du serveur enraye ici

+0

Merci, je vais vérifier ces options. Ce code n'est pas seulement utilisé par ma solution asp.net, donc je ne peux pas l'écrire avec ce scénario spécifique en tête. –

+0

Une question cependant, si je ne peux pas utiliser .Wait() ou .Result, comment puis-je capturer le résultat d'une de ces méthodes asynchrones dans une méthode d'appel qui n'est pas asynchrone? Ou en d'autres termes, comment mettre fin correctement à une chaîne asynchrone? –

+0

@LuisFerrao "sync over async" - ouais, fondamentalement, ce n'est pas garanti de bien jouer. Il y a 2 réponses: a) ajouter beaucoup de 'ConfigureAwait'; b) ne faites pas cela - ou c) (oui, je sais que j'ai dit 2!) - * make * la méthode d'appel async –

0

J'ai remarqué un autre point important à garder à l'esprit lors de l'écriture du code asynchrone/attendu dans le code-behind ASP.Net Web Forms, à savoir que Async = "true" dans la déclaration de page. Cet attribut est false par défaut.

Si vous ne le faites pas, vous pouvez voir votre page dans un état de chargement permanent.

<%@ Page Language="C#" Async="true" %> 

également, en .Net 4.5, selon la réponse par Stephen nous devons avoir 'UseTaskFriendlySynchronizationContext' définie sur true dans la section AppSettings de configuration Web. Un autre appsetting utile est AllowAsyncDuringSyncStages qui doit être false pour le code async/await dans le code-behind Webforms. Ces paramètres sont tous les deux faux par défaut.

<add key="aspnet:AllowAsyncDuringSyncStages" value="false" /> 
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/> 

J'ai eu l'exemple suivant async/code dans un attendent WebForm ASP.Net qui a couru très rapidement en utilisant les paramètres ci-dessus et en utilisant await tout le chemin à travers comme suggéré par Stephen. Si ces recommandations ne sont pas suivies, vous pouvez voir la page Webforms en cours de chargement dans le navigateur.

protected async void Page_Load(object sender, EventArgs e) 
{ 
    if (!Page.IsPostBack) 
    { 
     string sql = @"DELETE FROM dbo.Table1 
         WHERE Processed = 1"; 
     SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["MainDB"].ConnectionString); 
     SqlCommand cmd = new SqlCommand(sql, conn); 
     int numberOfRecordsUpdated = await UpdateDatabaseAsync(conn, cmd); 
    } 
} 
public async Task<int> UpdateDatabaseAsync(SqlConnection conn, SqlCommand cmd) 
{ 
    int i = 0; 
    try 
    { 
     await conn.OpenAsync(); 
     i = await cmd.ExecuteNonQueryAsync(); 
    } 
    catch (Exception ex) 
    { 
     //log the error 
     Elmah.ErrorSignal.FromCurrentContext().Raise(ex); 
    } 

    finally 
    { 
     if (conn != null) 
     { 
      conn.Close(); 
      conn.Dispose(); 
     } 
     if (cmd != null) 
     { 
      cmd.Dispose(); 
     } 
    } 
    return i; 
} 
+0

Pas sûr que cela s'applique à moi car j'utilise asp.net mvc –

+0

Vous pouvez, mais au lieu de gestionnaire d'événements asynchrone dans Webforms, vous utiliseriez des actions de contrôleur asynchrone. Vous pouvez également voir une réponse sur l'action du contrôleur async dans MVC à cette adresse: http://stackoverflow.com/questions/20227401/using-await-taskt-async-hangs-controller-in-mvc-app – Sunil

Questions connexes