如果一個Controller.Action里的處理非常耗時,比如讀資料庫、文件操作、調用第三方介面等此時用戶隨時可能關閉瀏覽器、F5刷新網頁等操作。但是服務端的耗時代碼任然在執行,這太浪費了,既然用戶終止請求了,我們就應該取消所有的耗時操作 在.net開發中,幾乎所有的非同步方法都有個Cancella ...
如果一個Controller.Action里的處理非常耗時,比如讀資料庫、文件操作、調用第三方介面等
此時用戶隨時可能關閉瀏覽器、F5刷新網頁等操作。
但是服務端的耗時代碼任然在執行,這太浪費了,既然用戶終止請求了,我們就應該取消所有的耗時操作
在.net開發中,幾乎所有的非同步方法都有個CancellationToken類型的參數,只要我們傳入此令牌,將來我們隨時可以通過此令牌取消非同步操作
而asp.net中HttpContext提供了一個RequestAborted屬性,它就是CancellationToken類型,當用戶以任何方式終止請求時, HttpContext.RequestAborted就會觸發取消
所以如果我們在非同步方法中都傳入這個參數,就能實現當用戶終止請求時,我們所有的非同步操作都會立即取消
併發大的情況下,這個操作很重要。
參考代碼:
1 public async Task<ActionResult> TestAsync() 2 { 3 await System.IO.File.ReadAllTextAsync(@"d:\a.txt", HttpContext.RequestAborted); 4 //....略
上面是asp.net預設行為,你會發現一個問題,真個應用程式有鋪天蓋地的非同步方法,如果都想實現上述特征 我們所有的非同步方法都得加上CancellationToken參數
abp提供了一種牛X的方式
它提供一個ICancellationTokenProvider介面,它會為我們提供一個CancellationToken對象,所以我們定義的非同步方法不需要定義CancellationToken參數了,首先在我們的類中依賴註入這個介面,然後在調用.net內置庫或第三方庫的非同步方法時,傳入ICancellationTokenProvider.Token就可以了,如下:
1 ICancellationTokenProvider CancellationTokenProvider ; 2 3 //構造函數註入CancellationTokenProvider 略... 4 5 public override async Task<List<TEntity>> GetAllListAsync() 6 { 7 return await GetAll().ToListAsync(CancellationTokenProvider.Token); 8 }
比較推薦的是使用“空模式”,用屬性註入,如下:
1 public ICancellationTokenProvider CancellationToken { get; set; } = NullCancellationTokenProvider.Instance;
abp中最終使用的是HttpContextCancellationTokenProvider,它的Token屬性返回的就是HttpContext.RequestAborted
預設情況下abp的Repository中的所有非同步方法已經使用這種模式,由於我們開發是大部分情況下都是資料庫讀寫,所以我們在abp中幾乎可以不關心這事,預設就是以合理的方式運行的。
但有時候我們需要做其它非同步操作,比如調用第三方介面啥的,此時就需要通過上面的方式來實現這種 用戶取消請求則所以非同步操作理解取消的效果。
在某些場景中我們可能並不想用這種預設的行為,而是希望傳入自己的CancellationToken對象,而不是用HttpContext的。這是我估計ICancellationTokenProvider.Use就派上用場了。怎麼用呢?