/// <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;
 }
Ejemplo n.º 2
0
        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);
        }