/// <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)
            WyamRazorProjectFileSystem projectFileSystem = serviceProvider.GetRequiredService <WyamRazorProjectFileSystem>();
            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);

            IRazorPage result = compilationResult.GetPage(request.RelativePath);

            return(result);
        }
Beispiel #2
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)
            IHostingEnvironment hostingEnvironment = serviceProvider.GetRequiredService <IHostingEnvironment>();
            IFileInfo           fileInfo           = new StreamFileInfo(hostingEnvironment.WebRootFileProvider.GetFileInfo(relativePath), request.Input);
            RelativeFileInfo    relativeFileInfo   = new RelativeFileInfo(fileInfo, relativePath);

            // 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 = MD5.Create().ComputeHash(request.Input);
            request.Input.Position = 0;

            CompilerCacheResult compilerCacheResult = CompilePage(serviceProvider, request, hash, relativeFileInfo, relativePath);

            IRazorPage result = compilerCacheResult.PageFactory();

            return(result);
        }
        /// <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)
        {
            WyamRazorProjectFileSystem projectFileSystem = serviceProvider.GetRequiredService <WyamRazorProjectFileSystem>();

            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));
        }
        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>());

            ViewContext viewContext = new ViewContext(
                actionContext,
                view,
                viewData,
                tempData,
                output,
                new HtmlHelperOptions(),
                request.Document,
                request.Context);

            return(viewContext);
        }
Beispiel #5
0
        private CompilerCacheResult CompilePage(IServiceProvider serviceProvider, RenderRequest request, byte[] hash, RelativeFileInfo relativeFileInfo, string relativePath)
        {
            CompilerCacheKey         cacheKey = new CompilerCacheKey(request, hash);
            IRazorCompilationService razorCompilationService = serviceProvider.GetRequiredService <IRazorCompilationService>();
            CompilationResult        compilationResult       = _compilationCache.GetOrAdd(cacheKey, _ => GetCompilation(relativeFileInfo, razorCompilationService));

            // Create and return the page
            // We're not actually using the ASP.NET cache, but the CompilerCacheResult ctor contains the logic to create the page factory
            CompilerCacheResult compilerCacheResult = new CompilerCacheResult(relativePath, compilationResult, Array.Empty <IChangeToken>());

            return(compilerCacheResult);
        }
Beispiel #6
0
        /// <inheritdoc />
        public IEnumerable <IDocument> Execute(IReadOnlyList <IDocument> inputs, 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
            List <IDocument> validInputs = inputs
                                           .Where(context, x => _ignorePrefix == null ||
                                                  !x.ContainsKey(Keys.SourceFileName) ||
                                                  !x.FilePath(Keys.SourceFileName).FullPath.StartsWith(_ignorePrefix))
                                           .ToList();

            if (validInputs.Count < inputs.Count)
            {
                Trace.Information($"Ignoring {inputs.Count - validInputs.Count} inputs due to source file name prefix");
            }

            // Compile and evaluate the pages in parallel
            return(validInputs.AsParallel().Select(context, input =>
            {
                Trace.Verbose("Processing Razor for {0}", input.SourceString());

                Stream contentStream = context.GetContentStream();
                using (Stream inputStream = input.GetStream())
                {
                    FilePath viewStartLocationPath = _viewStartPath?.Invoke <FilePath>(input, context);

                    RenderRequest request = new RenderRequest
                    {
                        Input = inputStream,
                        Output = contentStream,
                        BaseType = _basePageType,
                        Context = context,
                        Document = input,
                        LayoutLocation = _layoutPath?.Invoke <FilePath>(input, context)?.FullPath,
                        ViewStartLocation = viewStartLocationPath != null ? GetRelativePath(viewStartLocationPath, context) : null,
                        RelativePath = GetRelativePath(input, context),
                        Model = _model == null ? input : _model.Invoke(input, context),
                    };

                    RazorService.Render(request);
                }

                return context.GetDocument(input, contentStream);
            }));
        }
Beispiel #7
0
        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;
            }
        }
        public void Render(RenderRequest request)
        {
            CompilationParameters parameters = new CompilationParameters
            {
                BasePageType      = request.BaseType,
                DynamicAssemblies = new DynamicAssemblyCollection(request.Context.DynamicAssemblies),
                Namespaces        = new NamespaceCollection(request.Context.Namespaces),
                FileSystem        = request.Context.FileSystem
            };

            RazorCompiler compiler = _compilers.GetOrAdd(parameters, _ => new RazorCompiler(parameters));

            compiler.RenderPage(request);
        }
Beispiel #9
0
        public void RenderPage(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);
                    viewContext.View.RenderAsync(viewContext).GetAwaiter().GetResult();
                }
            }
        }
Beispiel #10
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)
        {
            IEnumerable <string> viewStartLocations = request.ViewStartLocation != null
                ? new[] { request.ViewStartLocation }
                : ViewHierarchyUtility.GetViewStartLocations(request.RelativePath);

            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>();

            return(new RazorView(viewEngine, pageActivator, viewStartPages, page, htmlEncoder));
        }
        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)));
        }