public void AddOrUpdate(EntityTagKey key, TimedEntityTagHeaderValue eTag)
 {
     _eTagCache.AddOrUpdate(key, eTag, (theKey, oldValue) => eTag);
     _routePatternCache.AddOrUpdate(key.RoutePattern, new HashSet<EntityTagKey>() { key },
         (routePattern, hashSet) =>
             {
                 hashSet.Add(key);
                 return hashSet;
             });
 }
Example #2
0
        protected void ExecuteCacheInvalidationRules(EntityTagKey entityTagKey,
			HttpRequestMessage request,
			HttpResponseMessage response)
        {
            new[]
                {
                    InvalidateCache(entityTagKey, request, response), // general invalidation
                    PostInvalidationRule(entityTagKey, request, response)
                }
                .Chain()();
        }
Example #3
0
        protected void ExecuteCacheAdditionRules(EntityTagKey entityTagKey,
			HttpRequestMessage request,
			HttpResponseMessage response,
			IEnumerable<KeyValuePair<string, IEnumerable<string>>> varyHeaders)
        {
            new[]
                {
                    AddCaching(entityTagKey, request, response, varyHeaders), // general caching
                }
                .Chain()();
        }
Example #4
0
        /// <summary>
        /// This is a scenario where we have a POST to a resource
        /// and it needs to invalidate the cache to that resource
        /// and all its linked URLs
        /// 
        /// For example:
        /// POST /api/cars => invalidate /api/cars
        /// also it might invalidate /api/cars/fastest in which case
        /// /api/cars/fastest must be one of the linked URLs
        /// </summary>
        /// <param name="entityTagKey">entityTagKey</param>
        /// <param name="request">request</param>
        /// <param name="response">response</param>
        /// <returns>returns the function to execute</returns>
        internal Action PostInvalidationRule(
			EntityTagKey entityTagKey,
			HttpRequestMessage request, 
			HttpResponseMessage response)
        {
            return () =>
            {
                if(request.Method!=HttpMethod.Post)
                    return;

                // if location header is set (for newly created resource), invalidate cache for it
                // this normally should not be necessary as the item is new and should not be in the cache
                // but releasing a non-existent item from cache should not have a big overhead
                if (response.Headers.Location != null)
                {
                    _entityTagStore.RemoveAllByRoutePattern(response.Headers.Location.ToString());
                }

            };
        }
Example #5
0
        /// <summary>
        /// This invalidates the resource based on routePattern
        /// for methods POST, PUT and DELETE.
        /// It also removes for all linked URLs
        /// </summary>
        /// <param name="entityTagKey"></param>
        /// <param name="request"></param>
        /// <param name="response"></param>
        /// <returns></returns>
        internal Action InvalidateCache(
			EntityTagKey entityTagKey,
			HttpRequestMessage request,
			HttpResponseMessage response)
        {
            return
                () =>
            {

                if (!request.Method.Method.IsIn("PUT", "DELETE", "POST"))
                    return;

                string uri = UriTrimmer(request.RequestUri);

                // remove pattern
                _entityTagStore.RemoveAllByRoutePattern(entityTagKey.RoutePattern);

                // remove all related URIs
                var linkedUrls = LinkedRoutePatternProvider(uri, request.Method);
                foreach (var linkedUrl in linkedUrls)
                    _entityTagStore.RemoveAllByRoutePattern(linkedUrl);

            };
        }
Example #6
0
        /// <summary>
        /// Adds caching for GET and PUT if 
        /// cache control provided is not null
        /// With PUT, since cache has been alreay invalidated,
        /// we provide the new ETag (old one has been cleared in invalidation phase)
        /// </summary>
        /// <param name="entityTagKey"></param>
        /// <param name="request"></param>
        /// <param name="response"></param>
        /// <param name="varyHeaders"></param>
        /// <returns></returns>
        internal Action AddCaching(
			EntityTagKey entityTagKey,
			HttpRequestMessage request,
			HttpResponseMessage response,
			IEnumerable<KeyValuePair<string, IEnumerable<string>>> varyHeaders)
        {
            return
                () =>
                {

                    var cacheControlHeaderValue = CacheControlHeaderProvider(request);
                    if (cacheControlHeaderValue == null)
                        return;

                    TimedEntityTagHeaderValue eTagValue;

                    string uri = UriTrimmer(request.RequestUri);

                    // in case of GET and no ETag
                    // in case of PUT, we should return the new ETag of the resource
                    // NOTE: No need to check if it is in the cache. If it were, it would not get
                    // here
                    if (request.Method == HttpMethod.Get || request.Method == HttpMethod.Put)
                    {
                        // create new ETag only if it does not already exist
                        if (!_entityTagStore.TryGetValue(entityTagKey, out eTagValue))
                        {
                            eTagValue = new TimedEntityTagHeaderValue(ETagValueGenerator(uri, varyHeaders));
                            _entityTagStore.AddOrUpdate(entityTagKey, eTagValue);
                        }

                        // set ETag
                        response.Headers.ETag = eTagValue.ToEntityTagHeaderValue();

                        // set last-modified
                        if (AddLastModifiedHeader && response.Content != null && !response.Content.Headers.Any(x => x.Key.Equals(HttpHeaderNames.LastModified,
                            StringComparison.CurrentCultureIgnoreCase)))
                        {
                            response.Content.Headers.Add(HttpHeaderNames.LastModified, eTagValue.LastModified.ToString("r"));
                        }

                        // set Vary
                        if (AddVaryHeader && _varyByHeaders != null && _varyByHeaders.Length > 0)
                        {
                            response.Headers.Add(HttpHeaderNames.Vary, _varyByHeaders);
                        }

                        response.Headers.TryAddWithoutValidation(HttpHeaderNames.CacheControl, cacheControlHeaderValue.ToString());

                    }

                };
        }
 public bool TryRemove(EntityTagKey key)
 {
     TimedEntityTagHeaderValue entityTagHeaderValue;
     return _eTagCache.TryRemove(key, out entityTagHeaderValue);
 }
 public bool TryGetValue(EntityTagKey key, out TimedEntityTagHeaderValue eTag)
 {
     return _eTagCache.TryGetValue(key, out eTag);
 }