void ValidateCacheState()
 {
     if (!isCacheLoaded)
     {
         QueryCacheService.Load();
         isCacheLoaded = true;
     }
 }
        public async Task <RequestWrapper <UserLadderData> > GetUserDataFromLadder(UserGameProfileId userGameProfileId, Ladders ladder, int timeout)
        {
            ValidateCacheState();

            RequestWrapper <UserLadderData> requestWrapper = new RequestWrapper <UserLadderData>();
            Dictionary <string, object>     logProperties  = new Dictionary <string, object>
            {
                { "timeout", timeout },
                { "game-profile-id", userGameProfileId.ProfileId },
                { "ladder", ladder.ToString() }
            };

            RequestState requestState = null;

            try
            {
                if (!StorageService.Has("stringResources"))
                {
                    throw new InvalidOperationException("App resources unaviable while sending request");
                }

                if (string.IsNullOrEmpty(userGameProfileId.ProfileId))
                {
                    throw new InvalidOperationException("Missing user id");
                }

                var stringResources = StorageService.Get <AoeNetAPIStringResources>("stringResources");

                //preapare query
                var query = HttpUtility.ParseQueryString(string.Empty);

                query["profile_id"]     = HttpUtility.UrlEncode(userGameProfileId.ProfileId);
                query["leaderboard_id"] = HttpUtility.UrlEncode(((int)ladder).ToString());
                query["game"]           = HttpUtility.UrlEncode("aoe2de"); //only aviable for DE at this moment, https://aoe2.net/#api

                var finallQuery = "https://aoe2.net/api/leaderboard?" + query.ToString();
                logProperties.Add("query", finallQuery);

                //create cts
                var cts = new CancellationTokenSource();
                //create timeout handler for current query
                requestState = AddTimeoutHandler(cts, timeout);

                requestState.isRunning    = true;
                requestWrapper.RequestUrl = finallQuery;
                //sumbit query via query cache service
                requestWrapper.RequestResponseWrapper = await QueryCacheService.GetOrUpdate(
                    finallQuery,
                    cts.Token,
                    DateTime.UtcNow.AddHours(1.5)
                    );

                if (!requestWrapper.RequestResponseWrapper.IsSuccess)
                {
                    throw new AggregateException("Request failed", requestWrapper.RequestResponseWrapper.Exception);
                }

                requestWrapper.Value = (this as IUserDataProcessingService).ProcessUserDataFromLadder(requestWrapper.RequestResponseWrapper.ResponseContent, stringResources);
            }
            catch (Exception e) // request timedout
            {
                if (
                    e is StackOverflowException ||
                    e is ThreadAbortException ||
                    e is AccessViolationException
                    )
                {
                    throw e;
                }

                string responseContent = "";
                string responseCode    = "";

                if (requestWrapper != null) //to make sure this will not conflict with test cases
                {
                    if (requestWrapper.RequestResponseWrapper != null)
                    {
                        if (requestWrapper.RequestResponseWrapper.ResponseContent != null)
                        {
                            responseContent = requestWrapper.RequestResponseWrapper.ResponseContent;
                        }

                        if (requestWrapper.RequestResponseWrapper.Response != null) //to make sure this will not conflict with test cases
                        {
                            responseCode = requestWrapper.RequestResponseWrapper.Response.StatusCode.ToString();
                        }
                    }
                }

                logProperties.Add("stack", e.StackTrace);
                logProperties.Add("response-code", responseCode);
                logProperties.Add("response-raw", responseContent);
                LogService.Error($"Error while requesting ladder: {e.ToString()}", logProperties);

                requestWrapper.Exception = e;
            }
            finally
            {
                if (requestState != null)
                {
                    requestState.isRunning = false; //prevent cancelling operation by timeout handler
                }
            }

            return(requestWrapper);
        }