【发布时间】:2015-05-05 13:02:35
【问题描述】:
我想使用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;
}
【问题讨论】:
-
我不太明白你想做什么。 在开始之前调用 ThrowIfCancellationRequested,这不太可能做任何事情。您需要在为其工作的代码中定期调用它才能运行。例如,在循环内。
-
当我使用
Task.Delay而不是webservice.GetDocumentAsync时无法重现该问题。因此,可能该服务调用或后面的代码 (do some other stuff) 不完全支持协作任务取消。 -
GetDocumentById是做什么的?如果您在GetDocumentById开始执行后取消令牌,则不会有人注意到它,因为它没有被监控。 -
@svinja 说的是对的,这是一个很难掌握的概念。
ThrowIfCancellationRequested没有设置选项,它检查令牌,如果设置,它会抛出错误。您需要定期调用它以引发异常,因为该调用实际上是引发它的原因。 -
@svinja:对于我的示例,这样的循环会是什么样子?我看到其他人使用
while(true),但我不知道使用它是否是个好主意。
标签: c# async-await cancellationtokensource