private Task <CompiledViewDescriptor> OnCacheMiss(string normalizedPath) { TaskCompletionSource <CompiledViewDescriptor> taskSource; lock (_cacheLock) { // Double-checked locking to handle a possible race. if (_cache.TryGetValue(normalizedPath, out Task <CompiledViewDescriptor> result)) { return(result); } var razorParts = _partManager.ApplicationParts.OfType <CompiledRazorModulesAssemblyPart>().ToList(); foreach (var razorPart in razorParts) { var provider = razorPart as IRazorCompiledItemProvider; var razorCompiledItems = provider.CompiledItems; var item = razorCompiledItems.FirstOrDefault(item => normalizedPath.Equals(GetNormalizedPath(item.Identifier))); if (item != null) { taskSource = new TaskCompletionSource <CompiledViewDescriptor>(creationOptions: TaskCreationOptions.RunContinuationsAsynchronously); var descriptor = new CompiledViewDescriptor(item) { ExpirationTokens = new List <IChangeToken>() { _moduleChangeProvider.GetChangeToken(razorPart.EntryAssemblyPath) } }; // At this point, we've decided what to do - but we should create the cache entry and // release the lock first. var cacheEntryOptions = new MemoryCacheEntryOptions(); for (var i = 0; i < descriptor.ExpirationTokens.Count; i++) { cacheEntryOptions.ExpirationTokens.Add(descriptor.ExpirationTokens[i]); } var task = _cache.Set(descriptor.RelativePath, Task.FromResult(descriptor), cacheEntryOptions); return(task); } } } // Entry does not exist. Attempt to create one. _logger.ViewCompilerCouldNotFindFileAtPath(normalizedPath); return(Task.FromResult(new CompiledViewDescriptor { RelativePath = normalizedPath, ExpirationTokens = Array.Empty <IChangeToken>(), })); }
public ModuleActionDescriptorChangeProvider( IModuleChangeProvider moduleChangeProvider) { _moduleChangeProvider = moduleChangeProvider ?? throw new ArgumentNullException(nameof(moduleChangeProvider)); _changeTokenRegistrations = new List <IDisposable>(_moduleChangeProvider.EntryAssemblyPaths.Count()); foreach (var entryAssemblyPath in _moduleChangeProvider.EntryAssemblyPaths) { _changeTokenRegistrations.Add( ChangeToken.OnChange( () => _moduleChangeProvider.GetChangeToken(entryAssemblyPath), RaiseChanged)); } }
public ModuleViewCompiler( ApplicationPartManager partManager, IModuleChangeProvider moduleChangeProvider, ILogger logger) { _partManager = partManager ?? throw new ArgumentNullException(nameof(partManager)); _moduleChangeProvider = moduleChangeProvider ?? throw new ArgumentNullException(nameof(moduleChangeProvider)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _normalizedPathCache = new ConcurrentDictionary <string, string>(StringComparer.Ordinal); // This is our L0 cache, and is a durable store. Views migrate into the cache as they are requested // from either the set of known precompiled views, or by being compiled. _cache = new MemoryCache(new MemoryCacheOptions()); var moduleRazorParts = _partManager.ApplicationParts.OfType <CompiledRazorModulesAssemblyPart>().ToList(); var razorParts = _partManager.ApplicationParts.OfType <CompiledRazorAssemblyPart>().ToList(); _compiledViews = new Dictionary <string, Task <CompiledViewDescriptor> >(StringComparer.OrdinalIgnoreCase); var precompiledViews = new Dictionary <string, CompiledViewDescriptor>(StringComparer.OrdinalIgnoreCase); foreach (var razorPart in moduleRazorParts) { if (razorPart is IRazorCompiledItemProvider provider) { foreach (var item in provider.CompiledItems) { var descriptor = new CompiledViewDescriptor(item) { ExpirationTokens = new List <IChangeToken>() { _moduleChangeProvider.GetChangeToken(razorPart.EntryAssemblyPath) } }; if (!precompiledViews.ContainsKey(descriptor.RelativePath)) { precompiledViews.Add(descriptor.RelativePath, descriptor); } } } } foreach (var razorPart in razorParts) { if (razorPart is IRazorCompiledItemProvider provider) { foreach (var item in provider.CompiledItems) { var descriptor = new CompiledViewDescriptor(item); if (!_compiledViews.ContainsKey(descriptor.RelativePath)) { _compiledViews.Add(descriptor.RelativePath, Task.FromResult(descriptor)); } } } } foreach (var razorView in precompiledViews) { var cacheEntryOptions = new MemoryCacheEntryOptions(); for (var i = 0; i < razorView.Value.ExpirationTokens.Count; i++) { cacheEntryOptions.ExpirationTokens.Add(razorView.Value.ExpirationTokens[i]); } _cache.Set(razorView.Value.RelativePath, Task.FromResult(razorView), cacheEntryOptions); } }