![](/img/trans.png)
[英]What is the correct way to cancel an async operation that doesn't accept a CancellationToken?
[英]Async/await with CancellationToken doesn't cancel the operation
我想使用CancellationToken
中止文件下載。 這是我嘗試的:
public async Task retrieveDocument(Document document)
{
// do some preparation work first before retrieving the document (not shown here)
if (cancelToken == null)
{
cancelToken = new CancellationTokenSource();
try
{
Document documentResult = await webservice.GetDocumentAsync(document.Id, cancelToken.Token);
// do some other stuff (checks ...)
}
catch (OperationCanceledException)
{
Console.WriteLine("abort download");
}
finally
{
cancelToken = null;
}
}
else
{
cancelToken.Cancel();
cancelToken = null;
}
}
public async Task<Document> GetDocumentAsync(string documentId, CancellationToken cancelToken)
{
Document documentResult = new Document();
try
{
cancelToken.ThrowIfCancellationRequested();
documentResult = await Task.Run(() => manager.GetDocumentById(documentId));
}
return documentResult;
}
cancelToken然后應用於取消操作:
public override void DidReceiveMemoryWarning ()
{
// Releases the view if it doesn't have a superview.
base.DidReceiveMemoryWarning ();
if (cancelToken != null) {
Console.WriteLine ("Token cancelled");
cancelToken.Cancel ();
}
}
似乎IsCancellationRequested
沒有更新。 因此操作不會被取消。 我也試圖用這個
cancelToken.ThrowIfCancellationRequested();
try{
documentResult = await Task.Run(() => manager.GetDocumentById (documentId), cancelToken);
} catch(TaskCanceledException){
Console.WriteLine("task canceled here");
}
但是什么都沒有改變。
我做錯了什么?
編輯:
以下是缺少的部分,例如GetDocumentById
:
public Document GetDocumentById(string docid)
{
GetDocumentByIdResult res;
try
{
res = ws.CallGetDocumentById(session, docid);
}
catch (WebException e)
{
throw new NoResponseFromServerException(e.Message);
}
return res;
}
public Document CallGetDocumentById(Session session, string parmsstring)
{
XmlDocument soapEnvelope = Factory.GetGetDocumentById(parmsstring);
HttpWebRequest webRequest = CreateWebRequest(session);
webRequest = InsertEnvelope(soapEnvelope, webRequest);
string result = WsGetResponseString(webRequest);
return ParseDocument(result);
}
static string WsGetResponseString(WebRequest webreq)
{
string soapResult = "";
IAsyncResult asyncResult = webreq.BeginGetResponse(null, null);
if (asyncResult.AsyncWaitHandle.WaitOne(50000))
{
using (WebResponse webResponse = webreq.EndGetResponse(asyncResult))
{
if (webResponse != null)
{
using (var rd = new StreamReader(webResponse.GetResponseStream()))
{
soapResult = rd.ReadToEnd();
}
}
}
}
else
{
webreq.Abort();
throw new NoResponseFromServerException();
}
return soapResult;
}
我想使用CancellationToken中止文件下載
下載文件是一項I / O操作,.NET平台上提供了異步可取消(基於I / O完成端口)功能。 但是您似乎並沒有使用它們。
相反,您似乎正在使用執行阻塞I / O的Task.Run
創建(一系列)任務,其中取消令牌沒有傳遞到Task.Run
鏈中的每個任務。
有關執行異步,等待和可取消文件下載的示例,請參考:
HttpClient
: 如何異步復制和取消HttpContent? WebClient
:有其自己的取消機制: CancelAsync方法,您可以使用令牌的Register方法將其連接到取消令牌: myToken.Register(myWebclient.CancelAsync);
您可以執行以下操作:
static async Task<string> WsGetResponseString(WebRequest webreq, CancellationToken cancelToken)`
{
cancelToken.Register(webreq.Abort);
using (var response = await webReq.GetResponseAsync())
using (var stream = response.GetResponseStream())
using (var destStream = new MemoryStream())
{
await stream.CopyToAsync(destStream, 4096, cancelToken);
return Encoding.UTF8.GetString(destStream.ToArray());
}
}
您的代碼在啟動GetDocumentAsync方法后僅調用ThrowIfCancellationRequested()
一次,這使得捕獲取消的窗口非常小。
您需要將CancellationToken
傳遞給GetDocumentById,並ThrowIfCancellationRequested
在操作之間調用ThrowIfCancellationRequested
,或者將令牌直接傳遞給較低級別的某些調用。
為了快速測試調用方法和CancellationToken
之間的關系,您可以將GetDocumentAsync
更改為:
cancelToken.ThrowIfCancellationRequested();
documentResult = await Task.Run(() => manager.GetDocumentById(documentId));
cancelToken.ThrowIfCancellationRequested();
並在創建CancellationTokenSource
之后立即調用CancelToken.CancelAfter(50)
或類似方法...您可能需要根據GetDocumentById
運行多長時間來調整值50。
[編輯]
根據您對問題的編輯,最快的解決方法是將CancelToken
向下傳遞給WsGetResponseString
並使用CancelToken.Register()
調用WebRequest.Abort()
。
您還可以使用CancelAfter()
來實現您的50秒超時,從BeginGetResponse..EndGetResponse
切換到GetResponseAsync
等。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.