private async Task <RawContentResponse> ExecuteContentRequestAsync <TId>(TId contentIdentifier, string endpoint, bool bypassCache, TryFunc <string, RawContentResponse> tryGetFromCache, Action <string, RawContentResponse> addToCache)
        {
            if (bypassCache == false && cacheIsAvailable)
            {
                RawContentResponse cacheOut;
                if (tryGetFromCache(contentIdentifier.ToString(), out cacheOut))
                {
                    return(cacheOut);
                }
            }

            var requestWithPolicy = new HttpRequestWithPolicy(this);
            var response          = await requestWithPolicy.Execute(() =>
                                                                    httpClient.GetAsync(string.Format((Target.Url.AbsoluteUri + endpoint), contentIdentifier))
                                                                    ).ConfigureAwait(false);


            if (response.Result?.IsSuccessStatusCode == false || response.Outcome == OutcomeType.Failure)
            {
                // We don't want to throw exceptions if we can't return any content.
                // Let the caller deal with the empty result if they deem it critical.
                return(RawContentResponse.Empty);
            }

            string jsonResult = await response.Result.Content.ReadAsStringAsync().ConfigureAwait(false);

            RawContentResponse rawContentResponse = RawContentResponseFactory.Build(jsonResult);

            if (cacheIsAvailable && !bypassCache && !string.IsNullOrWhiteSpace(rawContentResponse.RenderedContent))
            {
                addToCache(rawContentResponse.Id.ToString(), rawContentResponse);
            }

            return(rawContentResponse);
        }
        private async Task <DescendantIdsResponse> ExecuteTreePickerIdsRequestAsync(int id, string property, string endpoint, bool bypassCache, TryFunc <string, DescendantIdsResponse> tryGetFromCache, Action <string, DescendantIdsResponse> addToCache)
        {
            if (bypassCache == false && cacheIsAvailable)
            {
                DescendantIdsResponse cacheOut;
                if (tryGetFromCache(id.ToString(), out cacheOut))
                {
                    return(cacheOut);
                }
            }

            var requestWithPolicy = new HttpRequestWithPolicy(this);
            var response          = await requestWithPolicy.Execute(() =>
                                                                    httpClient.GetAsync(string.Format((Target.Url.AbsoluteUri + endpoint), id, property))
                                                                    ).ConfigureAwait(false);

            if (response.Result?.IsSuccessStatusCode == false || response.Outcome == OutcomeType.Failure)
            {
                return(DescendantIdsResponse.Empty);
            }

            string jsonResult = await response.Result.Content.ReadAsStringAsync().ConfigureAwait(false);

            DescendantIdsResponse treePickerIdsResponse = JsonConvert.DeserializeObject <DescendantIdsResponse>(jsonResult);

            if (cacheIsAvailable && !bypassCache && (treePickerIdsResponse.DescendantCount > 0))
            {
                addToCache(treePickerIdsResponse.Origin.ToString(), treePickerIdsResponse);
            }

            return(treePickerIdsResponse);
        }
        /// <summary>
        /// Exposes the api directly. This method allows you to supply a custom query and response type and do the mappings yourself.
        /// You get error & retry policies; along with caching built in.
        /// The TResponse type needs be fully serialisable.
        /// </summary>
        /// <typeparam name="TResponse">A custom response type to map to : SHOULD BE SERIALIZABLE</typeparam>
        /// <param name="query">An custom query, conforming to a IUmbracoCustomQuery contract</param>
        /// <param name="bypassCache"></param>
        public async Task <TResponse> QueryAsync <TResponse>(IUmbracoCustomQuery <TResponse> query, bool bypassCache)
        {
            if (bypassCache == false && cacheIsAvailable)
            {
                TResponse cacheOut;
                if (cache.TryGet(query.UniqueQueryId.ToString(), out cacheOut))
                {
                    return(cacheOut);
                }
            }

            var requestWithPolicy = new HttpRequestWithPolicy(this);
            var response          = await requestWithPolicy.Execute(() =>
                                                                    httpClient.GetAsync(string.Format(Target.Url.AbsoluteUri + query.RelativeRequestUrl().TrimStart('/')))
                                                                    ).ConfigureAwait(false);

            if (response.Result?.IsSuccessStatusCode == false || response.Outcome == OutcomeType.Failure)
            {
                return(query.EmptyResponse);
            }

            string jsonResult = await response.Result.Content.ReadAsStringAsync().ConfigureAwait(false);

            TResponse mappedTResponse = query.MapResponse(jsonResult);

            if (cacheIsAvailable && !bypassCache && mappedTResponse != null)
            {
                cache.Add(query.UniqueQueryId, mappedTResponse);

                IEnumerable <CustomQueryCacheValue> cq;
                if (cache.TryGet(CacheSettings.CUSTOM_QUERY_CACHE_KEY, out cq))
                {
                    var indexList = cq.ToList();
                    if (indexList.Any(x => x.CustomQueryKey == query.UniqueQueryId.ToString()) == false)
                    {
                        indexList.Add(new CustomQueryCacheValue
                        {
                            CustomQueryKey = query.UniqueQueryId.ToString(),
                            ContentId      = query.AssociatedContentId.ToString()
                        });
                        cache.Add(CacheSettings.CUSTOM_QUERY_CACHE_KEY, indexList);
                    }
                }
                else
                {
                    var newCacheIndex = new List <CustomQueryCacheValue>
                    {
                        new CustomQueryCacheValue {
                            CustomQueryKey = query.UniqueQueryId.ToString(), ContentId = query.AssociatedContentId.ToString()
                        }
                    };
                    cache.Add(CacheSettings.CUSTOM_QUERY_CACHE_KEY, newCacheIndex);
                }
            }

            return(mappedTResponse);
        }