请求被中止:无法在Windows 8 Metro应用程序中创建SSL/TLS安全通道

请求被中止:无法在Windows 8 Metro应用程序中创建SSL/TLS安全通道,ssl,windows-8,microsoft-metro,httpclient,Ssl,Windows 8,Microsoft Metro,Httpclient,我有一个350个可下载图像URL的列表。我通过运行多个任务一次并行下载10幅图像。但是在下载了大量图片后,我的代码突然抛出了以下异常 异常:“发送请求时出错。” InnerException:“请求被中止:无法创建SSL/TLS 安全通道。” StackTrace:“在 System.Runtime.CompilerServices.TaskWaiter.ThrowForNonSuccess(任务 任务)\r\n位于 System.Runtime.CompilerServices.TaskWai

我有一个350个可下载图像URL的列表。我通过运行多个任务一次并行下载10幅图像。但是在下载了大量图片后,我的代码突然抛出了以下异常

异常:“发送请求时出错。”

InnerException:“请求被中止:无法创建SSL/TLS 安全通道。”

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

我创建了一个示例项目来重现此异常。我手头有两个测试用例。您可以从下载运行的测试项目。右键单击文件httpclienttestcases1和2.zip并下载

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

在本例中,我使用相同的HttpClient向10个URL发送并行请求。在本例中,下载大部分时间都是成功的。上次成功下载映像后,请等待至少40秒(最多1分40秒)为下一批发送下一个并行下载请求。由于此异常,一个映像肯定会失败。但是,在许多地方,它已编写并建议使用单个HttpClient来处理多个请求

   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实例

在这种情况下,它只是由于并行下载图像时出现相同的异常而频繁失败

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);
            });
        }
    }
private void Send10DownloadRequestParallel()
{
对于(Int32索引=0;索引<10;索引++)
{
Task.Run(()=>
{   
Int32 index1=rand.Next(0,myImageDownloader.ImageURLs.Count-1);
UpdateDownloadProgress();
//案例1:使用单一共享HttpClient下载
//myImageDownloader.DownloadeUsingSingleSharedHTTPClient(index1);
//或
//案例2:每次使用创建Http客户端下载
myImageDownloader.creatingHttpClientEverytime(index1)下载;
});
}
}

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

我运行了您的示例应用程序,仅在几个场景中出现错误:

  • 当你的应用程序请求的映像不存在时,.NET HTTP客户端会抛出一个异常。你的处理程序不能完全处理这种情况,因为内部异常为NULL。我不得不稍微调整一下代码:

    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() + ")";
        });
    }
    
  • 我唯一一次收到你的另一个错误
    无法在Windows 8 Metro应用程序中创建SSL/TLS安全通道
    ,是在我使用HTTP调试代理(Fiddler)时。如果我没有使用Fiddler,它会截获所有HTTP(S)调用,那么我下载时没有问题。我甚至连续快速启动了多次下载(在一秒钟内多次单击蓝色下载区域)。结果是所有项目都已下载(除了上面提到的404错误)

  • 这是一个成功下载的屏幕截图(404除外)。这个屏幕截图正在运行测试用例2(HttpClient的多个实例)。我确实运行了测试用例1(HttpClient的单个实例),结果也很成功


    简而言之,我没有看到您遇到的问题。我唯一能想到的是您可以从不同的机器或位置尝试您的应用程序。

    假设您的图像托管在SSL位置下是否正确?@chuex是。例如,图像托管在Facebook或twitter服务器上。不幸的是,我没有测试服务器上有一个SSL站点可以尝试您的代码。如果有帮助,我可以在一个非SSL测试服务器上运行您的代码-在这种(非SSL)情况下运行得很好。@chuex,您可以尝试此链接。我使用您的SSL链接尝试了代码,一切都对我有效。下面是一些下载的示例代码(20次)您基于SSL的映像代码所做的全部工作是创建5次下载(一次),然后等待这5次下载完成。它会重复此操作,直到所有文件下载完成。+1,哪个Url引发异常404?您可以共享该Url吗?您可以在浏览器中尝试该Url,看看它是否引发404。@Somnath-我这次只能得到一个(可能有,也可能没有):我在浏览器中尝试了,但没有找到。你真的应该用谷歌
    Fiddler proxy
    。它在这些场景中非常方便,因为它显示了正在发出的请求,以及哪些请求成功或失败。