Пример #1
0
        /// <summary>
        /// Gets the view for an input document (which is different than the view for a layout, partial, or
        /// other indirect view because it's not necessarily on disk or in the file system).
        /// </summary>
        private IView GetViewFromStream(IServiceProvider serviceProvider, RenderRequest request, IRazorPage page)
        {
            StatiqRazorProjectFileSystem projectFileSystem = serviceProvider.GetRequiredService <StatiqRazorProjectFileSystem>();

            IEnumerable <string> viewStartLocations = request.ViewStartLocation != null
                ? new[] { request.ViewStartLocation }
                : projectFileSystem.FindHierarchicalItems(request.RelativePath, ViewStartFileName).Select(x => x.FilePath);

            List <IRazorPage> viewStartPages = viewStartLocations
                                               .Select(serviceProvider.GetRequiredService <IRazorPageFactoryProvider>().CreateFactory)
                                               .Where(x => x.Success)
                                               .Select(x => x.RazorPageFactory())
                                               .Reverse()
                                               .ToList();

            if (request.LayoutLocation != null)
            {
                page.Layout = request.LayoutLocation;
            }

            IRazorViewEngine    viewEngine       = serviceProvider.GetRequiredService <IRazorViewEngine>();
            IRazorPageActivator pageActivator    = serviceProvider.GetRequiredService <IRazorPageActivator>();
            HtmlEncoder         htmlEncoder      = serviceProvider.GetRequiredService <HtmlEncoder>();
            DiagnosticSource    diagnosticSource = serviceProvider.GetRequiredService <DiagnosticSource>();

            return(new RazorView(viewEngine, pageActivator, viewStartPages, page, htmlEncoder, diagnosticSource));
        }
Пример #2
0
        private ViewContext GetViewContext(IServiceProvider serviceProvider, RenderRequest request, IView view, TextWriter output)
        {
            HttpContext httpContext = new DefaultHttpContext
            {
                RequestServices = serviceProvider
            };

            ActionContext actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());

            ViewDataDictionary viewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), actionContext.ModelState)
            {
                Model = request.Model
            };

            ITempDataDictionary tempData = new TempDataDictionary(actionContext.HttpContext, serviceProvider.GetRequiredService <ITempDataProvider>());

            return(new ViewContext(
                       actionContext,
                       view,
                       viewData,
                       tempData,
                       output,
                       new HtmlHelperOptions(),
                       request.Document,
                       request.Context));
        }
Пример #3
0
        /// <inheritdoc />
        protected override async Task <IEnumerable <IDocument> > ExecuteContextAsync(IExecutionContext context)
        {
            // Expire the internal Razor cache if this is a new execution
            // This needs to be done so that layouts/partials can be re-rendered if they've changed,
            // otherwise Razor will just use the previously cached version of them
            if (_executionId != Guid.Empty && _executionId != context.ExecutionId)
            {
                RazorService.ExpireChangeTokens();
            }
            _executionId = context.ExecutionId;

            // Eliminate input documents that we shouldn't process
            ImmutableArray <IDocument> validInputs = context.Inputs
                                                     .Where(x => _ignorePrefix == null || x.Source.IsNull || !x.Source.FileName.FullPath.StartsWith(_ignorePrefix))
                                                     .ToImmutableArray();

            if (validInputs.Length < context.Inputs.Length)
            {
                context.LogInformation($"Ignoring {context.Inputs.Length - validInputs.Length} inputs due to source file name prefix");
            }

            // Compile and evaluate the pages in parallel
            return(await validInputs.ParallelSelectAsync(RenderDocumentAsync));

            async Task <IDocument> RenderDocumentAsync(IDocument input)
            {
                context.LogDebug("Processing Razor for {0}", input.ToSafeDisplayString());

                using (Stream contentStream = await context.GetContentStreamAsync())
                {
                    using (Stream inputStream = input.GetContentStream())
                    {
                        NormalizedPath viewStartLocationPath = _viewStartPath == null ? null : await _viewStartPath.GetValueAsync(input, context);

                        NormalizedPath layoutPath     = _layoutPath == null ? NormalizedPath.Null : (await _layoutPath.GetValueAsync(input, context));
                        string         layoutLocation = layoutPath.IsNull ? null : layoutPath.FullPath;

                        RenderRequest request = new RenderRequest
                        {
                            Input             = inputStream,
                            Output            = contentStream,
                            BaseType          = _basePageType,
                            Context           = context,
                            Document          = input,
                            LayoutLocation    = layoutLocation,
                            ViewStartLocation = viewStartLocationPath.IsNull ? null : GetRelativePath(viewStartLocationPath, context),
                            RelativePath      = GetRelativePath(input, context),
                            Model             = _model == null ? input : await _model.GetValueAsync(input, context)
                        };

                        await RazorService.RenderAsync(request);
                    }

                    return(input.Clone(context.GetContentProvider(contentStream, MediaTypes.Html)));
                }
            }
        }
Пример #4
0
        public async Task RenderAsync(RenderRequest request)
        {
            CompilationParameters parameters = new CompilationParameters
            {
                BasePageType = request.BaseType,
                Namespaces   = new NamespaceCollection(request.Context.Namespaces)
            };

            RazorCompiler compiler = _compilers.GetOrAdd(parameters, _ => new RazorCompiler(parameters, request.Context));
            await compiler.RenderPageAsync(request);
        }
        public CompilerCacheKey(RenderRequest request, byte[] fileHash)
        {
            _request  = request;
            _fileHash = fileHash;

            // Precalculate hash code since we know we'll need it
            _hashCode = 17;
            _hashCode = (_hashCode * 31) + (_request.LayoutLocation?.GetHashCode() ?? 0);
            _hashCode = (_hashCode * 31) + (_request.ViewStartLocation?.GetHashCode() ?? 0);
            foreach (byte b in _fileHash)
            {
                _hashCode = (_hashCode * 31) ^ b;
            }
        }
Пример #6
0
        public async Task RenderPageAsync(RenderRequest request)
        {
            using (IServiceScope scope = _serviceScopeFactory.CreateScope())
            {
                IServiceProvider serviceProvider = scope.ServiceProvider;
                IRazorPage       page            = GetPageFromStream(serviceProvider, request);
                IView            view            = GetViewFromStream(serviceProvider, request, page);

                using (StreamWriter writer = request.Output.GetWriter())
                {
                    Microsoft.AspNetCore.Mvc.Rendering.ViewContext viewContext = GetViewContext(serviceProvider, request, view, writer);
                    await viewContext.View.RenderAsync(viewContext);
                }
            }
        }
Пример #7
0
        /// <summary>
        /// Gets the Razor page for an input document stream. This is roughly modeled on
        /// DefaultRazorPageFactory and CompilerCache. Note that we don't actually bother
        /// with caching the page if it's from a live stream.
        /// </summary>
        private IRazorPage GetPageFromStream(IServiceProvider serviceProvider, RenderRequest request)
        {
            string relativePath = request.RelativePath;

            if (relativePath.StartsWith("~/", StringComparison.Ordinal))
            {
                // For tilde slash paths, drop the leading ~ to make it work with the underlying IFileProvider.
                relativePath = relativePath.Substring(1);
            }

            // Get the file info by combining the stream content with info found at the document's original location (if any)
            StatiqRazorProjectFileSystem projectFileSystem = serviceProvider.GetRequiredService <StatiqRazorProjectFileSystem>();
            RazorProjectItem             projectItem       = projectFileSystem.GetItem(relativePath, request.Input);

            // Compute a hash for the content since pipelines could have changed it from the underlying file
            // We have to pre-compute the hash (I.e., no CryptoStream) since we need to check for a hit before reading/compiling the view
            byte[] hash = SHA512.Create().ComputeHash(request.Input);
            request.Input.Position = 0;

            CompilationResult compilationResult = CompilePage(serviceProvider, request, hash, projectItem, projectFileSystem);

            return(compilationResult.GetPage(request.RelativePath));
        }
Пример #8
0
        private CompilationResult CompilePage(IServiceProvider serviceProvider, RenderRequest request, byte[] hash, RazorProjectItem projectItem, RazorProjectFileSystem projectFileSystem)
        {
            CompilerCacheKey cacheKey = new CompilerCacheKey(request, hash);

            return(_compilationCache.GetOrAdd(cacheKey, _ => GetCompilation(projectItem, projectFileSystem)));
        }