in common/src/service/HttpClientHelper.cs [737:854]
private async Task ExecuteAsync(
HttpClient httpClient,
HttpMethod httpMethod,
Uri requestUri,
Func<HttpRequestMessage, CancellationToken, Task> modifyRequestMessageAsync,
Func<HttpResponseMessage, bool> isMappedToException,
Func<HttpResponseMessage, CancellationToken, Task> processResponseMessageAsync,
IDictionary<HttpStatusCode, Func<HttpResponseMessage, Task<Exception>>> errorMappingOverrides,
CancellationToken cancellationToken)
{
if (Logging.IsEnabled)
Logging.Enter(this, httpMethod.Method, requestUri, nameof(ExecuteAsync));
try
{
IDictionary<HttpStatusCode, Func<HttpResponseMessage, Task<Exception>>> mergedErrorMapping = MergeErrorMapping(errorMappingOverrides);
using var msg = new HttpRequestMessage(httpMethod, requestUri);
msg.Headers.Add(HttpRequestHeader.Authorization.ToString(), _authenticationHeaderProvider.GetAuthorizationHeader());
msg.Headers.Add(HttpRequestHeader.UserAgent.ToString(), Utils.GetClientVersion());
if (modifyRequestMessageAsync != null)
{
await modifyRequestMessageAsync(msg, cancellationToken).ConfigureAwait(false);
}
// TODO: pradeepc - find out the list of exceptions that HttpClient can throw.
HttpResponseMessage responseMsg;
try
{
responseMsg = await httpClient.SendAsync(msg, cancellationToken).ConfigureAwait(false);
if (responseMsg == null)
{
throw new InvalidOperationException("The response message was null when executing operation {0}.".FormatInvariant(httpMethod));
}
if (!isMappedToException(responseMsg))
{
if (processResponseMessageAsync != null)
{
await processResponseMessageAsync(responseMsg, cancellationToken).ConfigureAwait(false);
}
}
}
catch (AggregateException ex)
{
if (Logging.IsEnabled)
Logging.Error(this, ex, nameof(ExecuteAsync));
ReadOnlyCollection<Exception> innerExceptions = ex.Flatten().InnerExceptions;
if (innerExceptions.Any(Fx.IsFatal))
{
throw;
}
// Apparently HttpClient throws AggregateException when a timeout occurs.
// TODO: pradeepc - need to confirm this with ASP.NET team
if (innerExceptions.Any(e => e is TimeoutException))
{
throw new IotHubCommunicationException(ex.Message, ex);
}
throw new IotHubException(ex.Message, ex);
}
catch (TimeoutException ex)
{
if (Logging.IsEnabled)
Logging.Error(this, ex, nameof(ExecuteAsync));
throw new IotHubCommunicationException(ex.Message, ex);
}
catch (IOException ex)
{
if (Logging.IsEnabled)
Logging.Error(this, ex, nameof(ExecuteAsync));
throw new IotHubCommunicationException(ex.Message, ex);
}
catch (HttpRequestException ex)
{
if (Logging.IsEnabled)
Logging.Error(this, ex, nameof(ExecuteAsync));
throw new IotHubCommunicationException(ex.Message, ex);
}
catch (TaskCanceledException ex)
{
if (Logging.IsEnabled)
Logging.Error(this, ex, nameof(ExecuteAsync));
// Unfortunately TaskCanceledException is thrown when HttpClient times out.
if (cancellationToken.IsCancellationRequested)
{
throw new IotHubException(ex.Message, ex);
}
throw new IotHubCommunicationException(string.Format(CultureInfo.InvariantCulture, "The {0} operation timed out.", httpMethod), ex);
}
catch (Exception ex) when (!Fx.IsFatal(ex))
{
if (Logging.IsEnabled)
Logging.Error(this, ex, nameof(ExecuteAsync));
throw new IotHubException(ex.Message, ex);
}
if (isMappedToException(responseMsg))
{
Exception mappedEx = await MapToExceptionAsync(responseMsg, mergedErrorMapping).ConfigureAwait(false);
throw mappedEx;
}
}
finally
{
if (Logging.IsEnabled)
Logging.Exit(this, httpMethod.Method, requestUri, nameof(ExecuteAsync));
}
}