private async Task ProcessWithMemoryCache(HttpContext context, string cacheKey, ImageJobInfo info) { var isCached = memoryCache.TryGetValue(cacheKey, out ArraySegment <byte> imageBytes); var isContentTypeCached = memoryCache.TryGetValue(cacheKey + ".contentType", out string contentType); if (isCached && isContentTypeCached) { logger?.LogInformation("Serving {0}?{1} from memory cache", info.FinalVirtualPath, info.CommandString); } else { if (info.HasParams) { logger?.LogInformation($"Memory Cache Miss: Processing image {info.FinalVirtualPath}?{info.CommandString}"); var imageData = await info.ProcessUncached(); imageBytes = imageData.ResultBytes; contentType = imageData.ContentType; } else { logger?.LogInformation($"Memory Cache Miss: Proxying image {info.FinalVirtualPath}?{info.CommandString}"); contentType = PathHelpers.ContentTypeForImageExtension(info.EstimatedFileExtension); imageBytes = new ArraySegment <byte>(await info.GetPrimaryBlobBytesAsync()); } // Set cache options. var cacheEntryOptions = new MemoryCacheEntryOptions() .SetSize(imageBytes.Count) .SetSlidingExpiration(options.MemoryCacheSlidingExpiration); var cacheEntryMetaOptions = new MemoryCacheEntryOptions() .SetSize(contentType.Length * 2) .SetSlidingExpiration(options.MemoryCacheSlidingExpiration); memoryCache.Set(cacheKey, imageBytes, cacheEntryOptions); memoryCache.Set(cacheKey + ".contentType", contentType, cacheEntryMetaOptions); } // write to stream context.Response.ContentType = contentType; context.Response.ContentLength = imageBytes.Count; SetCachingHeaders(context, cacheKey); await context.Response.Body.WriteAsync(imageBytes.Array, imageBytes.Offset, imageBytes.Count); }
private async Task ProcessWithDistributedCache(HttpContext context, string cacheKey, ImageJobInfo info) { var imageBytes = await distributedCache.GetAsync(cacheKey); var contentType = await distributedCache.GetStringAsync(cacheKey + ".contentType"); if (imageBytes != null && contentType != null) { logger?.LogInformation("Serving {0}?{1} from distributed cache", info.FinalVirtualPath, info.CommandString); } else { if (info.HasParams) { logger?.LogInformation($"Distributed Cache Miss: Processing image {info.FinalVirtualPath}?{info.CommandString}"); var imageData = await info.ProcessUncached(); imageBytes = imageData.ResultBytes.Count != imageData.ResultBytes.Array?.Length ? imageData.ResultBytes.ToArray() : imageData.ResultBytes.Array; contentType = imageData.ContentType; } else { logger?.LogInformation($"Distributed Cache Miss: Proxying image {info.FinalVirtualPath}?{info.CommandString}"); contentType = PathHelpers.ContentTypeForImageExtension(info.EstimatedFileExtension); imageBytes = await info.GetPrimaryBlobBytesAsync(); } // Set cache options. var cacheEntryOptions = new DistributedCacheEntryOptions() .SetSlidingExpiration(options.DistributedCacheSlidingExpiration); await distributedCache.SetAsync(cacheKey, imageBytes, cacheEntryOptions); await distributedCache.SetStringAsync(cacheKey + ".contentType", contentType, cacheEntryOptions); } // write to stream context.Response.ContentType = contentType; context.Response.ContentLength = imageBytes.Length; SetCachingHeaders(context, cacheKey); await context.Response.Body.WriteAsync(imageBytes, 0, imageBytes.Length); }
private async Task ProcessWithStreamCache(HttpContext context, string cacheKey, ImageJobInfo info) { var keyBytes = Encoding.UTF8.GetBytes(cacheKey); var typeName = streamCache.GetType().Name; var cacheResult = await streamCache.GetOrCreateBytes(keyBytes, async (cancellationToken) => { if (info.HasParams) { logger?.LogDebug("{CacheName} miss: Processing image {VirtualPath}?{Querystring}", typeName, info.FinalVirtualPath, info.ToString()); var result = await info.ProcessUncached(); if (result.ResultBytes.Array == null) { throw new InvalidOperationException("Image job returned zero bytes."); } return(new Tuple <string, ArraySegment <byte> >(result.ContentType, result.ResultBytes)); } logger?.LogDebug("{CacheName} miss: Proxying image {VirtualPath}", typeName, info.FinalVirtualPath); var bytes = await info.GetPrimaryBlobBytesAsync(); return(new Tuple <string, ArraySegment <byte> >(null, bytes)); }, CancellationToken.None, false); if (cacheResult.Status != null) { GlobalPerf.Singleton.IncrementCounter($"{typeName}_{cacheResult.Status}"); } if (cacheResult.Data != null) { await using (cacheResult.Data) { if (cacheResult.Data.Length < 1) { throw new InvalidOperationException($"{typeName} returned cache entry with zero bytes"); } SetCachingHeaders(context, cacheKey); await MagicBytes.ProxyToStream(cacheResult.Data, context.Response); } logger?.LogDebug("Serving from {CacheName} {VirtualPath}?{CommandString}", typeName, info.FinalVirtualPath, info.CommandString); } else { // TODO explore this failure path better throw new NullReferenceException("Caching failed: " + cacheResult.Status); } }
private async Task ProcessWithSqliteCache(HttpContext context, string cacheKey, ImageJobInfo info) { var cacheResult = await sqliteCache.GetOrCreate(cacheKey, async() => { if (info.HasParams) { logger?.LogInformation($"Sqlite Cache Miss: Processing image {info.FinalVirtualPath}?{info.CommandString}"); var imageData = await info.ProcessUncached(); var imageBytes = imageData.ResultBytes.Count != imageData.ResultBytes.Array?.Length ? imageData.ResultBytes.ToArray() : imageData.ResultBytes.Array; var contentType = imageData.ContentType; return(new SqliteCacheEntry() { ContentType = contentType, Data = imageBytes }); } else { logger?.LogInformation($"Sqlite Cache Miss: Proxying image {info.FinalVirtualPath}?{info.CommandString}"); var contentType = PathHelpers.ContentTypeForImageExtension(info.EstimatedFileExtension); return(new SqliteCacheEntry() { ContentType = contentType, Data = await info.GetPrimaryBlobBytesAsync() }); } }); // write to stream context.Response.ContentType = cacheResult.ContentType; context.Response.ContentLength = cacheResult.Data.Length; SetCachingHeaders(context, cacheKey); await context.Response.Body.WriteAsync(cacheResult.Data, 0, cacheResult.Data.Length); }