Запрос был прерван: не удалось создать безопасный канал SSL/TLS в приложении Windows 8 Metro
У меня есть список 350 загружаемых URL-адресов изображений. Я загружаю 10 изображений параллельно одним выстрелом, запуская несколько задач. Но после загрузки N количества изображений внезапно мой код выдает следующее исключение.
Исключение: "Произошла ошибка при отправке запроса".
InnerException: "Запрос был прерван: не удалось создать SSL/TLS безопасный канал".
StackTrace: "at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task задача)\r\n в System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task задача)\r\n в System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n...
Я создал образец проекта, чтобы воспроизвести это исключение. В моей руке у меня 2 теста. Вы можете загрузить текущий тестовый проект из My Sky Drive Here. Щелкните правой кнопкой мыши файл HTTPClientTestCases1and2.zip и загрузите.
Случай 1: использование одного экземпляра HttpClient для загрузки всего изображения.
В этом случае я отправляю параллельный запрос на 10 URL-адресов, используя тот же HttpClient. В этом случае загрузка выполняется в большинстве случаев. После последней успешной загрузки изображения подождите минимум 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);
});
}
}
Мой вопрос: Что я делаю неправильно? Каков наилучший способ реализации параллельного загрузчика в WinRT, преодолев это исключение.
Ответы
Ответ 1
Я запустил ваше примерное приложение и получаю ошибки только в нескольких сценариях:
-
Когда изображение, запрашиваемое вашим приложением, не существует, клиент .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() + ")";
});
}
-
Единственный раз, когда я получил вашу другую ошибку Could not create SSL/TLS secure channel in Windows 8 Metro App
, - это когда я использовал прокси-сервер отладки HTTP (Fiddler). Если я не пользователь Fiddler, который перехватывает все вызовы HTTP (S), то у меня нет проблем с загрузкой. Я даже начал несколько загрузок в быстрой последовательности (щелкнув синюю область загрузки несколько раз в течение одной секунды). В результате было загружено все предметы (за исключением 404 ошибок, как указано выше).
Вот скриншот успешных загрузок (опять же за исключением 404). На этом скриншоте работает тестовый пример # 2 (несколько экземпляров HttpClient). Я выполнил тестовый пример № 1 (единственный экземпляр HttpClient), и результаты также были успешными.
Короче говоря, я не видел проблем, с которыми вы сталкиваетесь. Единственное, что я могу придумать, это попробовать попробовать свое приложение с другой машины или местоположения.