2013-05-16 60 views
2

这是一个艰难的一个。使用完全相同的查询字符串,完全相同的下面的代码:DbConnection.Open()的作品,但dbConnection.OpenAsync()不

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

从Windows应用程序运行时会奏效。但是,当从IIS Express或IIS 7运行时,它将永久卡在await OpenAsync()中。如果我用db.Open()替换该行,它可以工作。有什么建议么?

+0

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

+0

@Andomar'await'不会阻止这样......不过是:如果有一些**调用**代码,调用'.Wait()'或'.Result',这将是一个问题 –

回答

5

正如其他人所说,首先要确保你有没有WaitResult调用您的层次结构。一个async方法链终止于依赖于框架的入口点。在UI/WebForms应用程序中,这通常是一个async void事件处理程序。在WebAPI/MVC应用程序中,这通常是一个async操作。其他

两件事情来检查ASP.NET是:

  • 确保您的目标平台是.NET 4.5。
  • 确保您已将UseTaskFriendlySynchronizationContext设置为true

如果您需要支持async在多个平台上的共享库,你会发现Microsoft.Bcl.Async的NuGet库是有帮助的。

4

await需要在ASP.NET中谨慎对待,因为同步上下文想要为单个请求序列化工作。您发布的代码本身可能很好 - await不会阻止。不过,我预计在此呼叫链的某个地方,您拨打.Wait()或访问.Result,而不是await

有几个选择这里:

  • 完全不使用.Wait().Result(或类似)- 相反,只使用await并使其正确异步操作
  • 或,使用.ConfigureAwait(false)来告诉它忽略sync-context;不幸的是,这将需要添加到所有的地方,你await,即

    await db.OpenAsync().ConfigureAwait(false); 
    var results = await db.ExecuteSomethingAsync(...).ConfigureAwait(false); 
    
  • ,或者只使用同步码 - 在大多数情况下,SQL是要快速运行非常 - 所以推它异步是不一定帮助尽可能多的,你可能会想;显然这可能会因使用情况而异;但一个关键点要记住这里的是,ASP.NET已经固有的线程 - 这是不是因为虽然整个服务器研在这里停了下来

+0

谢谢,我要检查这些选项。这段代码不仅仅被我的asp.net解决方案所使用,所以我不能只考虑这个特定的场景来编写它。 –

+0

虽然有一个问题,如果我不能使用.Wait()或.Result,我怎么能捕获这些异步方法之一的调用方法,而不是异步本身的结果?换句话说,如何正确结束异步链? –

+0

@LuisFerrao“通过异步同步” - 是的,基本上不能保证很好地播放。有2个答案:a)添加大量'ConfigureAwait'; b)不这样做 - 或者c)(是的,我知道我说过2!) - * make *调用方法async –

0

我注意到在ASP.Net Web Forms代码隐藏中编写async/await代码时要记住的另一个重点,那就是在页面声明中确保Async =“true”。该属性默认为false。

如果你不这样做,那么你可以看到你的网页处于永久加载状态。

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

此外,在.NET 4.5,根据斯蒂芬的答案,我们需要有“UseTaskFriendlySynchronizationContext”在web配置appSettings部分设置为true。另一个有用的应用程序是AllowAsyncDuringSyncStages对于Webforms代码隐藏中的异步/等待代码,它需要为false。这些设置默认都是假的。

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

我有下面的示例异步/在一个ASP.Net Web窗体跑很快使用上述的设置和使用的await通过斯蒂芬的建议一路等待代码。如果没有遵循这些建议,那么您可以在浏览器中永久加载Webforms页面。

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

不确定这适用于我,因为我使用asp.net mvc –

+0

您可以Webforms中的异步事件处理程序可以使用异步控制器操作。你也可以在这个URL看到MVC中的异步控制器动作的答案:http://stackoverflow.com/questions/20227401/using-await-taskt-async-hangs-controller-in-mvc-app – Sunil

相关问题