public virtual async Task Remove() { Setup(); try { var data = new BundleCacheData { Version = "1", Timestamp = DateTimeOffset.UtcNow, Content = Encoding.UTF8.GetBytes("html { }") }; var key = new BundleCacheKey(0, "/test.css", QueryString.Empty); var factoryRun = false; IBundleCacheItem addItem = await Cache.GetOrAddAsync(key, ct => { factoryRun = true; return(Task.FromResult(data)); }, CancellationToken.None, BundleCacheOptions.Default, lockFile : true); Assert.True(factoryRun); if (addItem.FileReleaser != NullDisposable.Instance) { // file is not released so the next call must block (remove should acquire a writer lock) Task removeItemTask = Cache.RemoveAsync(key, CancellationToken.None); await AsyncHelper.NeverCompletesAsync(removeItemTask); // releasing file addItem.FileReleaser.Dispose(); try { await removeItemTask; } catch (ApplicationException) { } } // re-checking await Cache.RemoveAsync(key, CancellationToken.None); factoryRun = false; await Cache.GetOrAddAsync(key, ct => { factoryRun = true; return(Task.FromResult(data)); }, CancellationToken.None, BundleCacheOptions.Default, lockFile : false); Assert.True(factoryRun); } finally { Teardown(); } }
public async Task <bool> TryEnsureUrlAsync(HttpContext httpContext) { PathString branchPath = httpContext.Request.Path; if (!branchPath.StartsWithSegments(_bundlingContext.BundlesPathPrefix, out PathString bundlePath)) { return(false); } QueryString query = httpContext.Request.QueryString; _urlHelper.RemoveVersion(ref bundlePath, ref query); if (!_bundles.TryGetValue(bundlePath, out IBundleModel bundle)) { return(false); } IScopedDisposer disposer = httpContext.RequestServices.GetRequiredService <IScopedDisposer>(); query = UrlUtils.NormalizeQuery(query, out IDictionary <string, StringValues> @params); if (!bundle.DependsOnParams) { query = QueryString.Empty; } var cacheKey = new BundleCacheKey(_id, bundlePath, query); IBundleCacheItem cacheItem = await _cache.GetOrAddAsync(cacheKey, ct => BuildBundleAsync(bundle, query, @params, httpContext), httpContext.RequestAborted, bundle.CacheOptions, lockFile : true); try { // scheduling release of the lock for the end of the scope (request), // so that the file remain unchanged until it's served disposer.Register(cacheItem.FileReleaser); } catch { cacheItem.FileReleaser.Dispose(); throw; } // passing file info to GetFileInfo(), which is called later in the request (see BundlingMiddleware and BundleFileProvider) httpContext.Items.Add(s_httpContextItemKey, cacheItem.FileInfo); return(true); }
public async Task <string> TryGenerateUrlAsync(PathString path, QueryString query, HttpContext httpContext) { PathString pathPrefix = httpContext.Request.PathBase + _bundlingContext.BundlesPathPrefix; if (!path.StartsWithSegments(pathPrefix, out PathString bundlePath) || !_bundles.TryGetValue(bundlePath, out IBundleModel bundle)) { return(null); } query = UrlUtils.NormalizeQuery(query, out IDictionary <string, StringValues> @params); if (!bundle.DependsOnParams) { query = QueryString.Empty; } var cacheKey = new BundleCacheKey(_id, bundlePath, query); IBundleCacheItem cacheItem = await GetBundleCacheItem(cacheKey, bundle, query, @params, httpContext, lockFile : false); _urlHelper.AddVersion(cacheItem.Version, ref bundlePath, ref query); return(pathPrefix + bundlePath + query); }
public virtual async Task GetOrAdd() { Setup(); try { var data = new BundleCacheData { Version = "1", Timestamp = DateTimeOffset.UtcNow, Content = Encoding.UTF8.GetBytes("html { }") }; var key = new BundleCacheKey(0, "/test.css", QueryString.Empty); var factoryRun = false; IBundleCacheItem addItem = await Cache.GetOrAddAsync(key, ct => { factoryRun = true; return(Task.FromResult(data)); }, CancellationToken.None, BundleCacheOptions.Default, lockFile : true); Assert.True(factoryRun); if (addItem.FileReleaser != NullDisposable.Instance) { // file is not released so the next call must block (using a parametrized key will force acquiring a writer lock) var key2 = new BundleCacheKey(key.ManagerId, key.Path, new QueryString("?q")); Task <IBundleCacheItem> getItemTask = Cache.GetOrAddAsync(key2, ct => throw new ApplicationException(), CancellationToken.None, BundleCacheOptions.Default, lockFile: false); await AsyncHelper.NeverCompletesAsync(getItemTask); // releasing file addItem.FileReleaser.Dispose(); try { await getItemTask; } catch (ApplicationException) { } } // re-checking factoryRun = false; IBundleCacheItem getItem = await Cache.GetOrAddAsync(key, ct => { factoryRun = true; return(Task.FromResult(new BundleCacheData())); }, CancellationToken.None, BundleCacheOptions.Default, lockFile : false); Assert.False(factoryRun); Assert.Equal(data.Version, getItem.Version); Assert.Equal(data.Timestamp, getItem.Timestamp); Assert.True(!ProvidesPhysicalFiles ^ getItem.FileInfo is PhysicalFileInfo); Assert.Equal(data.Content, await FileHelper.GetContentAsync(getItem.FileInfo)); // file lock was not requested so next call must not block factoryRun = false; getItem = await Cache.GetOrAddAsync(key, ct => { factoryRun = true; return(Task.FromResult(new BundleCacheData())); }, CancellationToken.None, BundleCacheOptions.Default, lockFile : false); Assert.False(factoryRun); } finally { Teardown(); } }