该请求已中止:无法在Windows 8 Metro App中创建SSL/TLS安全通道

问题描述:

我有350个可下载图像网址的列表.通过运行多个任务,我一次可以并行下载10张图像.但是在下载 N 个图像后,我的代码突然抛出了以下异常.

I have a list of 350 downloadable image urls. I download 10 images parallely at one shot by running multiple tasks. But after downloading N number of images suddenly my code throws the following exception.

异常:发送请求时发生错误."

Exception: "An error occurred while sending the request."

InnerException:请求已中止:无法创建SSL/TLS 安全通道."

InnerException: "The request was aborted: Could not create SSL/TLS secure channel."

StackTrace:位于 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务 任务)\ r \ n位于 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务 任务)\ r \ n位于 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\ r \ n ...

StackTrace: "at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n ...

我创建了一个示例项目来重现此异常.我手里有2个测试用例.您可以从我的天空"此处下载正在运行的测试项目.右键单击文件HTTPClientTestCases1and2.zip并下载.

I have created a sample project to reproduce this exception. I have 2 test-cases in my hand. You can download the running test project from My Sky Drive Here. Right click on the file HTTPClientTestCases1and2.zip and download.

案例1:使用单个实例HttpClient进行所有图像下载.

在这种情况下,我正在使用相同的HttpClient向10个URL发送并行请求.在这种情况下,大多数情况下下载都是成功的.上次成功下载图像后,请等待至少40秒(最多1分钟40秒),以发送下一个并行下载请求以供下一批使用.由于该异常,一个图像肯定会失败.但是有很多地方将其书面建议放在多个请求中使用单个HttpClient.

In this case I'm sending parallel request to 10 urls using same HttpClient. In this case download is successful for most of the time. After last successful download of an image wait for minimum 40 seconds (Max 1 minute 40 seconds) to send the next parallel download request for the next batch. One image will definitely fail due to this exception. But so many places its written and suggested to use single HttpClient for multiple request.

   public async void DownloadUsingSingleSharedHttpClient(Int32 imageIndex)
    {   
        Uri url = new Uri(ImageURLs[imageIndex]);

        UnderDownloadCount++;

        try
        {
            Byte[] contentBytes = null;

            try
            {
                // Exception IS THROWN AT LINE BELOW 
                HttpResponseMessage response = await _httpClient.GetAsync(url);

                contentBytes = await response.Content.ReadAsByteArrayAsync();
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("Download Failed at GetAsync() :" + ex.Message);
                throw ex;
            }

            DownloadedCount++;

            if (OnSuccess != null)
                OnSuccess(this, new DownloadSuccessEventArgs() { Index = imageIndex, Data = contentBytes });
        }
        catch (HttpRequestException hre)
        {
            DownloadFailedCount++;
            if (OnFailed != null)
                OnFailed(hre, null);
        }
        catch (TaskCanceledException hre)
        {   
            DownloadFailedCount++;
            if (OnFailed != null)
                OnFailed(hre, null);
        }
        catch (Exception e)
        {
            DownloadFailedCount++;
            if (OnFailed != null)
                OnFailed(e, null);
        }
    }

案例2:为每个图像下载创建新的HttpClient实例

在这种情况下,由于并行下载映像时,由于相同的异常,它非常频繁地失败.

In this case it just fails very frequently due to same exception while downloading images parallely.

public async void DownloadUsingCreatingHttpClientEveryTime(Int32 imageIndex)
{
    Uri url = new Uri(ImageURLs[imageIndex]);

    UnderDownloadCount++;
    try
    {
        Byte[] contentBytes = null;

        using (HttpClientHandler _handler = new HttpClientHandler())
        {
            _handler.AllowAutoRedirect = true;
            _handler.MaxAutomaticRedirections = 4;

            using (HttpClient httpClient = new HttpClient(_handler))
            {
                httpClient.DefaultRequestHeaders.ExpectContinue = false;
                httpClient.DefaultRequestHeaders.Add("Keep-Alive", "false");

                try
                {
                    // Exception IS THROWN AT LINE BELOW 
                    contentBytes = await httpClient.GetByteArrayAsync(url.OriginalString);
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine("Download Failed :" + ex.Message);
                    throw ex;
                    }
                }

            _handler.Dispose();
        }

        DownloadedCount++;

        if (OnSuccess != null)
            OnSuccess(this, new DownloadSuccessEventArgs() { Index = imageIndex, Data = contentBytes });
    }
    catch (HttpRequestException hre)
    {
        DownloadFailedCount++;
        if (OnFailed != null)
            OnFailed(hre, null);
    }
    catch (TaskCanceledException hre)
    {
        DownloadFailedCount++;
        if (OnFailed != null)
            OnFailed(hre, null);
    }
    catch (Exception e)
    {
        DownloadFailedCount++;
        if (OnFailed != null)
            OnFailed(e, null);
    }
}

请在MainPage.xaml.cs中编辑以下功能以检查两种情况

 private void Send10DownloadRequestParallel()
    {
        for (Int32 index = 0; index < 10; index++)
        {
            Task.Run(() =>
            {   
                Int32 index1 = rand.Next(0, myImageDownloader.ImageURLs.Count - 1);

                UpdateDownloadProgress();

                // Case 1: Download Using Single Shared HttpClient
                // myImageDownloader.DownloadUsingSingleSharedHttpClient(index1);

                // OR

                // Case 2: Download Using Creating Http Client Every Time
                myImageDownloader.DownloadUsingCreatingHttpClientEveryTime(index1);
            });
        }
    }

我的问题:我在做什么错?通过克服此异常,在WinRT中实现并行下载器的最佳方法是什么.

My Question: What I'm doing wrong? What is the best way of implementing parallel downloader in WinRT by overcoming this exception.

我运行了您的示例应用程序,但是在以下两种情况下我只会遇到错误:

I ran your sample application and am only get errors in a couple of scenarios:

  1. 当您的应用程序请求的图像不存在时,.NET HTTP客户端将引发异常.您的处理程序无法完全处理这种情况,因为内部异常为NULL.我只需要稍微调整一下代码:

  1. When the image that your app is requesting does not exist, the .NET HTTP client throws an exception. Your handler doesn't quite handle this case, as the inner exception is NULL. I had to tweak that code just a little:

async void myImageDownloader_OnFailed(object sender, EventArgs e)
{
    await App.CurrentDispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, delegate
    {   
        TimeSpan time =(DateTime.Now -dateTimeSuccess);

        String timeGap = "Ideal For:" + time.ToString() + "\n";
        ErrorListBox.Text += "\n Failed When: " + DownloadInfo.Text + "\n";
        ErrorListBox.Text += timeGap;

        // CX - added null check for InnerException, as these are NULL on HTTP result status 404
        var ex = sender as Exception;
        if (ex.InnerException != null)
            ErrorListBox.Text += ex.InnerException.Message;
        else
            ErrorListBox.Text += "Inner Exception null - Outer = (" + ex.ToString() + ")";
    });
}

  • 我唯一一次收到其他错误Could not create SSL/TLS secure channel in Windows 8 Metro App的时间是当我使用HTTP调试代理(Fiddler)时.如果我不使用Fiddler(会拦截所有HTTP(S)调用),那么下载就不会有问题.我什至连续快速地开始了多次下载(通过在一秒钟内多次单击蓝色下载区域).结果是所有项目均已下载(如上所述,除了404错误外).

  • The only time I got your other error Could not create SSL/TLS secure channel in Windows 8 Metro App, is when I was using a HTTP debugging proxy (Fiddler). If I don't user Fiddler, which intercepts all HTTP(S) calls, then I have no problems downloading. I even started multiple downloads in rapid succession (by clicking the blue download area multiple times within one second). The result was that all items were downloaded (except for the 404 errors, as mentioned above).

    这是成功下载的屏幕截图(同样是404除外).该屏幕快照正在运行测试用例#2(HttpClient的多个实例).我确实运行了测试案例#1(HttpClient的单个实例),结果也成功了.

    Here is a screenshot of the successful downloads (again except for the 404s). This screenshot is running test case #2 (multiple instances of HttpClient). I did run test case #1 (single instance of HttpClient) and the results were also successful.

    简而言之,我没有看到您遇到的问题.我唯一能想到的就是让您从其他计算机或其他位置尝试应用.

    In short, I did not see the problems that you are experiencing. The only thing I can think of is for you to try your app from a different machine or location.