public async Task <IHttpJsonResponseMessage <T> > GetJsonAsync <T>(
            Uri requestUri,
            TimeSpan?requestTimeout = null,
            AuthenticationHeaderValue authenticationHeaderValue = null)
        {
            // SocialGist only accepts TLS 1.1 or higher.  AzureFunctions (on Azure) default to SSL3 or TLS
            // AzureFunctions runing locally use defaults that work with SocialGist but remote Azure Functions do not.
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11;
            log.Verbose($"Retrieving URL using protocol: {ServicePointManager.SecurityProtocol}");
            telemetryClient.TrackEvent(TelemetryNames.HTTP_Get, new Dictionary <string, string> {
                { "URL", requestUri.ToString() }
            });

            var handler = new HttpClientHandler()
            {
                AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
            };

            using (var client = new System.Net.Http.HttpClient(handler))
            {
                if (requestTimeout.HasValue)
                {
                    client.Timeout = requestTimeout.Value;
                }

                if (authenticationHeaderValue != null)
                {
                    client.DefaultRequestHeaders.Authorization = authenticationHeaderValue;
                }

                string data = "";
                HttpResponseMessage response = null;
                int retryCount = 0;
                while (retryCount < RETRY_COUNT)
                {
                    try
                    {
                        telemetryClient.TrackEvent(TelemetryNames.HTTP_Try, new Dictionary <string, string> {
                            { "URL", requestUri?.ToString() }, { "try number", retryCount.ToString() }
                        });
                        log.Verbose($"Retrieving URL {requestUri} on attempt {retryCount}");

                        // Track telemetry for each host query
                        using (var tracker = telemetryClient.StartTrackDependency(requestUri.Host, requestUri.AbsolutePath, "HTTP"))
                        {
                            tracker.Properties.Add("Request URL", requestUri?.ToString());
                            tracker.Properties.Add("Try attempt", retryCount.ToString());

                            try
                            {
                                response = await client.GetAsync(requestUri);
                            }
                            catch (TaskCanceledException)
                            {
                                tracker.IsSuccess  = false;
                                tracker.ResultCode = "Task Canceled (HTTP Timeout)";
                                throw;
                            }
                            catch (HttpRequestException e)
                            {
                                tracker.IsSuccess  = false;
                                tracker.ResultCode = $"HTTPException: {e.Message}";
                                throw;
                            }

                            tracker.IsSuccess  = response.IsSuccessStatusCode;
                            tracker.ResultCode = response.StatusCode.ToString();

                            // Get data after setting telemetry status codes incase this errors out.
                            data = await response.Content.ReadAsStringAsync();

                            if (!response.IsSuccessStatusCode)
                            {
                                // Do not store this data unless the request failed.  This data can get very large very fast.
                                tracker.Properties.Add("Server Response", data);
                            }
                        }

                        if (response.IsSuccessStatusCode)
                        {
                            this.objectLogger.Log(data, "HttpClient", requestUri.ToString());

                            // Successfully completed request
                            break;
                        }
                        else
                        {
                            telemetryClient.TrackEvent(TelemetryNames.HTTP_Error, new Dictionary <string, string> {
                                { "URL", requestUri?.ToString() },
                                { "StatusCode", response?.StatusCode.ToString() }
                            });
                            retryCount = HandleFailure(retryCount, requestUri, response);
                        }
                    }
                    catch (Exception e)
                    {
                        retryCount++;
                        telemetryClient.TrackEvent(TelemetryNames.HTTP_Error, new Dictionary <string, string> {
                            { "URL", requestUri?.ToString() },
                            { "StatusCode", response?.StatusCode.ToString() },
                            { "Exception", e.ToString() }
                        });
                        if (retryCount < RETRY_COUNT)
                        {
                            log.Error($"Error executing web request for URL {requestUri} on attempt {retryCount}.  Retrying.", e);
                        }
                        else
                        {
                            log.Error($"Error executing web request for URI {requestUri} on attempt {retryCount}.  NOT retrying", e);

                            // Rethrow the exception to fail the current job
                            throw;
                        }
                    }

                    // Do not wait after the final try.
                    if (retryCount < RETRY_COUNT)
                    {
                        // Request failed.  Wait a random time and try again.  Random() uses a time-dependent seed.
                        int wait = new Random().Next((int)minWaitBeforeRetry.TotalMilliseconds, (int)maxWaitBeforeRetry.TotalMilliseconds);
                        log.Verbose($"Waiting {wait} milliseconds before retrying");
                        Thread.Sleep(wait);
                    }
                }

                log.Verbose($"URL {requestUri} retrieved.");

                var metric = new MetricTelemetry();
                metric.Name      = TelemetryNames.HTTP_RetryCount;
                metric.Sum       = retryCount;
                metric.Timestamp = DateTime.Now;
                metric.Properties.Add("Domain", requestUri.Host);
                telemetryClient.TrackMetric(metric);

                try
                {
                    var obj = JsonConvert.DeserializeObject <T>(data);

                    log.Verbose($"Result deserialized from URL {requestUri}");

                    return(new HttpJsonResponseMessage <T>
                    {
                        Object = obj,
                        ResponseMessage = response
                    });
                }
                catch (Exception e)
                {
                    telemetryClient.TrackEvent(TelemetryNames.HTTP_JSON_Error, new Dictionary <string, string>
                    {
                        { "URL", requestUri?.ToString() },
                        { "StatusCode", response?.StatusCode.ToString() },
                        { "Exception", e.ToString() },
                        { "Response", data }
                    });

                    // Log and rethrow the exception
                    log.Error($"Error deserializing result from URL {requestUri}", e);

                    // Rethrow the exception to fail the current job
                    throw;
                }
            }
        }