/// <summary> /// Initializes a new instance of <see cref="TemplateFactoryResult"/> with the /// specified <see cref="ITemplatePage"/> factory. /// </summary> /// <param name="templatePageFactory">The <see cref="ITemplatePage"/> factory.</param> /// <param name="viewDescriptor">The <see cref="CompiledTemplateDescriptor"/>.</param> public TemplateFactoryResult( CompiledTemplateDescriptor viewDescriptor, Func <ITemplatePage> templatePageFactory) { TemplateDescriptor = viewDescriptor ?? throw new ArgumentNullException(nameof(viewDescriptor)); TemplatePageFactory = templatePageFactory; }
public Func <ITemplatePage> CreateFactory(CompiledTemplateDescriptor templateDescriptor) { string templateKey = templateDescriptor.TemplateKey; if (templateDescriptor.TemplateAttribute != null) { Type compiledType = templateDescriptor.TemplateAttribute.TemplateType; var newExpression = Expression.New(compiledType); var keyProperty = compiledType.GetTypeInfo().GetProperty(nameof(ITemplatePage.Key)); var propertyBindExpression = Expression.Bind(keyProperty, Expression.Constant(templateKey)); var objectInitializeExpression = Expression.MemberInit(newExpression, propertyBindExpression); var pageFactory = Expression .Lambda <Func <ITemplatePage> >(objectInitializeExpression) .Compile(); return(pageFactory); } else { throw new RazorLightException($"Template {templateKey} is corrupted or invalid"); } }
private Task <CompiledTemplateDescriptor> OnCacheMissAsync(string templateKey) { ViewCompilerWorkItem item; TaskCompletionSource <CompiledTemplateDescriptor> taskSource; MemoryCacheEntryOptions cacheEntryOptions; // 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) { string normalizedKey = GetNormalizedKey(templateKey); // Double-checked locking to handle a possible race. if (_cache.TryGetValue(normalizedKey, out Task <CompiledTemplateDescriptor> result)) { return(result); } if (_precompiledViews.TryGetValue(normalizedKey, out var precompiledView)) { item = null; //item = CreatePrecompiledWorkItem(normalizedKey, precompiledView); } else { item = CreateRuntimeCompilationWorkItem(templateKey).GetAwaiter().GetResult(); } // At this point, we've decided what to do - but we should create the cache entry and // release the lock first. cacheEntryOptions = new MemoryCacheEntryOptions(); if (item.ExpirationToken != null) { cacheEntryOptions.ExpirationTokens.Add(item.ExpirationToken); } taskSource = new TaskCompletionSource <CompiledTemplateDescriptor>(); if (item.SupportsCompilation) { // We'll compile in just a sec, be patient. } else { // If we can't compile, we should have already created the descriptor Debug.Assert(item.Descriptor != null); taskSource.SetResult(item.Descriptor); } _cache.Set(item.NormalizedKey, taskSource.Task, cacheEntryOptions); } // Now the lock has been released so we can do more expensive processing. if (item.SupportsCompilation) { Debug.Assert(taskSource != null); //if (item.Descriptor?.Item != null && // ChecksumValidator.IsItemValid(_projectEngine, item.Descriptor.Item)) //{ // // If the item has checksums to validate, we should also have a precompiled view. // Debug.Assert(item.Descriptor != null); // taskSource.SetResult(item.Descriptor); // return taskSource.Task; //} try { CompiledTemplateDescriptor descriptor = CompileAndEmit(item.ProjectItem); descriptor.ExpirationToken = cacheEntryOptions.ExpirationTokens.FirstOrDefault(); taskSource.SetResult(descriptor); } catch (Exception ex) { taskSource.SetException(ex); } } return(taskSource.Task); }