我正在尝试将 CancellationToken 与 SqlConnection.OpenAsync() 结合使用来限制 OpenAsync 函数所花费的时间。
我创建了一个新的 CancellationToken 并将其设置为在 200 毫秒后取消。然后我将它传递给 OpenAsync(token)。然而,此功能仍可能需要几秒钟才能运行。
查看文档我真的看不出我做错了什么。 https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlconnection.openasync?view=netframework-4.7.2
这是我使用的代码:
private async void btnTestConnection_Click(object sender, EventArgs e)
{
SqlConnection connection = new SqlConnection(SQLConnectionString);
Task.Run(() => QuickConnectionTest(connection)).Wait();
}
public async Task QuickConnectionTest(SqlConnection connection)
{
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token;
source.CancelAfter(200);
ConnectionOK = false;
try
{
using (connection)
{
await connection.OpenAsync(token);
if (connection.State == System.Data.ConnectionState.Open)
{
ConnectionOK = true;
}
}
}
catch (Exception ex)
{
ErrorMessage = ex.ToString();
}
}
当 CancellationToken 在 200 毫秒过去时抛出 OperationCanceledException 但它只是等待时,我期待 OpenAsync() 提前结束。
为了复制这个,我做了以下事情:
最佳答案
你的代码对我来说似乎是正确的。如果这没有按预期执行取消,则 SqlConnection.OpenAsync
不支持可靠取消。取消是合作的。如果它没有得到适当的支持,或者存在错误,那么您将无法得到任何保证。
尝试升级到最新的 .NET Framework 版本。您也可以尝试 .NET Core,它似乎领先于 .NET Framework。我关注 GitHub 存储库,发现了多个与异步相关的 ADO.NET 错误。
您可以在超时后尝试调用 SqlConnection.Dispose()
。也许那行得通。您也可以尝试使用同步 API (Open
)。也许那使用了不同的代码路径。我相信它不会,但值得一试。
如果这不起作用,您需要编写代码,以便即使连接任务尚未完成,您的逻辑也会继续。假装它已经完成,让它在后台徘徊,直到它自己完成。这可能会导致资源使用量增加,但可能没问题。
无论如何,请考虑在 GitHub corefx 存储库中以最少的重现(例如 5 行连接到 example.com)打开一个问题。这应该可以正常工作。
关于C# CancellationToken 如何与 SqlConnection.OpenAsync(token) 一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54150514/