Exemple #1
0
 public async Task TryRemoveAsync(CacheIdentity id)
 {
     using (await _locker.AcquireAsync())
     {
         _cache.Remove(id);
     }
 }
Exemple #2
0
 public async Task TryAddAsync(CacheIdentity id, CacheEntry entry)
 {
     using (await _locker.AcquireAsync())
     {
         _cache.EnsureKeyExists(id, new List <CacheEntry>());
         _cache[id].Add(entry);
     }
 }
Exemple #3
0
 public async Task <IList <CacheEntry> > TryGetAsync(CacheIdentity id)
 {
     using (await _locker.AcquireAsync())
     {
         if (_cache.ContainsKey(id))
         {
             return(_cache[id]);
         }
         else
         {
             return(null);
         }
     }
 }
        public async Task InvokeAsync(HttpContext httpContext, URIProviderService uriProvider, IServiceProvider serviceProvider, ILoggerFactory loggerFactory, UserManager <User> userManager)
        {
            var logger = loggerFactory.CreateLogger("Response caching");

            var requestURI = uriProvider.GetCurrentRequestURI();
            var cacheKey   = new CacheIdentity(requestURI);
            var cacheEntry = await tryGetCacheAsync();

            var manager = new CacheManagerFeature(_storage, cacheEntry?.IsRequestDataSet ?? false, cacheEntry?.RequestData);

            httpContext.Features.Set <ICacheManagerFeature>(manager);

            if (cacheEntry != null)
            {
                logger.LogInformation($"Serving response from cache...");

                await setResponseAsync();
                await executeHandlerAsync();
            }
            else
            {
                await nextAndPopulateAsync();
            }

            ///////////////////////////////////////////////////////////////////////

            async Task setResponseAsync()
            {
                httpContext.Response.StatusCode = cacheEntry.StatusCode;
                foreach (var header in cacheEntry.Headers)
                {
                    httpContext.Response.Headers[header.Key] = header.Value;
                }
                await httpContext.Response.Body.WriteAsync(cacheEntry.ResponseBody);
            }

            async Task executeHandlerAsync()
            {
                CacheHandlerDelegate handler = null;
                var has = cacheEntry.CachingInfo.CacheEntryKey == null
                    ? false
                    : _cacheHandlers.TryGetValue(cacheEntry.CachingInfo.CacheEntryKey, out handler);

                if (has && handler != null)
                {
                    var scope = new CacheScope(cacheEntry.IsRequestDataSet, cacheEntry.RequestData, serviceProvider);
                    await handler(scope);
                }
            }

            async Task <CacheEntry> tryGetCacheAsync()
            {
                var cache = await _storage.TryGetAsync(cacheKey);

                if (cache != null)
                {
                    foreach (var c in cache)
                    {
                        if (await c.Policy.CanBeServedAsync(httpContext, serviceProvider, c.PolicyMetadata))
                        {
                            return(c);
                        }
                    }
                }

                return(null);
            }

            async Task nextAndPopulateAsync()
            {
                byte[] cacheBuffer = null;
                {
                    var originalBodyStream = httpContext.Response.Body;
                    var cacheStream        = new MemoryStream();
                    httpContext.Response.Body = cacheStream;

                    try
                    {
                        // Allow MVC action to execute (so that we will be able to get endpoint info later)
                        await _next(httpContext);
                    }
                    finally
                    {
                        cacheBuffer = cacheStream.ToArray();
                        await originalBodyStream.WriteAsync(cacheBuffer);

                        httpContext.Response.Body = originalBodyStream;
                    }
                }

                var endpoint = httpContext.Features.Get <IEndpointFeature>()?.Endpoint;

                // Endpoint will be null if the URL didn't match an action, e.g. a 404 response
                if (endpoint != null && httpContext.Response.IsSuccessStatusCode())
                {
                    var cachingInfo = tryGetCacheAttribute();
                    if (cachingInfo != null)
                    {
                        if (cachingInfo.CacheDuration > 0)
                        {
                            var policy = _cachePolicies[cachingInfo.CachePolicy];
                            if (await policy.CanBeSavedAsync(httpContext, serviceProvider))
                            {
                                var routeData = httpContext.Features
                                                .Get <RouteDataProviderFeature>().RouteData
                                                .ToArray();
                                var cache = new CacheEntry(cachingInfo,
                                                           cacheBuffer,
                                                           httpContext.Response.StatusCode,
                                                           httpContext.Response.Headers,
                                                           manager.IsRequestDataSet,
                                                           manager.RequestData,
                                                           routeData,
                                                           policy,
                                                           await policy.GenerateMetadata(httpContext, serviceProvider));
                                await _storage.TryAddAsync(cacheKey, cache);

                                logger.LogInformation($"Response for request to {requestURI} has been added to cache for {cachingInfo.CacheDuration}s");
                            }
                        }
                    }

                    ServerResponseCacheAttribute tryGetCacheAttribute()
                    {
                        // Does not work for page handlers
                        var attr = endpoint.Metadata.GetMetadata <ServerResponseCacheAttribute>();

                        if (attr == null) // Fallback for page handlers
                        {
                            var attributesProvider = httpContext.Features
                                                     .Select(f => f.Value as PageHandlerAttributesProviderFeature)
                                                     .SkipNulls()
                                                     .FirstOrDefault();
                            attr = attributesProvider == null
                                ? attr
                                : attributesProvider.Attributes.Select(a => a as ServerResponseCacheAttribute)
                                   .SkipNulls()
                                   .FirstOrDefault();
                        }

                        return(attr);
                    }
                }
            }
        }