protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { HttpResponseMessage response = null; CacheEnabledRequestMessage cacheRequest = request as CacheEnabledRequestMessage; if (cacheRequest != null && cacheRequest.CacheOptions.UseFileCache) { Uri uri = request.RequestUri; using (var uriLock = new UriLock(uri, cancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); // check cache Stream stream = null; if (_fileCache.TryGet(uri, out stream)) { DataTraceSources.Verbose("[HttpClient] Cached Length: {0}", "" + stream.Length); response = new CacheResponse(stream); } else { // get the item and add it to the cache DataTraceSources.Verbose("[HttpClient] GET {0}", uri.AbsoluteUri); response = await base.SendAsync(request, cancellationToken); if (response.IsSuccessStatusCode) { DataTraceSources.Verbose("[HttpClient] Caching {0}"); _fileCache.Add(uri, cacheRequest.CacheOptions.MaxCacheLife, await response.Content.ReadAsStreamAsync()); } } } } if (response == null) { // skip cache DataTraceSources.Verbose("[HttpClient] GET {0}", request.RequestUri.AbsoluteUri); response = await base.SendAsync(request, cancellationToken); } return(response); }
private async Task <JObject> GetFileInternal(Uri uri, TimeSpan cacheTime, bool cacheInGraph = true, bool cloneJson = true) { if (uri == null) { throw new ArgumentNullException("uri"); } if (cacheTime == null) { throw new ArgumentNullException("cacheTime"); } bool cache = cacheTime.TotalSeconds > 0; // request the root document Uri fixedUri = Utility.GetUriWithoutHash(uri); Stream stream = null; JObject result = null; JObject clonedResult = null; // the copy we give the caller try { using (var uriLock = new UriLock(fixedUri)) { if (!cache || !_fileCache.TryGet(fixedUri, out stream)) { // the stream was not in the cache or we are skipping the cache int tries = 0; // try up to 5 times to be a little more robust while (stream == null && tries < 5) { tries++; try { HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, fixedUri.AbsoluteUri); DataTraceSources.Verbose("[HttpClient] GET {0}", fixedUri.AbsoluteUri); var response = await _httpClient.SendAsync(request); Debug.Assert(response.StatusCode == HttpStatusCode.OK, "Received non-OK status code response from " + request.RequestUri.ToString()); if (response.StatusCode == HttpStatusCode.OK) { stream = await response.Content.ReadAsStreamAsync(); if (stream != null) { if (cache) { DataTraceSources.Verbose("[HttpClient] Caching {0}"); _fileCache.Add(fixedUri, _lifeSpan, stream); } DataTraceSources.Verbose("[HttpClient] 200 OK Length: {0}", "" + stream.Length); result = await StreamToJson(stream); } } else { DataTraceSources.Verbose("[HttpClient] FAILED {0}", "" + (int)response.StatusCode); result = new JObject(); result.Add("HttpStatusCode", (int)response.StatusCode); } } catch (HttpRequestException ex) { Debug.Fail("WebRequest failed: " + ex.ToString()); DataTraceSources.Verbose("[HttpClient] FAILED {0}", ex.ToString()); // request error result = new JObject(); result.Add("HttpRequestException", ex.ToString()); } } } else { // the stream was in the cache DataTraceSources.Verbose("[HttpClient] Cached Length: {0}", "" + stream.Length); result = await StreamToJson(stream); } } } finally { if (stream != null) { stream.Dispose(); } } if (result != null) { // this must be called before the entity cache thread starts using it if (cloneJson) { clonedResult = result.DeepClone() as JObject; } else { // in some scenarios we can skip cloning, such as when we are throwing away the result clonedResult = result; } if (cacheInGraph) { // this call is only blocking if the cache is overloaded _entityCache.Add(result, fixedUri); } } return(clonedResult); }