Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 异步内部使用块_C#_Async Await_Using - Fatal编程技术网

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控制器中的操作调用此函数,

我在C#中有以下异步函数:

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);
    }
}