/// <summary> /// Sets the file watch expiration. /// </summary> /// <param name="options">The options.</param> /// <param name="fileName">Name of the file.</param> /// <returns>MemoryCacheEntryOptions.</returns> public static MemoryCacheEntryOptions SetFileWatchExpiration(this MemoryCacheEntryOptions options, string fileName) { var fileInfo = new FileInfo(fileName); var fileProvider = new PhysicalFileProvider(fileInfo.DirectoryName); options.AddExpirationToken(fileProvider.Watch(fileInfo.Name)); return(options); }
public void GetCurrentStatistics_UpdateAfterExistingItemExpired_CurrentEstimatedSizeResets(bool sizeLimitIsSet) { const string Key = "myKey"; var cache = new MemoryCache(sizeLimitIsSet ? new MemoryCacheOptions { TrackStatistics = true, Clock = new SystemClock(), SizeLimit = 10 } : new MemoryCacheOptions { TrackStatistics = true, Clock = new SystemClock() } ); ICacheEntry entry; using (entry = cache.CreateEntry(Key)) { var expirationToken = new TestExpirationToken() { ActiveChangeCallbacks = true }; var mc = new MemoryCacheEntryOptions { Size = 5 }; cache.Set(Key, new object(), mc.AddExpirationToken(expirationToken)); MemoryCacheStatistics?stats = cache.GetCurrentStatistics(); Assert.NotNull(stats); Assert.Equal(1, cache.Count); Assert.Equal(1, stats.CurrentEntryCount); VerifyCurrentEstimatedSize(5, sizeLimitIsSet, stats); expirationToken.HasChanged = true; cache.Set(Key, new object(), mc.AddExpirationToken(expirationToken)); stats = cache.GetCurrentStatistics(); Assert.NotNull(stats); Assert.Equal(0, cache.Count); Assert.Equal(0, stats.CurrentEntryCount); VerifyCurrentEstimatedSize(0, sizeLimitIsSet, stats); } }
/// <summary> /// Adds version query parameter to the specified file path. /// </summary> /// <param name="path">The path of the file to which version should be added.</param> /// <returns>Path containing the version query string.</returns> /// <remarks> /// The version query string is appended with the key "v". /// </remarks> public string AddFileVersionToPath(string path) { if (path == null) { throw new ArgumentNullException(nameof(path)); } var resolvedPath = path; var queryStringOrFragmentStartIndex = path.IndexOfAny(QueryStringAndFragmentTokens); if (queryStringOrFragmentStartIndex != -1) { resolvedPath = path.Substring(0, queryStringOrFragmentStartIndex); } Uri uri; if (Uri.TryCreate(resolvedPath, UriKind.Absolute, out uri) && !uri.IsFile) { // Don't append version if the path is absolute. return path; } string value; if (!_cache.TryGetValue(path, out value)) { var cacheEntryOptions = new MemoryCacheEntryOptions(); cacheEntryOptions.AddExpirationToken(_fileProvider.Watch(resolvedPath)); var fileInfo = _fileProvider.GetFileInfo(resolvedPath); if (!fileInfo.Exists && _requestPathBase.HasValue && resolvedPath.StartsWith(_requestPathBase.Value, StringComparison.OrdinalIgnoreCase)) { var requestPathBaseRelativePath = resolvedPath.Substring(_requestPathBase.Value.Length); cacheEntryOptions.AddExpirationToken(_fileProvider.Watch(requestPathBaseRelativePath)); fileInfo = _fileProvider.GetFileInfo(requestPathBaseRelativePath); } if (fileInfo.Exists) { value = QueryHelpers.AddQueryString(path, VersionKey, GetHashForFile(fileInfo)); } else { // if the file is not in the current server. value = path; } value = _cache.Set<string>(path, value, cacheEntryOptions); } return value; }
/// <summary> /// Adds inherited token and absolute expiration information. /// </summary> /// <param name="link"></param> public static MemoryCacheEntryOptions AddEntryLink(this MemoryCacheEntryOptions options, IEntryLink link) { foreach (var expirationToken in link.ExpirationTokens) { options.AddExpirationToken(expirationToken); } if (link.AbsoluteExpiration.HasValue) { options.SetAbsoluteExpiration(link.AbsoluteExpiration.Value); } return(options); }
private ViewLocationCacheResult OnCacheMiss( ViewLocationExpanderContext expanderContext, ViewLocationCacheKey cacheKey) { // Only use the area view location formats if we have an area token. IEnumerable<string> viewLocations = !string.IsNullOrEmpty(expanderContext.AreaName) ? _options.AreaViewLocationFormats : _options.ViewLocationFormats; for (var i = 0; i < _options.ViewLocationExpanders.Count; i++) { viewLocations = _options.ViewLocationExpanders[i].ExpandViewLocations(expanderContext, viewLocations); } ViewLocationCacheResult cacheResult = null; var searchedLocations = new List<string>(); var expirationTokens = new HashSet<IChangeToken>(); foreach (var location in viewLocations) { var path = string.Format( CultureInfo.InvariantCulture, location, expanderContext.ViewName, expanderContext.ControllerName, expanderContext.AreaName); cacheResult = CreateCacheResult(expirationTokens, path, expanderContext.IsMainPage); if (cacheResult != null) { break; } searchedLocations.Add(path); } // No views were found at the specified location. Create a not found result. if (cacheResult == null) { cacheResult = new ViewLocationCacheResult(searchedLocations); } var cacheEntryOptions = new MemoryCacheEntryOptions(); cacheEntryOptions.SetSlidingExpiration(_cacheExpirationDuration); foreach (var expirationToken in expirationTokens) { cacheEntryOptions.AddExpirationToken(expirationToken); } return ViewLookupCache.Set<ViewLocationCacheResult>(cacheKey, cacheResult, cacheEntryOptions); }
private ViewLocationCacheResult LocatePageFromPath(string executingFilePath, string pagePath, bool isMainPage) { var applicationRelativePath = GetAbsolutePath(executingFilePath, pagePath); var cacheKey = new ViewLocationCacheKey(applicationRelativePath, isMainPage); ViewLocationCacheResult cacheResult; if (!ViewLookupCache.TryGetValue(cacheKey, out cacheResult)) { var expirationTokens = new HashSet<IChangeToken>(); cacheResult = CreateCacheResult(expirationTokens, applicationRelativePath, isMainPage); var cacheEntryOptions = new MemoryCacheEntryOptions(); cacheEntryOptions.SetSlidingExpiration(_cacheExpirationDuration); foreach (var expirationToken in expirationTokens) { cacheEntryOptions.AddExpirationToken(expirationToken); } // No views were found at the specified location. Create a not found result. if (cacheResult == null) { cacheResult = new ViewLocationCacheResult(new[] { applicationRelativePath }); } cacheResult = ViewLookupCache.Set<ViewLocationCacheResult>( cacheKey, cacheResult, cacheEntryOptions); } return cacheResult; }
private Task<CompilerCacheResult> CreateCacheEntry( string normalizedPath, Func<RelativeFileInfo, CompilationResult> compile) { TaskCompletionSource<CompilerCacheResult> compilationTaskSource = null; MemoryCacheEntryOptions cacheEntryOptions = null; IFileInfo fileInfo = null; Task<CompilerCacheResult> cacheEntry; // Safe races cannot be allowed when compiling Razor pages. To ensure only one compilation request succeeds // per file, we'll lock the creation of a cache entry. Creating the cache entry should be very quick. The // actual work for compiling files happens outside the critical section. lock (_cacheLock) { if (_cache.TryGetValue(normalizedPath, out cacheEntry)) { return cacheEntry; } fileInfo = _fileProvider.GetFileInfo(normalizedPath); if (!fileInfo.Exists) { var expirationToken = _fileProvider.Watch(normalizedPath); cacheEntry = Task.FromResult(new CompilerCacheResult(new[] { expirationToken })); cacheEntryOptions = new MemoryCacheEntryOptions(); cacheEntryOptions.AddExpirationToken(expirationToken); } else { cacheEntryOptions = GetMemoryCacheEntryOptions(normalizedPath); // A file exists and needs to be compiled. compilationTaskSource = new TaskCompletionSource<CompilerCacheResult>(); cacheEntry = compilationTaskSource.Task; } cacheEntry = _cache.Set<Task<CompilerCacheResult>>(normalizedPath, cacheEntry, cacheEntryOptions); } if (compilationTaskSource != null) { // Indicates that the file was found and needs to be compiled. Debug.Assert(fileInfo != null && fileInfo.Exists); Debug.Assert(cacheEntryOptions != null); var relativeFileInfo = new RelativeFileInfo(fileInfo, normalizedPath); try { var compilationResult = compile(relativeFileInfo); compilationResult.EnsureSuccessful(); compilationTaskSource.SetResult( new CompilerCacheResult(compilationResult, cacheEntryOptions.ExpirationTokens)); } catch (Exception ex) { compilationTaskSource.SetException(ex); } } return cacheEntry; }
private MemoryCacheEntryOptions GetMemoryCacheEntryOptions(string relativePath) { var options = new MemoryCacheEntryOptions(); options.AddExpirationToken(_fileProvider.Watch(relativePath)); var viewImportsPaths = ViewHierarchyUtility.GetViewImportsLocations(relativePath); foreach (var location in viewImportsPaths) { options.AddExpirationToken(_fileProvider.Watch(location)); } return options; }
private CompilerCacheResult CreateCacheEntry( string normalizedPath, Func<RelativeFileInfo, CompilationResult> compile) { CompilerCacheResult cacheResult; var fileInfo = _fileProvider.GetFileInfo(normalizedPath); MemoryCacheEntryOptions cacheEntryOptions; CompilerCacheResult cacheResultToCache; if (!fileInfo.Exists) { cacheResultToCache = CompilerCacheResult.FileNotFound; cacheResult = CompilerCacheResult.FileNotFound; cacheEntryOptions = new MemoryCacheEntryOptions(); cacheEntryOptions.AddExpirationToken(_fileProvider.Watch(normalizedPath)); } else { var relativeFileInfo = new RelativeFileInfo(fileInfo, normalizedPath); var compilationResult = compile(relativeFileInfo).EnsureSuccessful(); cacheEntryOptions = GetMemoryCacheEntryOptions(normalizedPath); // By default the CompilationResult returned by IRoslynCompiler is an instance of // UncachedCompilationResult. This type has the generated code as a string property and do not want // to cache it. We'll instead cache the unwrapped result. cacheResultToCache = new CompilerCacheResult( CompilationResult.Successful(compilationResult.CompiledType)); cacheResult = new CompilerCacheResult(compilationResult); } _cache.Set(normalizedPath, cacheResultToCache, cacheEntryOptions); return cacheResult; }
/// <summary> /// Sets the cache entry change expiration. /// </summary> /// <param name="options">The options.</param> /// <param name="cache">The cache.</param> /// <param name="key">The key.</param> /// <returns>MemoryCacheEntryOptions.</returns> public static MemoryCacheEntryOptions SetCacheEntryChangeExpiration(this MemoryCacheEntryOptions options, IMemoryCache cache, string key) { options.AddExpirationToken(MakeCacheEntryChangeToken(cache, new[] { key })); return(options); }
/// <summary> /// Forces the absolute expiration. /// </summary> /// <param name="options">The options.</param> /// <param name="delay">The delay.</param> /// <returns>MemoryCacheEntryOptions.</returns> public static MemoryCacheEntryOptions ForceAbsoluteExpiration(this MemoryCacheEntryOptions options, TimeSpan delay) => options.AddExpirationToken(new CancellationChangeToken(new CancellationTokenSource(delay).Token));
private static IMemoryCache MakeCache(object result = null) { var cache = new Mock<IMemoryCache>(); cache.CallBase = true; cache.Setup(c => c.TryGetValue(It.IsAny<string>(), out result)) .Returns(result != null); var cacheEntryOptions = new MemoryCacheEntryOptions(); cacheEntryOptions.AddExpirationToken(Mock.Of<IChangeToken>()); cache .Setup( c => c.Set( /*key*/ It.IsAny<string>(), /*value*/ It.IsAny<object>(), /*options*/ cacheEntryOptions)) .Returns(result); return cache.Object; }