2014-03-07 62 views
1

我有一个列表,每次用户进行研究时都会加载元素...这些元素包含一个图标,它使用HttpClient对象的异步方法GetByteArrayAsync进行下载。
我有一个问题,当用户在第一个列表的图标仍在下载时进行第二个研究。因为元素列表正在更改,而图标下载正在处理第一个列表的每个元素。
所以我的猜测是,我需要取消这些请求,每次用户前往一个新的研究...我重新在Task.run和CancellationTokenSource一些stuuf,但我找不到真正有用的示例为我的情况,所以这里是我的代码...
希望你能帮助我与...谢谢你如何取消Windows Phone中的异步呼叫?

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 我需要取消这个funntion,当用户做一个新的研究和列表“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) 
        { 

        } 
       } 


     } 

回答

2

首先需要定义CancellationTokenSource

private System.Threading.CancellationTokenSource cts; 

地方上面的代码的某个地方,在那里你可以与你的按钮或其他方法来访问它。

不幸的是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); 
    } 
} 

您可以自由变动b uffer大小,这将影响取消将被检查的频率。

我没有试过这个,但我认为它应该工作。

+0

我已经尝试o添加令牌参数,但GetByteArrayAsync不接受这种参数...(仅限字符串或Uri) –

+0

@PaulMartinez您是对的,此方法不支持取消。必须用不同的方法或实施来完成。 – Romasz

+0

@PaulMartinez但也许你可以使用其他支持取消的方法 - 我编辑了我的答案。 – Romasz