C# 如果与主机的连接丢失,请取消IIInputStream.ReadAsync

C# 如果与主机的连接丢失,请取消IIInputStream.ReadAsync,c#,uwp,windows-runtime,winrt-async,winrt-httpclient,C#,Uwp,Windows Runtime,Winrt Async,Winrt Httpclient,我正在编写一个UWP(WinRT)解决方案,它从服务器下载一个文件并保存到光盘,同时指示进度。为此,我扩展了IAsyncOperationWithProgress方法 我的问题是,在一行: while ((await responseStream.ReadAsync(streamReadBuffer, bufferLength, InputStreamOptions.None)).Length > 0 && !token.IsCancellationRequested)

我正在编写一个UWP(WinRT)解决方案,它从服务器下载一个文件并保存到光盘,同时指示进度。为此,我扩展了IAsyncOperationWithProgress方法

我的问题是,在一行:

while ((await responseStream.ReadAsync(streamReadBuffer, bufferLength, InputStreamOptions.None)).Length > 0 && !token.IsCancellationRequested)
我等待从流中读取内容。如果连接丢失,此线路将无限期等待,直到重新建立连接

对于UWP,我如何为Http请求分配超时,或者取消单个任务

我的扩展iAsyncopeWithProgress:

private static IAsyncOperationWithProgress<HttpDownloadStatus, DownloadResponse> DownloadAsyncWithProgress(this HttpClient client, HttpRequestMessage request, CancellationToken cancelToken, StorageFile fileToStore)
    {
        const uint bufferLength = 2048;
        var progressResponse = new DownloadResponse
        {
            File = fileToStore,
            DownloadStatus = HttpDownloadStatus.Started,
            BytesRecieved = 0,
            Progress = 0.00
        };
        string result = string.Empty;
        HttpDownloadStatus returnStatus = HttpDownloadStatus.Busy;
        IBuffer streamReadBuffer = new Windows.Storage.Streams.Buffer(bufferLength);

        var operation = client.SendRequestAsync(request, HttpCompletionOption.ResponseHeadersRead);

            return AsyncInfo.Run<HttpDownloadStatus, DownloadResponse>((token, progress) =>
                Task.Run(async () =>
                {
                    try
                    {
                        if (cancelToken != CancellationToken.None) token = cancelToken;
                        HttpResponseMessage respMessage;
                        try
                        {
                            respMessage = await operation;
                        }
                        catch (Exception ex)
                        {
                            throw new Exception("Error sending download request - " + ex.Message);
                        }
                        progressResponse.TotalBytes = Convert.ToInt64(respMessage.Content.Headers.ContentLength);
                        using (var responseStream = await respMessage.Content.ReadAsInputStreamAsync())
                        {
                            using (var fileWriteStream = await fileToStore.OpenAsync(FileAccessMode.ReadWrite))
                            {
                                token.ThrowIfCancellationRequested();
                                while ((await responseStream.ReadAsync(streamReadBuffer, bufferLength, InputStreamOptions.None)).Length > 0 && !token.IsCancellationRequested)
                                {

                                    while(DownloadManager.ShouldPauseDownload && DownloadManager.CurrentDownloadingBook.FileName == fileToStore.Name)
                                    {
                                        if (token.IsCancellationRequested)
                                            break;
                                    }

                                    progressResponse.DownloadStatus = HttpDownloadStatus.Busy;
                                    if (token.IsCancellationRequested)
                                    {
                                       // progressResponse.DownloadStatus = HttpDownloadStatus.Cancelled;
                                       // returnStatus = HttpDownloadStatus.Cancelled;
                                        break;
                                    }

                                    ;
                                    await fileWriteStream.WriteAsync(streamReadBuffer);
                                    progressResponse.BytesRecieved += (int)streamReadBuffer.Length;
                                    progressResponse.Progress = (progressResponse.BytesRecieved / (double)progressResponse.TotalBytes) * 100;
                                    //Only give response when close to a byte
                                    if (progressResponse.BytesRecieved % 1048576 == 0)
                                    {
                                        Debug.WriteLine("Should be 1 meg: " + progressResponse.BytesRecieved);
                                        progress.Report(progressResponse);
                                    }
                                } //while (offset < contentLength);
                                if (token.IsCancellationRequested)
                                {
                                    progressResponse.DownloadStatus = HttpDownloadStatus.Cancelled;
                                    returnStatus = HttpDownloadStatus.Cancelled;
                                }

                            }
                        }
                        if(returnStatus == HttpDownloadStatus.Busy) //only set it if it was still legitimately busy
                            returnStatus = HttpDownloadStatus.Complete;

                        return returnStatus;
                    }
                    catch (TaskCanceledException tce)
                    {
                        Debug.WriteLine("CANCEL - Download cancellation token caught from within task");
                        return HttpDownloadStatus.Cancelled;
                    }
                }, token));


    }
私有静态IAsyncOperationWithProgress下载AsyncWithProgress(此HttpClient客户端、HttpRequestMessage请求、CancellationToken cancelToken、StorageFile fileToStore)
{
常数缓冲长度=2048;
var progressResponse=新下载响应
{
File=fileToStore,
DownloadStatus=HttpDownloadStatus.Started,
BytesReceived=0,
进度=0.00
};
字符串结果=string.Empty;
HttpDownloadStatus returnStatus=HttpDownloadStatus.Busy;
IBuffer streamReadBuffer=新的Windows.Storage.Streams.Buffer(bufferLength);
var operation=client.SendRequestAsync(请求,HttpCompletionOption.ResponseHeadersRead);
返回AsyncInfo.Run((令牌,进度)=>
Task.Run(异步()=>
{
尝试
{
如果(cancelToken!=CancellationToken.None)token=cancelToken;
HttpResponseMessage;
尝试
{
respMessage=等待操作;
}
捕获(例外情况除外)
{
抛出新异常(“发送下载请求时出错-”+ex.Message);
}
progressResponse.TotalBytes=Convert.ToInt64(respMessage.Content.Headers.ContentLength);
使用(var responseStream=await respMessage.Content.ReadAsInputStreamAsync())
{
使用(var fileWriteStream=await fileToStore.OpenAsync(FileAccessMode.ReadWrite))
{
token.ThrowIfCancellationRequested();
while((等待响应Stream.ReadAsync(streamReadBuffer、bufferLength、InputStreamOptions.None)).Length>0&&!token.IsCancellationRequested)
{
while(DownloadManager.shoulldpausedownload&&DownloadManager.CurrentDownloadingBook.FileName==fileToStore.Name)
{
if(令牌.IsCancellationRequested)
打破
}
progressResponse.DownloadStatus=HttpDownloadStatus.Busy;
if(令牌.IsCancellationRequested)
{
//progressResponse.DownloadStatus=HttpDownloadStatus.Cancelled;
//returnStatus=HttpDownloadStatus.已取消;
打破
}
;
等待fileWriteStream.WriteAsync(streamReadBuffer);
progressResponse.ByteReceived+=(int)streamReadBuffer.Length;
progressResponse.Progress=(progressResponse.ByteReceived/(double)progressResponse.TotalBytes)*100;
//仅在接近一个字节时给出响应
如果(progressResponse.BytesReceived%1048576==0)
{
Debug.WriteLine(“应为1兆:“+progressResponse.ByteReceived”);
进度报告(进度响应);
}
}//while(偏移量
如何调用上述代码:

HttpClient httpClient = new HttpClient(PFilter);

try
{
DownloadResponse downloadResponse = new DownloadResponse { File = fileToSave, DownloadStatus = HttpDownloadStatus.Busy };
CancellationToken cancelToken = m_CancellationSource.Token;

HttpRequestMessage requestMsg = new HttpRequestMessage(HttpMethod.Get, downloadUri);

IAsyncOperationWithProgress<HttpDownloadStatus,DownloadResponse> operationWithProgress = httpClient.DownloadAsyncWithProgress(requestMsg, cancelToken, fileToSave);

operationWithProgress.Progress = new AsyncOperationProgressHandler<HttpDownloadStatus, DownloadResponse>((result, progress) => { progressDelegate(progress); });

var response = await operationWithProgress;

downloadResponse.DownloadStatus = response;

if (response == HttpDownloadStatus.Complete)
{
    return HttpWebExceptionResult.Success;
}
else if (response == HttpDownloadStatus.ConnectionLost)
    return HttpWebExceptionResult.ConnectionFailure;
else if (response == HttpDownloadStatus.Cancelled)
    return HttpWebExceptionResult.RequestCanceled;
else
    return HttpWebExceptionResult.UnexpectedError;



}
catch (TaskCanceledException tce)
{
    Debug.WriteLine("CANCEL - token caught from StartDownloadAsync ");
    return HttpWebExceptionResult.RequestCanceled;
}
catch (Exception ex)
{
    return HttpWebExceptionResult.UnexpectedError;
}
HttpClient-HttpClient=新的HttpClient(PFilter);
尝试
{
DownloadResponse DownloadResponse=new DownloadResponse{File=fileToSave,DownloadStatus=HttpDownloadStatus.Busy};
CancellationToken cancelToken=m_CancellationSource.Token;
HttpRequestMessage requestMsg=新的HttpRequestMessage(HttpMethod.Get,downloadUri);
IAsyncOperationWithProgress操作WithProgress=httpClient.DownloadAsyncWithProgress(requestMsg、cancelToken、fileToSave);
operationWithProgress.Progress=新的AsyncOperationProgressHandler((结果,进度)=>{progressDelegate(进度);});
var响应=等待操作进行;
downloadResponse.DownloadStatus=响应;
如果(响应)
var timeoutCancellationSource = new CancellationTokenSource(TimeSpan.FromSeconds(2));
var response = await inputStream.ReadAsync(buffer, bufferLength, InputStreamOptions.None).AsTask(timeoutCancellationSource.Token);
timeoutCancellationSource.Cancel();