And*_*rew 13 c# using async-await
我在C#中有以下异步函数:
private async Task<T> CallDatabaseAsync<T>(Func<SqlConnection, Task<T>> execAsync)
{
using (var connection = new SqlConnection(_connectionString))
{
connection.Open();
return await execAsync(connection);
}
}
Run Code Online (Sandbox Code Playgroud)
它允许执行任何异步函数execAsync,它将SQL连接作为参数并通过提供连接对象并确保它将被正确关闭来使用它来进行数据库调用.
然后从WebApi控制器中的操作调用此函数,如下所示:
public async Task<HttpResponseMessage> MyAction()
{
Func<SqlConnection, Task<SomeType>> execAsync = (function definition here);
await CallDatabaseAsync(execAsync);
return Request.CreateResponse(HttpStatusCode.OK);
}
Run Code Online (Sandbox Code Playgroud)
这一切都很有效,直到我对WebApi操作进行了一次更改:我从中删除了异步/等待.我不想等待数据库调用,因为我不关心结果,我只是想解雇并忘记.
这仍然似乎工作正常 - 即如果我在浏览器中导航到操作的URL我没有得到任何错误.但实际上有一个问题 - 数据库连接没有关闭.在100次调用操作后,连接池达到其默认限制100,并且应用程序停止工作.
我究竟做错了什么?我需要在CallDatabaseAsync()中进行哪些更改,以便绝对确保连接将被关闭,无论如何?
Yac*_*sad 13
在ASP.NET中,每个请求都有一个特殊的SynchronizationContext.此同步上下文使得在await使用原始请求的相同"上下文" 之后运行的代码.例如,如果await访问当前HttpContext后的代码,它将访问HttpContext属于同一ASP.NET请求的代码.
当请求终止时,该请求的同步上下文将随之消失.现在,当异步数据库访问完成时,它会尝试使用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);
}
}
Run Code Online (Sandbox Code Playgroud)