Tempo limite em solicitações HTTP do Xamarin
Boa noite!
Eu estava tentando limpar / refinar algum código e acabei encontrando problemas comtempos limite em solicitações HTTP do Xamarin (conforme descrito no meu tópico original:Download assíncrono e desserializar)
Problema encontrado (testado apenas com o Xamarin.Android; não sei sobre o iOS):
Quando umhost não pode ser alcançado (por exemplo, um servidor local offline),GetAsync
lança umSystem.Net.WebException
depois de aproximadamente3 minutos com a mensagemErro: ConnectFailure (conexão expirou). A exceção interna éSystem.Net.Sockets.SocketsException
(log completo aqui:http://pastebin.com/MzHyp2FM)
Código:
internal static class WebUtilities
{
/// <summary>
/// Downloads the page of the given url
/// </summary>
/// <param name="url">url to download the page from</param>
/// <param name="cancellationToken">token to cancel the download</param>
/// <returns>the page content or null when impossible</returns>
internal static async Task<string> DownloadStringAsync(string url, CancellationToken cancellationToken)
{
try
{
// create Http Client and dispose of it even if exceptions are thrown (same as using finally statement)
using (var client = new HttpClient() { Timeout = TimeSpan.FromSeconds(5) })
{
// should I always do this?
client.CancelPendingRequests();
// Issue here; Timeout of roughly 3 minutes
using (var response = await client.GetAsync(url, cancellationToken).ConfigureAwait(false))
{
// if response was successful (otherwise return null)
if (response.IsSuccessStatusCode)
{
// return its content
return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
}
}
}
}
// TODO: split exceptions?
catch (Exception ex) when (ex is System.Net.Sockets.SocketException ||
ex is InvalidOperationException ||
ex is OperationCanceledException ||
ex is System.Net.Http.HttpRequestException)
{
WriteLine("DownloadStringAsync task has been cancelled.");
WriteLine(ex.Message);
return null;
}
// return null if response was unsuccessful
return null;
}
}
Método de chamada:
internal static async Task CallAsync(string url)
{
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)))
{
var token = cts.Token;
token.ThrowIfCancellationRequested();
string result = await WebUtilities.DownloadStringAsync(url, token).ConfigureAwait(false);
}
}
Configuraçãoclient.Timeout
parece não funcionar.
De qualquer jeito,cancelamento automático de voz após 10 segundos?
Esse problema de tempo limite ocorre quando:
É solicitado um endereço IP offline / inacessível (no meu caso, um servidor local offline como 192.168.1.101:8080) (ou seja, usandoGetAsync
, SendAsync
, GetResponseAsync
)O código funciona bem quando:
A solicitação é feita a partir de umcliente de desktop (por exemplo.,WPF) Se o IP estiver offline / inacessível, lançará 4 exceções muito rapidamente (Nenhuma conexão pôde ser estabelecida porque a máquina de destino a recusou ativamente)Conclusões
Xamarin parece ter algumbugs em solicitações HTTP (com tempos limite pelo menos?), pois eles não fornecem os resultados esperados. E pelo que li, pode ser algo que existe há alguns anos (desde 2012 ou 2013).
O teste de unidade Xamarin também não ajuda:https://github.com/xamarin/xamarin-android/blob/1b3a76c6874853049e89bbc113b22bc632ed5ca4/src/Mono.Android/Test/Xamarin.Android.Net/HttpClientIntegrationTests.cs
Editar
Timeout = TimeSpan.FromMilliseconds(1000)
- trabalhoTimeout = Timeout = TimeSpan.FromSeconds(1)
- não funciona (?????)Timeout = TimeSpan.FromMilliseconds(2000)
(e acima) - não funcionaAlguma ideia? Obrigado!