public async Task <T> GetAsync <T>(string key, Func <Task <T> > acquirer, TimeSpan?duration = null, bool independent = false) { if (TryGet(key, independent, out T value)) { return(value); } if (_scopeAccessor.Value.HasScope(key)) { throw new LockRecursionException(LockRecursionExceptionMessage.FormatInvariant(key)); } // Get the async (semaphore) locker specific to this key using (await KeyedLock.LockAsync("cache:" + key, TimeSpan.FromMinutes(1))) { if (!TryGet(key, independent, out value)) { using (_scopeAccessor.Value.BeginScope(key)) { value = await acquirer(); Put(key, value, duration, _scopeAccessor.Value.Current.Dependencies); return(value); } } } return(value); }
public async Task <T> GetAsync <T>(string key, Func <Task <T> > acquirer, TimeSpan?duration = null, bool independent = false, bool allowRecursion = false) { if (TryGet(key, independent, out T value)) { return(value); } if (!allowRecursion && _scopeAccessor.Value.HasScope(key)) { throw new LockRecursionException(LockRecursionExceptionMessage.FormatInvariant(key)); } // Get the async (semaphore) locker specific to this key using (await KeyedLock.LockAsync("cache:" + key, TimeSpan.FromMinutes(1))) { if (!TryGet(key, independent, out value)) { var scope = !allowRecursion?_scopeAccessor.Value.BeginScope(key) : ActionDisposable.Empty; using (scope) { value = await acquirer(); var dependencies = !allowRecursion ? _scopeAccessor.Value.Current?.Dependencies : (IEnumerable <string>)null; Put(key, value, duration, dependencies); return(value); } } } return(value); }
private async Task <ActionResult> HandleImageAsync( ProcessImageQuery query, CachedImageResult cachedImage, string nameWithoutExtension, string mime, string extension, Func <string, Task <byte[]> > getSourceBufferAsync) { string prevMime = null; if (extension != cachedImage.Extension) { // The query requests another format. // Adjust extension and mime type fo proper ETag creation. extension = cachedImage.Extension; prevMime = mime; mime = MimeTypes.MapNameToMimeType(cachedImage.FileName); } try { if (!cachedImage.Exists) { // Lock concurrent requests to same resource using (await KeyedLock.LockAsync("MediaController.HandleImage." + cachedImage.Path)) { _imageCache.RefreshInfo(cachedImage); // File could have been processed by another request in the meantime, check again. if (!cachedImage.Exists) { // Call inner function byte[] source = await getSourceBufferAsync(prevMime); if (source == null || source.Length == 0) { return(NotFound(mime)); } source = await ProcessAndPutToCacheAsync(cachedImage, source, query); return(new CachedFileResult(mime, cachedImage.LastModifiedUtc.GetValueOrDefault(), () => source, source.LongLength)); } } } if (Request.HttpMethod == "HEAD") { return(new HttpStatusCodeResult(200)); } if (cachedImage.IsRemote && !_streamRemoteMedia) { // Redirect to existing remote file Response.ContentType = mime; return(Redirect(_imageCache.GetPublicUrl(cachedImage.Path))); } else { // Open existing stream return(new CachedFileResult(cachedImage.File, mime)); } } catch (Exception ex) { if (!(ex is ProcessImageException)) { // ProcessImageException is logged already in ImageProcessor Logger.ErrorFormat(ex, "Error processing media file '{0}'.", cachedImage.Path); } return(new HttpStatusCodeResult(500, ex.Message)); } }
public async Task ExecuteAsync(MediaHandlerContext context) { if (!IsProcessable(context)) { return; } var query = context.ImageQuery; var pathData = context.PathData; var cachedImage = ImageCache.Get(context.MediaFileId, pathData, query); if (!pathData.Extension.IsCaseInsensitiveEqual(cachedImage.Extension)) { // The query requests another format. // Adjust extension and mime type fo proper ETag creation. pathData.Extension = cachedImage.Extension; pathData.MimeType = cachedImage.MimeType; } var exists = cachedImage.Exists; if (exists && cachedImage.FileSize == 0) { // Empty file means: thumb extraction failed before and will most likely fail again. // Don't bother proceeding. context.Exception = ExceptionFactory.ExtractThumbnail(cachedImage.FileName); context.Executed = true; return; } if (!exists) { // Lock concurrent requests to same resource using (await KeyedLock.LockAsync("ImageHandlerBase.Execute." + cachedImage.Path)) { ImageCache.RefreshInfo(cachedImage); // File could have been processed by another request in the meantime, check again. if (!cachedImage.Exists) { // Call inner function var sourceFile = context.SourceFile; if (sourceFile == null || sourceFile.Size == 0) { context.Executed = true; return; } var inputStream = sourceFile.OpenRead(); if (inputStream == null) { context.Exception = ExceptionFactory.ExtractThumbnail(sourceFile.Path, T("Admin.Media.Exception.NullInputStream")); context.Executed = true; return; } try { await ProcessImageAsync(context, cachedImage, inputStream); } catch (Exception ex) { Logger.Error(ex); if (ex is ExtractThumbnailException) { // Thumbnail extraction failed and we must assume that it always will fail. // Therefore we create an empty file to prevent repetitive processing. using (var memStream = new MemoryStream()) { await ImageCache.PutAsync(cachedImage, memStream); } } context.Exception = ex; context.Executed = true; return; } finally { if (inputStream != null) { inputStream.Dispose(); } } if (context.ResultImage != null) { ImageCache.Put(cachedImage, context.ResultImage); context.ResultFile = cachedImage.File; } context.Executed = true; return; } } } // Cached image existed already context.ResultFile = cachedImage.File; context.Executed = true; }