繁体   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