2013-05-16 84 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

相關問題