我有一个列表,每次用户进行研究时都会加载元素...这些元素包含一个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)
{
}
}
}
答案 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);
}
}
您可以自由更改缓冲区大小,这将影响检查取消的频率。
我没试过,但我认为它应该有用。