我今天在「C# 開發實戰:非同步程式開發技巧」課程中有學員提問,如何偵測用戶端已斷線並自動取消非同步方法執行。事實上 ASP.NET (.NET Framework) 與 ASP.NET Core 的實作方式相當類似,今天這篇文章我就來分享 ASP.NET Core 的實作方式,幫助你有效偵測用戶端已斷線,並自動取消非同步方法執行。
在 ASP.NET Core 中,直接就有個 Request.HttpContext.RequestAborted 屬性可用,而這個屬性的型別恰恰就是 System.Threading.CancellationToken 結構,就是這麼佛心來著! 😍
由於幾乎所有的非同步方法,都有個 CancellationToken
參數可以傳入,今後你不需要特別建立一個 CancellationTokenSource 來自行管理取消非同步的判斷,直接把 Request.HttpContext.RequestAborted
拿去用即可。例如:
-
實作一個寫入 512MB 檔案,並在用戶端斷線的時候,立即停止寫入,並刪除寫入到一半的檔案
const string filePath = @"G:\big-file.log";
try
{
await System.IO.File.WriteAllTextAsync(filePath,
string.Join("", Enumerable.Repeat("A", 1024 * 1024 * 500)),
Request.HttpContext.RequestAborted);
}
catch (TaskCanceledException) when (System.IO.File.Exists(filePath))
{
System.IO.File.Delete(filePath);
}
上述 try/cache 的 when 是 C# 6.0 的例外篩選條件語法,當例外發生且條件成立(有檔案存在)才會刪除檔案。
-
透過 EF Core 5.0 寫入 100 萬筆資料,並在用戶端斷線的時候 Rollback 所有寫到一半的資料
由於 DbContext.SaveChangesAsync 方法本身就預設包含了交易處理,因此當 CancellationToken
進入取消狀態的時候,寫入到一半的交易就會自動 Rollback,不會殘留髒資料。
for (int i = 0; i < 1_000_000; i++)
{
var d = new Department();
d.InjectFrom(Department);
_context.Department.Add(d);
}
await db.SaveChangesAsync(Request.HttpContext.RequestAborted);
if (Request.HttpContext.RequestAborted.IsCancellationRequested)
{
// 如果你想在最後檢查用戶端是否斷線,如果斷線可以在這裡進行一些髒資料清理動作!
}
當 db.SaveChangesAsync()
這個 Task 被取消的時候會拋出 System.Threading.Tasks.TaskCanceledException 例外,不過由於使用者已經斷線,因此他也不可能看到任何錯誤訊息,但 ASP.NET Core 的 ILogger
會詳實的記錄到這個例外狀況,你可以視情況決定要不要隱藏這些記錄。
有了上述兩個例子,我想應該足以讓你應付所有類似的狀況! 😎
對了,如果你想在 ASP.NET MVC 或 ASP.NET Web API 實現類似機制,從 .NET Framework 4.5 開始,就有個 System.Web.HttpContext.Current.Response.ClientDisconnectedToken
可用,這個屬性的型別也是個 System.Threading.CancellationToken 結構,因此開發與使用的方式完全一樣!😍
如果是更早之前 .NET Framework 版本,也有個 HttpResponse.IsClientConnected 屬性可用。
相關連結