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