public async Task TryRemoveAsync(CacheIdentity id) { using (await _locker.AcquireAsync()) { _cache.Remove(id); } }
public async Task TryAddAsync(CacheIdentity id, CacheEntry entry) { using (await _locker.AcquireAsync()) { _cache.EnsureKeyExists(id, new List <CacheEntry>()); _cache[id].Add(entry); } }
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); } } } }