public IEnumerable<IDocument> Execute(IReadOnlyList<IDocument> inputs, IExecutionContext context) { IRazorPageFactory pageFactory = new VirtualPathRazorPageFactory(context.InputFolder, context, _basePageType); IViewStartProvider viewStartProvider = new ViewStartProvider(pageFactory); IRazorViewFactory viewFactory = new RazorViewFactory(viewStartProvider); IRazorViewEngine viewEngine = new RazorViewEngine(pageFactory, viewFactory); return inputs.Select(x => { ViewContext viewContext = new ViewContext(null, new ViewDataDictionary(), null, x.Metadata, context, viewEngine); string relativePath = "/"; if (x.ContainsKey(MetadataKeys.RelativeFilePath)) { relativePath += x.String(MetadataKeys.RelativeFilePath); } ViewEngineResult viewEngineResult = viewEngine.GetView(viewContext, relativePath, x.Content).EnsureSuccessful(); using (StringWriter writer = new StringWriter()) { viewContext.View = viewEngineResult.View; viewContext.Writer = writer; AsyncHelper.RunSync(() => viewEngineResult.View.RenderAsync(viewContext)); return x.Clone(writer.ToString()); } }); }
public IEnumerable<IDocument> Execute(IReadOnlyList<IDocument> inputs, IExecutionContext context) { IRazorPageFactory pageFactory = new VirtualPathRazorPageFactory(context.InputFolder, context, _basePageType); List<IDocument> validInputs = inputs .Where(x => _ignorePrefix == null || !x.ContainsKey(Keys.SourceFileName) || !x.String(Keys.SourceFileName).StartsWith(_ignorePrefix)) .ToList(); // Compile the pages in parallel ConcurrentDictionary<IDocument, Tuple<ViewContext, ViewEngineResult>> compilationResults = new ConcurrentDictionary<IDocument, Tuple<ViewContext, ViewEngineResult>>(); Parallel.ForEach(validInputs, x => { Trace.Verbose("Compiling Razor for {0}", x.Source); IViewStartProvider viewStartProvider = new ViewStartProvider(pageFactory, _viewStartPath?.Invoke<string>(x, context)); IRazorViewFactory viewFactory = new RazorViewFactory(viewStartProvider); IRazorViewEngine viewEngine = new RazorViewEngine(pageFactory, viewFactory); ViewContext viewContext = new ViewContext(null, new ViewDataDictionary(), null, x, context, viewEngine); ViewEngineResult viewEngineResult; using (Stream stream = x.GetStream()) { viewEngineResult = viewEngine.GetView(viewContext, GetRelativePath(x), stream).EnsureSuccessful(); } compilationResults[x] = new Tuple<ViewContext, ViewEngineResult>(viewContext, viewEngineResult); }); // Now evaluate them in sequence - have to do this because BufferedHtmlContent doesn't appear to work well in multi-threaded parallel execution TaskScheduler exclusiveScheduler = new ConcurrentExclusiveSchedulerPair().ExclusiveScheduler; CancellationToken cancellationToken = new CancellationToken(); return validInputs .Select(input => { using (Trace.WithIndent().Verbose("Processing Razor for {0}", input.Source)) { Tuple<ViewContext, ViewEngineResult> compilationResult; if (compilationResults.TryGetValue(input, out compilationResult)) { using (StringWriter writer = new StringWriter()) { compilationResult.Item1.View = compilationResult.Item2.View; compilationResult.Item1.Writer = writer; Task.Factory.StartNew(() => compilationResult.Item2.View.RenderAsync(compilationResult.Item1), cancellationToken, TaskCreationOptions.None, exclusiveScheduler).Unwrap().GetAwaiter().GetResult(); return context.GetDocument(input, writer.ToString()); } } Trace.Warning("Could not find compilation result for {0}", input.Source); return null; } }); }