筆記下 CancellationToken 的一些東西
介紹
ICancellationTokenProvider
使用 ABP 提供的 ICancellationTokenProvider
public class TestAppService : ProjectNameAppService
{
private readonly TestManager _manager;
private readonly ICancellationTokenProvider _cancellationTokenProvider;
public TestAppService(TestManager manager, ICancellationTokenProvider cancellationTokenProvider)
{
_manager = manager;
_cancellationTokenProvider = cancellationTokenProvider;
}
public async Task<int> GetAsync()
{
return await _manager.GetTestDataAsync(cancellationToken: _cancellationTokenProvider.Token);
}
}
通常,應將 CancellationToken
傳遞給方法的參數以使用它。
有了 ICancellationTokenProvider
您無需為每種方法傳遞。
可以使用依賴項注入進行注入,並從其來源提供令牌。
P.S. 例如 API 則為 Request.HttpContext.RequestAborted
Cancellation Token Provider | Documentation Center | ABP.IO
CancellationToken
原本每個 API 方法要傳入 CancellationToken
public class TestAppService : ProjectNameAppService
{
private readonly TestManager _manager;
public TestAppService(TestManager manager)
{
_manager = manager;
}
public async Task<int> GetAsync(CancellationToken cancellationToken = default)
{
return await _manager.GetTestDataAsync(cancellationToken: cancellationToken);
}
}
[ASP.NET Web API 2] 通過 CancellationToken 取消非同步請求 | 余小章 @ 大內殿堂 - 點部落 (dotblogs.com.tw)
Request.HttpContext.RequestAborted
.Net 本身有個 Request.HttpContext.RequestAborted
可以用
public class TestAppService : ProjectNameAppService
{
private readonly TestManager _manager;
public TestAppService(TestManager manager)
{
_manager = manager;
}
public async Task<int> GetAsync()
{
return await _manager.GetTestDataAsync(cancellationToken: Request.HttpContext.RequestAborted);
}
}
ASP.NET 與 ASP․NET Core 偵測用戶端已斷線並自動取消非同步方法執行 | The Will Will Web (miniasp.com)
測試
模擬一項作業預計花費一分鐘完成
public async Task<int> GetAsync()
{
const int max = 60;
var curr = 0;
for (; curr < max; curr++)
{
if (_cancellationTokenProvider.Token.IsCancellationRequested)
{
Console.WriteLine("IsCancellationRequested {0}", curr);
break;
}
await Task.Delay(1000);
}
Console.WriteLine("Current: {0}", curr);
return curr;
}
假設有 if (_cancellationTokenProvider.Token.IsCancellationRequested)
使用 Swagger 呼叫該 API 9s 後將該頁面關閉
會發現的 LOG 顯示該 Request 費時約 9s

反之即使提前關閉畫面還是需要消耗 60s 來完成該 API 呼叫

結論
由此可知如果有將 CancellationToken 傳遞給該 API 所使用的非同步方法
EF ToListAsync, HttpClinet RequestAsync, Stream ReadAsync, Blob SaveAsync…ETC.
則可以在使用者提前取消 Request 時,節省消耗資源並提前完成該要求
