使用CancellationToken进行异步/等待不会取消操作 [英] Async/await with CancellationToken doesn't cancel the operation

查看:148
本文介绍了使用CancellationToken进行异步/等待不会取消操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用 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:

  • 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);

  • 使用抽象的WebRequest :如果它不是使用附加的取消令牌创建的,就像您编辑的示例一样,并且您实际上并没有下载文件,而是在阅读内容字符串,则需要结合使用前面提到的几种方法.
  • Using the abstract WebRequest: If it was not created using an attached cancelation token, as seems to be the case for your edited example, and you are not actually downloading a file, but reading a content string, you need to use a combination of a few of the earlier mentioned methods.
  • 您可以执行以下操作:

    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屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆