private IEnumerable <ItemOrderStats> RetrieveItems(IEnumerable <int> typesToRequest, int regionId, string cacheKey)
        {
            var resultItems = new List <ItemOrderStats>();

            if (!_isServiceAvailable)
            {
                return(resultItems);
            }

            var requestUri  = new Uri($"https://market.fuzzwork.co.uk/aggregates/?region={regionId}&types={string.Join(",", typesToRequest)}");
            var requestTask = _requestProvider.GetAsync(requestUri);

            requestTask.Wait();             // wait for the completion (we're in a background task anyways)

            if (!requestTask.Result.IsSuccessStatusCode ||
                WebServiceExceptionHelper.IsServiceUnavailableError(requestTask.Exception))
            {
                _isServiceAvailable = false;                 // TODO: postpone next check.
                return(resultItems);
            }

            if (!requestTask.IsTaskSuccessfullyCompleted())
            {
                return(resultItems);
            }

            var contentStreamTask = requestTask.Result.Content.ReadAsStreamAsync();

            contentStreamTask.Wait();

            using (var reader = new StreamReader(contentStreamTask.Result))
            {
                try
                {
                    // process result
                    var retrievedItems = ParseResult(reader.ReadToEnd());

                    // cache it.
                    foreach (var item in retrievedItems)
                    {
                        _regionDataCache.Add(
                            ItemKeyFormat.FormatInvariant(item.ItemTypeId, cacheKey),
                            item,
                            DateTimeOffset.Now.Add(_cacheTtl));
                        resultItems.Add(item);
                    }
                }
                catch (Exception ex)
                {
                    Trace.TraceError(ex.FormatException());
                    throw;
                }
            }

            return(resultItems);
        }
        private Task <IEnumerable <ItemOrderStats> > GetOrderStats(int[] typeIds, int regionId)
        {
            return(Task <IEnumerable <ItemOrderStats> > .Factory.TryRun(
                       () =>
            {
                var cacheKey = regionId.ToInvariantString();
                // Get all cached items for the selected region.
                var cachedItemStats = typeIds
                                      .Select(typeId => _regionDataCache.Get <ItemOrderStats>(ItemKeyFormat.FormatInvariant(typeId, cacheKey))).ToList();
                // Add to the result set not expired items for quered types from cache.
                var result = cachedItemStats.Where(item => item?.Data != null && !item.IsDirty).Select(item => item.Data).ToList();
                // Get only type IDs that not in the cache.
                var typesToRequest = typeIds.Except(result.Select(stats => stats.ItemTypeId)).ToArray();

                if (!typesToRequest.Any())
                {
                    return result;
                }

                result.AddRange(RetrieveItems(typesToRequest, regionId, cacheKey));

                // Dirty cached items is better than nothing in the end. Add them to dirty cache in case of no data/error.
                var fromDirtyCache = cachedItemStats
                                     .Where(
                    item => item?.Data != null && item.IsDirty &&
                    result.Any(resultItem => item.Data.ItemTypeId == resultItem.ItemTypeId))
                                     .Select(item => item.Data);
                result.AddRange(fromDirtyCache);

                return result;
            }));
        }