protected override async Task <HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { var resourceKey = GetResourceKey(request.RequestUri, _varyHeaders, request); CacheableEntity cacheableEntity = null; var cacheControlHeader = new CacheControlHeaderValue { Private = true, MustRevalidate = true, MaxAge = TimeSpan.FromSeconds(0) }; if (request.Method == HttpMethod.Get) { var eTags = request.Headers.IfNoneMatch; var modifiedSince = request.Headers.IfModifiedSince; var anyEtagsFromTheClientExist = eTags.Any(); var doWeHaveAnyCacheableEntityForTheRequest = _eTagCacheDictionary.TryGetValue(resourceKey, out cacheableEntity); if (anyEtagsFromTheClientExist) { if (doWeHaveAnyCacheableEntityForTheRequest) { if (eTags.Any(x => x.Tag == cacheableEntity.EntityTag.Tag)) { var tempResp = new HttpResponseMessage(HttpStatusCode.NotModified); tempResp.Headers.CacheControl = cacheControlHeader; return(tempResp); } } } else if (modifiedSince.HasValue) { if (doWeHaveAnyCacheableEntityForTheRequest) { if (cacheableEntity.IsValid(modifiedSince.Value)) { var tempResp = new HttpResponseMessage(HttpStatusCode.NotModified); tempResp.Headers.CacheControl = cacheControlHeader; return(tempResp); } } } } HttpResponseMessage response; try { response = await base.SendAsync(request, cancellationToken); } catch (Exception ex) { response = request.CreateErrorResponse( HttpStatusCode.InternalServerError, ex); } if (response.IsSuccessStatusCode) { if (request.Method == HttpMethod.Get && !_eTagCacheDictionary.TryGetValue(resourceKey, out cacheableEntity)) { cacheableEntity = new CacheableEntity(resourceKey); cacheableEntity.EntityTag = GenerateETag(); cacheableEntity.LastModified = DateTimeOffset.Now; _eTagCacheDictionary.AddOrUpdate( resourceKey, cacheableEntity, (k, e) => cacheableEntity); } if (request.Method == HttpMethod.Put || request.Method == HttpMethod.Post || request.Method == HttpMethod.Delete) { HashSet <string> invalidCaches = new HashSet <string>(); invalidCaches.Add(GetRequestUri(request.RequestUri)); CacheInvalidationStore.ForEach( func => func(GetRequestUri(request.RequestUri)) .ForEach(uri => invalidCaches.Add(uri))); invalidCaches.ForEach(invalidCacheUri => { var cacheEntityKeys = _eTagCacheDictionary.Keys.Where( x => x.StartsWith( string.Format("{0}:", invalidCacheUri), StringComparison.InvariantCultureIgnoreCase)); cacheEntityKeys.ForEach(key => { if (!string.IsNullOrEmpty(key)) { CacheableEntity outVal = null; _eTagCacheDictionary.TryRemove(key, out outVal); } }); }); } else { response.Headers.CacheControl = cacheControlHeader; response.Headers.ETag = cacheableEntity.EntityTag; response.Content.Headers.LastModified = cacheableEntity.LastModified; _varyHeaders.ForEach( varyHeader => response.Headers.Vary.Add(varyHeader)); } } return(response); }
protected override async Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { var resourceKey = GetResourceKey(request.RequestUri, _varyHeaders, request); CacheableEntity cacheableEntity = null; var cacheControlHeader = new CacheControlHeaderValue { Private = true, MustRevalidate = true, MaxAge = TimeSpan.FromSeconds(0) }; if (request.Method == HttpMethod.Get) { var eTags = request.Headers.IfNoneMatch; var modifiedSince = request.Headers.IfModifiedSince; var anyEtagsFromTheClientExist = eTags.Any(); var doWeHaveAnyCacheableEntityForTheRequest = _eTagCacheDictionary.TryGetValue(resourceKey, out cacheableEntity); if (anyEtagsFromTheClientExist) { if (doWeHaveAnyCacheableEntityForTheRequest) { if (eTags.Any(x => x.Tag == cacheableEntity.EntityTag.Tag)) { var tempResp = new HttpResponseMessage(HttpStatusCode.NotModified); tempResp.Headers.CacheControl = cacheControlHeader; return tempResp; } } } else if (modifiedSince.HasValue) { if (doWeHaveAnyCacheableEntityForTheRequest) { if (cacheableEntity.IsValid(modifiedSince.Value)) { var tempResp = new HttpResponseMessage(HttpStatusCode.NotModified); tempResp.Headers.CacheControl = cacheControlHeader; return tempResp; } } } } HttpResponseMessage response; try { response = await base.SendAsync(request, cancellationToken); } catch (Exception ex) { response = request.CreateErrorResponse( HttpStatusCode.InternalServerError, ex); } if (response.IsSuccessStatusCode) { if (request.Method == HttpMethod.Get && !_eTagCacheDictionary.TryGetValue(resourceKey, out cacheableEntity)) { cacheableEntity = new CacheableEntity(resourceKey); cacheableEntity.EntityTag = GenerateETag(); cacheableEntity.LastModified = DateTimeOffset.Now; _eTagCacheDictionary.AddOrUpdate( resourceKey, cacheableEntity, (k, e) => cacheableEntity); } if (request.Method == HttpMethod.Put || request.Method == HttpMethod.Post || request.Method == HttpMethod.Delete) { HashSet<string> invalidCaches = new HashSet<string>(); invalidCaches.Add(GetRequestUri(request.RequestUri)); CacheInvalidationStore.ForEach( func => func(GetRequestUri(request.RequestUri)) .ForEach(uri => invalidCaches.Add(uri))); invalidCaches.ForEach(invalidCacheUri => { var cacheEntityKeys = _eTagCacheDictionary.Keys.Where( x => x.StartsWith( string.Format("{0}:", invalidCacheUri), StringComparison.InvariantCultureIgnoreCase)); cacheEntityKeys.ForEach(key => { if (!string.IsNullOrEmpty(key)) { CacheableEntity outVal = null; _eTagCacheDictionary.TryRemove(key, out outVal); } }); }); } else { response.Headers.CacheControl = cacheControlHeader; response.Headers.ETag = cacheableEntity.EntityTag; response.Content.Headers.LastModified = cacheableEntity.LastModified; _varyHeaders.ForEach( varyHeader => response.Headers.Vary.Add(varyHeader)); } } return response; }