我讀documentation for DbConnection.OpenAsync(CancellationToken)
,發現下面的代碼片段:爲什麼DbConnection.OpenAsync(CancellationToken)的默認實現是同步的?
的默認實現調用同步Open調用和返回完成的任務。如果傳遞一個已經取消的cancellationToken,默認實現將返回一個取消的任務。 Open引發的異常將通過返回的Task Exception屬性進行通信。現在
,如果我是一個參差不齊/慢速網絡連接,並使用尚未覆蓋DbConnection.OpenAsync(CancellationToken)
(即我用比其他System.Data.SqlClient
東西),和如果我屁股那到數據庫提供商一個UI按鈕的事件處理程序,如:基於我引用,如果連接了足夠長的時間才能完成,我的表是「(無響應)」的文件上(假設的代碼,未經測試)
async void button1_Clicked(object sender, EventArgs e)
{
using (var connection = MyProviderFactory.CreateConnection())
{
button1.Text = "Opening…";
connection.ConnectionString = _SomeString;
try
{
await connection.OpenAsync(); // Convenience wrapper around OpenAsync(CancellationToken)
button1.Text = "Opened successfully!";
}
catch (Exception ex)
{
button1.Text = ex.Message;
}
}
}
而連接如果提供者沒有重寫默認實現,則正在建立。爲了防止這種情況發生,無論底層數據庫提供者如何,我不妨做await Task.Run(async() => await connection.OpenAsync());
。爲什麼採用這種方式實現默認實現,以及如何在不編寫提供程序感知代碼的情況下知道何時需要Task.Run()
?
這種隱式事務管理API看起來使用起來很危險,並且喜歡某些事情以避免對我... – binki
啊,我明白了,你是說因爲某些提供程序在打開連接時使用線程本地存儲,所以' DbConnection' *不能*安全地使用線程池來使它立即返回。 – binki
@binki就像在Transaction.Current文檔中說的那樣,你通常不直接使用它。你使用'TransactionScope'來管理它,然後它變成一個非常有用的機制。連接類本身直接使用'Transaction.Current',如果在後臺線程上調用,則不會看到預期的值。我沒有提到使用線程本地存儲的連接類本身(我只想到其他類),但是你是對的,那是另一種有效的可能性。 – hvd