簡體   English   中英

內部異步使用塊

[英]Async inside Using block

我在C#中有以下異步函數:

private async Task<T> CallDatabaseAsync<T>(Func<SqlConnection, Task<T>> execAsync)
{
    using (var connection = new SqlConnection(_connectionString))
    {
        connection.Open();
        return await execAsync(connection);
    }
}

它允許執行任何異步函數execAsync ,它將SQL連接作為參數並通過提供連接對象並確保它將被正確關閉來使用它來進行數據庫調用。

然后從WebApi控制器中的操作調用此函數,如下所示:

public async Task<HttpResponseMessage> MyAction()
{
    Func<SqlConnection, Task<SomeType>> execAsync = (function definition here);
    await CallDatabaseAsync(execAsync);
    return Request.CreateResponse(HttpStatusCode.OK);
}

這一切都很有效,直到我對WebApi操作進行了一次更改:我從中刪除了異步/等待。 我不想等待數據庫調用,因為我不關心結果,我只是想解雇並忘記。

這仍然似乎工作正常 - 即如果我在瀏覽器中導航到操作的URL我沒有得到任何錯誤。 但實際上有一個問題 - 數據庫連接沒有關閉。 在100次調用操作后,連接池達到其默認限制100,並且應用程序停止工作。

我究竟做錯了什么? 我需要在CallDatabaseAsync()中進行哪些更改,以便絕對確保連接將被關閉,無論如何?

在ASP.NET中,每個請求都有一個特殊的SynchronizationContext 此同步上下文使得在await之后運行的代碼使用原始請求的相同“上下文”。 例如,如果await之后的代碼訪問當前的HttpContext ,它將訪問屬於同一ASP.NET請求的HttpContext

當請求終止時,該請求的同步上下文將隨之消失。 現在,異步數據庫訪問完成時,它會嘗試使用SynchronizationContext ,它捕獲的之前await運行后的代碼await (其中包括部署SQL連接的代碼),但它無法找到它了,因為請求已經終止。

在這種情況下你可以做的是使await之后的代碼不依賴於當前的ASP.NET請求的SynchronizationContext ,而是在線程池線程上運行。 您可以通過ConfigureAwait方法執行此操作,如下所示:

private async Task<T> CallDatabaseAsync<T>(Func<SqlConnection, Task<T>> execAsync)
{
    using (var connection = new SqlConnection(_connectionString))
    {
        connection.Open();
        return await execAsync(connection).ConfigureAwait(false);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM