使用CancellationToken进行异步/等待不会取消操作 [英] Async/await with CancellationToken doesn't cancel the operation
问题描述
我想使用 CancellationToken
中止文件下载.这是我尝试过的:
I want to use the CancellationToken
to abort a file download. This is what I tried:
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 然后应用于取消操作:
The cancelToken should then be used to cancel the operation:
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
没有更新.因此操作不会被取消.我也试图用这个
It seems that IsCancellationRequested
is not updated. So the operation is not cancelled. I also tried to use this
cancelToken.ThrowIfCancellationRequested();
try{
documentResult = await Task.Run(() => manager.GetDocumentById (documentId), cancelToken);
} catch(TaskCanceledException){
Console.WriteLine("task canceled here");
}
但没有任何改变.
我做错了什么?
以下是缺少的部分,例如 GetDocumentById
:
Here are the missing parts like 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 want to use the CancellationToken to abort a file download
下载文件是一项I/O操作,.NET平台上提供了异步可取消(基于I/O完成端口)功能.但是您似乎并没有使用它们.
Downloading a file is an I/O operation, for which asynchronous cancelable (I/O completion port based) functions are available on the .NET platform. Yet you seem to not be using them.
相反,您似乎正在使用 Task.Run
创建(一系列)任务,这些任务执行阻止I/O,其中取消令牌没有传递给 Task中的每个任务.运行
链.
Instead you appear to be creating (a chain of) tasks using Task.Run
that perform blocking I/O, where a cancelation token is not passed on to each task in your Task.Run
chain.
有关进行异步,可等待和可取消的文件下载的示例,请参阅:
For examples of doing async, awaitable and cancelable file downloads, refer to:
- 使用
HttpClient
:在Windows Phone 8中下载并保存异步文件 - 使用
WebClient
:具有自己的取消机制:注册方法:
- Using
HttpClient
: How to copy HttpContent async and cancelable? - Windows Phone: Downloading and saving a file Async in Windows Phone 8
- Using
WebClient
: Has its own cancellation mechanism: the CancelAsync method, you can connect it to your cancellation token, using the token's Register method:
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());
}
}
这篇关于使用CancellationToken进行异步/等待不会取消操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!