如何取消Windows Phone中的异步调用?

时间:2014-03-07 09:50:35

标签: windows-phone-8 windows-phone task async-await

我有一个列表,每次用户进行研究时都会加载元素...这些元素包含一个Icon,它使用HttpClient对象的异步方法GetByteArrayAsync下载。
当用户进行第二次研究而第一个列表的图标仍在下载时,我遇到了一个问题。因为图标下载正在处理第一个列表的每个元素时元素列表正在变化。
所以我的猜测是每次用户进行新的研究时我都需要取消这些请求...我已经在Task.run和CancellationTokenSource上找到了一些stuuf,但我找不到真正有用的示例,所以这里是我的代码... ...希望你能帮助我...谢谢你

   
public static async Task<byte[]> DownloadElementFile(BdeskElement bdeskElement)
{
    //create and send the request

    DataRequest requesteur = new DataRequest();

    byte[] encryptedByte = await requesteur.GetBytesAsync(dataRequestParam);

    return encryptedByte;
}


public async Task<Byte[]> GetBytesAsync(DataRequestParam datarequesparam)
{
    var handler = new HttpClientHandler { Credentials = new NetworkCredential(datarequesparam.AuthentificationLogin, datarequesparam.AuthentificationPassword, "bt0d0000") };
    HttpClient httpClient = new HttpClient(handler);

    try
    {
        byte[] BytesReceived = await httpClient.GetByteArrayAsync(datarequesparam.TargetUri);

        if (BytesReceived.Length > 0)
        {
            return BytesReceived;
        }

        else
        {
            return null;

        }
    }
    catch (WebException)
    {
        throw new MyException(MyExceptionsMessages.Webexception);
    }

}

修改

public async Task<Byte[]> GetBytesAsync(DataRequestParam datarequesparam)
        {
            var handler = new HttpClientHandler { Credentials = new NetworkCredential(datarequesparam.AuthentificationLogin, datarequesparam.AuthentificationPassword, "bt0d0000") };
            HttpClient httpClient = new HttpClient(handler);

            try
            {
                cts = new CancellationTokenSource();

                HttpResponseMessage reponse = await httpClient.GetAsync(datarequesparam.TargetUri,cts.Token);

               if (reponse.StatusCode == HttpStatusCode.OK)
               {
                   byte[] BytesReceived = reponse.Content.ReadAsByteArrayAsync().Result;

                   if (BytesReceived.Length > 0)
                   {
                       return BytesReceived;
                   }

                   else
                   {
                       return null;

                   }
               }

               else
               {
                   return null;
               }

            }
            catch (WebException)
            {
                throw new MyException(MyExceptionsMessages.Webexception);
            }
              catch(OperationCanceledException)
            {
                  throw new OperationCanceledException();
            }

EDIT2 当用户进行新的研究并且列表“listBoxGetDocsLibs”发生变化时,我需要取消此功能。

 private async void LoadIconDocLibs()
        {

            foreach (var doclib in listBoxGetDocsLibs)//ERROR HERE COLLECTION HAS CHANGED
            {

                doclib.Icon = new BitmapImage();


                    try
                    {

                        byte[] Icon = await ServerFunctions.GetDocLibsIcon(doclib);

                        if (Icon != null)
                        {
                            {

                                var ms = new MemoryStream(Icon);

                                BitmapImage photo = new BitmapImage();
                                photo.DecodePixelHeight = 64;
                                photo.DecodePixelWidth = 92;
                                photo.SetSource(ms);
                                doclib.Icon = photo;
                            }
                        }
                    }
                    catch(OperationCanceledException)
                    {

                    }
                }


        }

1 个答案:

答案 0 :(得分:2)

首先,您需要定义CancellationTokenSource

private System.Threading.CancellationTokenSource cts;

将代码置于某处,您可以使用Button或其他方法访问代码。

不幸的是GetByteArrayAsync缺少取消 - 所以它不能与cts.Token一起使用,但也许你可以使用GetAsync来完成你的任务 - 它支持取消:

ctsDownload = new System.Threading.CancellationTokenSource();
HttpResponseMessage response = await httpClient.GetAsync(requestUri, cts.Token);

然后,您可以从回复中获取您的内容。

当您想要取消任务时,它可能如下所示:

private void cancelBtn_Click(object sender, RoutedEventArgs e)
{
   if (this.cts != null)
       this.cts.Cancel();
}

当您取消任务时,将抛出异常。

如果你想取消自己的异步任务,你可以找到一个很好的例子at Stephen Cleary blog

编辑 - 您还可以构建自己的方法(例如使用HttpWebRequest),它将支持取消:

为此,你必须扩展HttpWebRequest(在WP下它没有GetResponseAsync):

// create a static class in your namespace
public static class Extensions
{
    public static Task<HttpWebResponse> GetResponseAsync(this HttpWebRequest webRequest)
    {
        TaskCompletionSource<HttpWebResponse> taskComplete = new TaskCompletionSource<HttpWebResponse>();
        webRequest.BeginGetResponse(
            asyncResponse =>
            {
                try
                {
                    HttpWebRequest responseRequest = (HttpWebRequest)asyncResponse.AsyncState;
                    HttpWebResponse someResponse = (HttpWebResponse)responseRequest.EndGetResponse(asyncResponse);
                    taskComplete.TrySetResult(someResponse);
                }
                catch (WebException webExc)
                {
                    HttpWebResponse failedResponse = (HttpWebResponse)webExc.Response;
                    taskComplete.TrySetResult(failedResponse);
                }
                catch (Exception exc) { taskComplete.SetException(exc); }
            }, webRequest);
        return taskComplete.Task;
    }
}

然后您的方法可能如下所示:

public async Task<Byte[]> GetBytesAsync(DataRequestParam datarequesparam, CancellationToken ct)
{
   HttpWebRequest request = HttpWebRequest.CreateHttp(datarequesparam.TargetUri);
   request.Method = "GET";
   request.Credentials = new NetworkCredential(datarequesparam.AuthentificationLogin, datarequesparam.AuthentificationPassword, "bt0d0000");
   request.AllowReadStreamBuffering = false;

   try
   {
       if (request != null)
       {
           using (HttpWebResponse response = await request.GetResponseAsync())
           using (Stream mystr = response.GetResponseStream())
           using (MemoryStream output = new MemoryStream())
           {
               const int BUFFER_SIZE = 10 * 1024;
               byte[] buf = new byte[BUFFER_SIZE];

               int bytesread = 0;
               while ((bytesread = await mystr.ReadAsync(buf, 0, BUFFER_SIZE)) > 0)
               {
                   output.Write(buf, 0, bytesread);
                   ct.ThrowIfCancellationRequested();
               }
               return output.ToArray();
           }
       }
       else return null;
  }
  catch (WebException)
  {
      throw new MyException(MyExceptionsMessages.Webexception);
  }
}

您可以自由更改缓冲区大小,这将影响检查取消的频率。

我没试过,但我认为它应该有用。