C# 异步内部使用块
我在C#中有以下异步函数:C# 异步内部使用块,c#,async-await,using,C#,Async Await,Using,我在C#中有以下异步函数: private async Task CallDatabaseAsync(Func execAsync) { 使用(var connection=newsqlconnection(_connectionString)) { connection.Open(); 返回等待执行异步(连接); } } 它允许执行任何异步函数execAsync,该函数将SQL连接作为参数并使用它进行数据库调用,方法是提供连接对象并确保其正确关闭 然后从WebApi控制器中的操作调用此函数,
private async Task CallDatabaseAsync(Func execAsync)
{
使用(var connection=newsqlconnection(_connectionString))
{
connection.Open();
返回等待执行异步(连接);
}
}
它允许执行任何异步函数execAsync,该函数将SQL连接作为参数并使用它进行数据库调用,方法是提供连接对象并确保其正确关闭
然后从WebApi控制器中的操作调用此函数,如下所示:
public async Task<HttpResponseMessage> MyAction()
{
Func<SqlConnection, Task<SomeType>> execAsync = (function definition here);
await CallDatabaseAsync(execAsync);
return Request.CreateResponse(HttpStatusCode.OK);
}
公共异步任务MyAction()
{
Func execAsync=(此处为函数定义);
等待CallDatabaseAsync(execAsync);
返回Request.CreateResponse(HttpStatusCode.OK);
}
这一切都很好,直到我对WebApi操作做了一个更改:从中删除async/await。我不想等待数据库调用,因为我不关心结果,我只想启动并忘记
这似乎仍然可以正常工作-即,如果在浏览器中导航到操作的URL,则不会出现任何错误。但实际上有一个问题——数据库连接没有关闭。对操作调用100次后,连接池达到其默认限制100,应用程序停止工作
我做错了什么?在CallDatabaseAsync()中我需要更改什么,以确保无论发生什么情况,连接都会被关闭?在ASP.NET中,每个请求都有一个特殊的属性。此同步上下文使在
wait
之后运行的代码使用与原始请求相同的“上下文”。例如,如果wait
之后的代码访问当前请求,它将访问属于同一ASP.NET请求的HttpContext
当请求终止时,该请求的同步上下文也随之终止。现在,当异步数据库访问完成时,它尝试使用在wait
之前捕获的SynchronizationContext
在wait
之后运行代码(其中包括处理SQL连接的代码),但由于请求已终止,它无法再找到它
在这种情况下,您可以做的是使等待后的代码不依赖于当前ASP.NET请求的SynchronizationContext
,而是在线程池线程上运行。您可以通过以下方法执行此操作:
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);
}
}
private async Task CallDatabaseAsync(Func execAsync)
{
使用(var connection=newsqlconnection(_connectionString))
{
connection.Open();
返回await execAsync(连接).ConfigureAwait(false);
}
}
你确定是那个连接没有被关闭吗?@PauloMorgado非常确定。所有数据库调用都通过CallDatabaseAsync()进行,这个特定的控制器操作调用CallDatabaseAsync()只有一次。您可以显示删除async
和await
后您的操作方法的外观吗?您可以显示execAsync
?我不想等待数据库调用,因为我不关心结果,我只想触发并忘记。
-这几乎肯定是错误的。您是否知道ASP.NET上的“启动并忘记”实际上意味着“我不在乎此代码是否实际运行”?谢谢Yacoub。我的一位同事向我提出了同样的建议,并准确地解释了你在回答中所说的话。我对它进行了测试,它确实按预期工作,连接总是关闭的。将此标记为正确答案。
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);
}
}