/// <summary> /// Gets an ordered <see cref="IReadOnlyList{ChunkTreeResult}"/> of parsed <see cref="ChunkTree"/>s and /// file paths for each <c>_ViewImports</c> that is applicable to the page located at /// <paramref name="pagePath"/>. The list is ordered so that the <see cref="ChunkTreeResult"/>'s /// <see cref="ChunkTreeResult.ChunkTree"/> for the <c>_ViewImports</c> closest to the /// <paramref name="pagePath"/> in the file system appears first. /// </summary> /// <param name="pagePath">The path of the page to locate inherited chunks for.</param> /// <returns>A <see cref="IReadOnlyList{ChunkTreeResult}"/> of parsed <c>_ViewImports</c> /// <see cref="ChunkTree"/>s and their file paths.</returns> /// <remarks> /// The resulting <see cref="IReadOnlyList{ChunkTreeResult}"/> is ordered so that the result /// for a _ViewImport closest to the application root appears first and the _ViewImport /// closest to the page appears last i.e. /// [ /_ViewImport, /Views/_ViewImport, /Views/Home/_ViewImport ] /// </remarks> public virtual IReadOnlyList <ChunkTreeResult> GetInheritedChunkTreeResults(string pagePath) { if (pagePath == null) { throw new ArgumentNullException(nameof(pagePath)); } var inheritedChunkTreeResults = new List <ChunkTreeResult>(); var templateEngine = new RazorTemplateEngine(_razorHost); foreach (var viewImportsPath in ViewHierarchyUtility.GetViewImportsLocations(pagePath)) { // viewImportsPath contains the app-relative path of the _ViewImports. // Since the parsing of a _ViewImports would cause parent _ViewImports to be parsed // we need to ensure the paths are app-relative to allow the GetGlobalFileLocations // for the current _ViewImports to succeed. var chunkTree = _chunkTreeCache.GetOrAdd( viewImportsPath, fileInfo => ParseViewFile( templateEngine, fileInfo, viewImportsPath)); if (chunkTree != null) { var result = new ChunkTreeResult(chunkTree, viewImportsPath); inheritedChunkTreeResults.Insert(0, result); } } return(inheritedChunkTreeResults); }
/// <summary> /// Gets an ordered <see cref="IReadOnlyList{T}"/> of parsed <see cref="ChunkTree"/> for each /// <c>_ViewImports</c> that is applicable to the page located at <paramref name="pagePath"/>. The list is /// ordered so that the <see cref="ChunkTree"/> for the <c>_ViewImports</c> closest to the /// <paramref name="pagePath"/> in the file system appears first. /// </summary> /// <param name="pagePath">The path of the page to locate inherited chunks for.</param> /// <returns>A <see cref="IReadOnlyList{ChunkTree}"/> of parsed <c>_ViewImports</c> /// <see cref="ChunkTree"/>s.</returns> public virtual IReadOnlyList <ChunkTree> GetInheritedChunkTrees([NotNull] string pagePath) { var inheritedChunkTrees = new List <ChunkTree>(); var templateEngine = new RazorTemplateEngine(_razorHost); foreach (var viewImportsPath in ViewHierarchyUtility.GetViewImportsLocations(pagePath)) { // viewImportsPath contains the app-relative path of the _ViewImports. // Since the parsing of a _ViewImports would cause parent _ViewImports to be parsed // we need to ensure the paths are app-relative to allow the GetGlobalFileLocations // for the current _ViewImports to succeed. var chunkTree = _chunkTreeCache.GetOrAdd( viewImportsPath, fileInfo => ParseViewFile( templateEngine, fileInfo, viewImportsPath)); if (chunkTree != null) { inheritedChunkTrees.Add(chunkTree); } } return(inheritedChunkTrees); }
private MemoryCacheEntryOptions GetMemoryCacheEntryOptions( RelativeFileInfo fileInfo, PrecompilationCacheEntry cacheEntry) { var options = new MemoryCacheEntryOptions(); options.AddExpirationToken(FileProvider.Watch(fileInfo.RelativePath)); foreach (var path in ViewHierarchyUtility.GetViewImportsLocations(fileInfo.RelativePath)) { options.AddExpirationToken(FileProvider.Watch(path)); } return(options); }
private MemoryCacheEntryOptions GetMemoryCacheEntryOptions(string relativePath) { var options = new MemoryCacheEntryOptions(); options.AddExpirationTrigger(_fileProvider.Watch(relativePath)); var viewImportsPaths = ViewHierarchyUtility.GetViewImportsLocations(relativePath); foreach (var location in viewImportsPaths) { options.AddExpirationTrigger(_fileProvider.Watch(location)); } return(options); }
internal CompilerCache(IEnumerable <RazorFileInfoCollection> razorFileInfoCollections, IAssemblyLoadContext loadContext, IFileProvider fileProvider) { _fileProvider = fileProvider; _cache = new MemoryCache(new MemoryCacheOptions { CompactOnMemoryPressure = false }); var cacheEntries = new List <CompilerCacheEntry>(); foreach (var viewCollection in razorFileInfoCollections) { var containingAssembly = viewCollection.LoadAssembly(loadContext); foreach (var fileInfo in viewCollection.FileInfos) { var viewType = containingAssembly.GetType(fileInfo.FullTypeName); var cacheEntry = new CompilerCacheEntry(fileInfo, viewType); // There shouldn't be any duplicates and if there are any the first will win. // If the result doesn't match the one on disk its going to recompile anyways. var normalizedPath = NormalizePath(fileInfo.RelativePath); _cache.Set( normalizedPath, cacheEntry, GetMemoryCacheEntryOptions(fileInfo.RelativePath)); cacheEntries.Add(cacheEntry); } } // Set up _ViewImports foreach (var entry in cacheEntries) { var globalFileLocations = ViewHierarchyUtility.GetViewImportsLocations(entry.RelativePath); foreach (var location in globalFileLocations) { var globalFileEntry = _cache.Get <CompilerCacheEntry>(location); if (globalFileEntry != null) { // Add the composite _ViewImports entry as a dependency. entry.AssociatedGlobalFileEntry = globalFileEntry; break; } } } }
// Returns the entry for the nearest _ViewImports that the file inherits directives from. Since _ViewImports // entries are affected by other _ViewImports entries that are in the path hierarchy, the returned value // represents the composite result of performing a cache check on individual _ViewImports entries. private CompilerCacheEntry GetCompositeGlobalFileEntry(string relativePath, Func <RelativeFileInfo, CompilationResult> compile) { var viewImportsLocations = ViewHierarchyUtility.GetViewImportsLocations(relativePath); foreach (var viewImports in viewImportsLocations) { var getOrAddResult = GetOrAddCore(viewImports, compile); if (getOrAddResult != null) { // This is the nearest _ViewImports that exists on disk. return(getOrAddResult.CompilerCacheEntry); } } // No _ViewImports discovered. return(null); }