public void CompileCalculatesRootRelativePath(string appPath, string viewPath) { // Arrange var host = new Mock<IMvcRazorHost>(); host.Setup(h => h.GenerateCode(@"Views\index\home.cshtml", It.IsAny<Stream>())) .Returns(GetGeneratorResult()) .Verifiable(); var fileInfo = new Mock<IFileInfo>(); fileInfo.Setup(f => f.PhysicalPath).Returns(viewPath); fileInfo.Setup(f => f.CreateReadStream()).Returns(Stream.Null); var relativeFileInfo = new RelativeFileInfo(fileInfo.Object, @"Views\index\home.cshtml"); var compiler = new Mock<ICompilationService>(); compiler.Setup(c => c.Compile(relativeFileInfo, It.IsAny<string>())) .Returns(CompilationResult.Successful(typeof(RazorCompilationServiceTest))); var razorService = new RazorCompilationService(compiler.Object, host.Object); // Act razorService.Compile(relativeFileInfo); // Assert host.Verify(); }
public void Compile_ReturnsFailedResultIfParseFails() { // Arrange var errorSink = new ParserErrorSink(); errorSink.OnError(new RazorError("some message", 1, 1, 1, 1)); var generatorResult = new GeneratorResults( new Block(new BlockBuilder { Type = BlockType.Comment }), Enumerable.Empty<TagHelperDescriptor>(), errorSink, new CodeBuilderResult("", new LineMapping[0]), new CodeTree()); var host = new Mock<IMvcRazorHost>(); host.Setup(h => h.GenerateCode(It.IsAny<string>(), It.IsAny<Stream>())) .Returns(generatorResult) .Verifiable(); var fileInfo = new Mock<IFileInfo>(); fileInfo.Setup(f => f.CreateReadStream()) .Returns(Stream.Null); var compiler = new Mock<ICompilationService>(MockBehavior.Strict); var relativeFileInfo = new RelativeFileInfo(fileInfo.Object, @"Views\index\home.cshtml"); var razorService = new RazorCompilationService(compiler.Object, host.Object); // Act var result = razorService.Compile(relativeFileInfo); // Assert Assert.NotNull(result.CompilationFailure); var message = Assert.Single(result.CompilationFailure.Messages); Assert.Equal("some message", message.Message); host.Verify(); }
// Internal for unit testing internal CompilationResult GetCompilationFailedResult(RelativeFileInfo file, IEnumerable <RazorError> errors) { // If a SourceLocation does not specify a file path, assume it is produced // from parsing the current file. var messageGroups = errors .GroupBy(razorError => razorError.Location.FilePath ?? file.RelativePath, StringComparer.Ordinal); var failures = new List <CompilationFailure>(); foreach (var group in messageGroups) { var filePath = group.Key; var fileContent = ReadFileContentsSafely(filePath); var compilationFailure = new CompilationFailure( filePath, fileContent, compiledContent: string.Empty, messages: group.Select(parserError => CreateDiagnosticMessage(parserError, filePath))); failures.Add(compilationFailure); } return(new CompilationResult(failures)); }
public void CompileCalculatesRootRelativePath(string appPath, string viewPath) { // Arrange var host = new Mock <IMvcRazorHost>(); host.Setup(h => h.GenerateCode(@"views\index\home.cshtml", It.IsAny <Stream>())) .Returns(GetGeneratorResult()) .Verifiable(); var fileInfo = new Mock <IFileInfo>(); fileInfo.Setup(f => f.PhysicalPath).Returns(viewPath); fileInfo.Setup(f => f.CreateReadStream()).Returns(Stream.Null); var compiler = new Mock <ICompilationService>(); compiler.Setup(c => c.Compile(fileInfo.Object, It.IsAny <string>())) .Returns(CompilationResult.Successful(typeof(RazorCompilationServiceTest))); var razorService = new RazorCompilationService(compiler.Object, host.Object); var relativeFileInfo = new RelativeFileInfo() { FileInfo = fileInfo.Object, RelativePath = @"views\index\home.cshtml", }; // Act razorService.Compile(relativeFileInfo, isInstrumented: false); // Assert host.Verify(); }
public void GetOrAdd_IgnoresCache_IfCachedItemIsNotInstrumentedAndEnableInstrumentationIsTrue() { // Arrange var lastModified = DateTime.UtcNow; var cache = new CompilerCache(); var fileInfo = new Mock <IFileInfo>(); fileInfo.SetupGet(f => f.PhysicalPath) .Returns("test"); fileInfo.SetupGet(f => f.LastModified) .Returns(lastModified); var type = GetType(); var uncachedResult1 = UncachedCompilationResult.Successful(type, "hello world"); var uncachedResult2 = UncachedCompilationResult.Successful(typeof(object), "hello world"); var uncachedResult3 = UncachedCompilationResult.Successful(typeof(Guid), "hello world"); var runtimeFileInfo = new RelativeFileInfo() { FileInfo = fileInfo.Object, RelativePath = "test", }; // Act cache.GetOrAdd(runtimeFileInfo, false, () => uncachedResult1); var actual1 = cache.GetOrAdd(runtimeFileInfo, true, () => uncachedResult2); var actual2 = cache.GetOrAdd(runtimeFileInfo, false, () => uncachedResult3); // Assert Assert.Same(uncachedResult2, actual1); Assert.Same(typeof(object), actual1.CompiledType); Assert.NotSame(actual2, uncachedResult3); Assert.Same(typeof(object), actual2.CompiledType); }
public void Compile_ReturnsGeneratedCodePath_IfLinePragmaIsNotAvailable() { // Arrange var fileContent = "file content"; var content = @"this should fail"; var compilationService = new DefaultRoslynCompilationService( GetDependencyContext(), GetOptions(), GetFileProviderAccessor(), NullLoggerFactory.Instance); var relativeFileInfo = new RelativeFileInfo( new TestFileInfo { Content = fileContent }, "some-relative-path"); // Act var result = compilationService.Compile(relativeFileInfo, content); // Assert Assert.IsType <CompilationResult>(result); Assert.Null(result.CompiledType); var compilationFailure = Assert.Single(result.CompilationFailures); Assert.Equal("Generated Code", compilationFailure.SourceFilePath); Assert.Equal(content, compilationFailure.SourceFileContent); }
public void Compile_SucceedsIfReferencesAreAddedInCallback() { // Arrange var options = GetOptions(context => { var assemblyLocation = typeof(object).GetTypeInfo().Assembly.Location; context.Compilation = context .Compilation .AddReferences(MetadataReference.CreateFromFile(assemblyLocation)); }); var content = "public class MyTestType {}"; var compilationService = new DefaultRoslynCompilationService( dependencyContext: null, viewEngineOptions: options, fileProviderAccessor: GetFileProviderAccessor(), loggerFactory: NullLoggerFactory.Instance); var relativeFileInfo = new RelativeFileInfo( new TestFileInfo { PhysicalPath = "SomePath" }, "some-relative-path.cshtml"); // Act var result = compilationService.Compile(relativeFileInfo, content); // Assert Assert.Null(result.CompilationFailures); Assert.NotNull(result.CompiledType); }
public void Compile_DoesNotThrowIfReferencesWereClearedInCallback() { // Arrange var options = GetOptions(context => { context.Compilation = context.Compilation.RemoveAllReferences(); }); var content = "public class MyTestType {}"; var compilationService = new DefaultRoslynCompilationService( dependencyContext: GetDependencyContext(), viewEngineOptions: options, fileProviderAccessor: GetFileProviderAccessor(), loggerFactory: NullLoggerFactory.Instance); var relativeFileInfo = new RelativeFileInfo( new TestFileInfo { PhysicalPath = "SomePath" }, "some-relative-path.cshtml"); // Act var result = compilationService.Compile(relativeFileInfo, content); // Assert Assert.Single(result.CompilationFailures); }
public void Compile_ThrowsIfDependencyContextReturnsNoReferencesAndTheApplicationFailsToCompile() { // Arrange var content = "public class MyTestType {}"; var dependencyContext = new DependencyContext( new TargetInfo("framework", "runtime", "signature", isPortable: true), Extensions.DependencyModel.CompilationOptions.Default, new CompilationLibrary[0], new RuntimeLibrary[0], Enumerable.Empty <RuntimeFallbacks>()); var compilationService = new DefaultRoslynCompilationService( dependencyContext: dependencyContext, viewEngineOptions: GetOptions(), fileProviderAccessor: GetFileProviderAccessor(), loggerFactory: NullLoggerFactory.Instance); var relativeFileInfo = new RelativeFileInfo( new TestFileInfo { PhysicalPath = "SomePath" }, "some-relative-path.cshtml"); var expected = "The Razor page 'some-relative-path.cshtml' failed to compile. Ensure that your " + "application's project.json sets the 'preserveCompilationContext' compilation property."; // Act and Assert var ex = Assert.Throws <InvalidOperationException>(() => compilationService.Compile(relativeFileInfo, content)); Assert.Equal(expected, ex.Message); }
/// <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( string relativePath, string viewStartLocation, string layoutLocation, Stream stream, IFileProvider rootFileProvider, IRazorCompilationService razorCompilationService) { 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) IFileInfo fileInfo = new StreamFileInfo(rootFileProvider.GetFileInfo(relativePath), stream); RelativeFileInfo relativeFileInfo = new RelativeFileInfo(fileInfo, relativePath); // Try to get the compilation from the cache, but only if the stream is empty // Cache key is relative path if no explicit view start or layout OR either/both of those if specified CompilationResult compilationResult = stream.Length == 0 ? _compilationCache.GetOrAdd( viewStartLocation == null ? (layoutLocation ?? relativePath) : (layoutLocation == null ? viewStartLocation : viewStartLocation + layoutLocation), _ => GetCompilation(relativeFileInfo, razorCompilationService)) : 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.PageFactory()); }
/// <inheritdoc /> public CompilationResult Compile(RelativeFileInfo file) { if (file == null) { throw new ArgumentNullException(nameof(file)); } GeneratorResults results; using (var inputStream = file.FileInfo.CreateReadStream()) { _logger.RazorFileToCodeCompilationStart(file.RelativePath); var startTimestamp = _logger.IsEnabled(LogLevel.Debug) ? Stopwatch.GetTimestamp() : 0; results = GenerateCode(file.RelativePath, inputStream); _logger.RazorFileToCodeCompilationEnd(file.RelativePath, startTimestamp); } if (!results.Success) { return(GetCompilationFailedResult(file, results.ParserErrors)); } return(_compilationService.Compile(file, results.GeneratedCode)); }
public void Compile_ReturnsFailedResultIfParseFails() { // Arrange var generatorResult = new GeneratorResults( new Block(new BlockBuilder { Type = BlockType.Comment }), Enumerable.Empty <TagHelperDescriptor>(), new RazorError[] { new RazorError("some message", 1, 1, 1, 1) }, new CodeBuilderResult("", new LineMapping[0]), new CodeTree()); var host = new Mock <IMvcRazorHost>(); host.Setup(h => h.GenerateCode(It.IsAny <string>(), It.IsAny <Stream>())) .Returns(generatorResult) .Verifiable(); var fileInfo = new Mock <IFileInfo>(); fileInfo.Setup(f => f.CreateReadStream()) .Returns(Stream.Null); var compiler = new Mock <ICompilationService>(MockBehavior.Strict); var relativeFileInfo = new RelativeFileInfo(fileInfo.Object, @"Views\index\home.cshtml"); var razorService = new RazorCompilationService(compiler.Object, host.Object); // Act var result = razorService.Compile(relativeFileInfo); // Assert var ex = Assert.Throws <CompilationFailedException>(() => result.CompiledType); Assert.Equal("some message", Assert.Single(ex.Messages).Message); host.Verify(); }
public void Compile_ReturnsGeneratedCodePath_IfLinePragmaIsNotAvailable() { // Arrange var fileContent = "file content"; var content = "this should fail"; var compilationService = GetRoslynCompilationService(); var relativeFileInfo = new RelativeFileInfo( new TestFileInfo { Content = fileContent }, "some-relative-path"); // Act var result = compilationService.Compile(relativeFileInfo, content); // Assert Assert.IsType <CompilationResult>(result); Assert.Null(result.CompiledType); var compilationFailure = Assert.Single(result.CompilationFailures); Assert.Equal("Generated Code", compilationFailure.SourceFilePath); Assert.Equal(content, compilationFailure.SourceFileContent); }
public void Compile_SucceedsIfReferencesAreAddedInCallback() { // Arrange var options = GetOptions(context => { var assemblyLocation = typeof(object).GetTypeInfo().Assembly.Location; context.Compilation = context .Compilation .AddReferences(MetadataReference.CreateFromFile(assemblyLocation)); }); var content = "public class MyTestType {}"; var applicationPartManager = new ApplicationPartManager(); var compilationService = GetRoslynCompilationService(applicationPartManager, options); var relativeFileInfo = new RelativeFileInfo( new TestFileInfo { PhysicalPath = "SomePath" }, "some-relative-path.cshtml"); // Act var result = compilationService.Compile(relativeFileInfo, content); // Assert Assert.Null(result.CompilationFailures); Assert.NotNull(result.CompiledType); }
public void Compile_ReturnsCompilationFailureWithPathsFromLinePragmas() { // Arrange var viewPath = "some-relative-path"; var fileContent = "test file content"; var content = $@" #line 1 ""{viewPath}"" this should fail"; var fileProvider = new TestFileProvider(); var fileInfo = fileProvider.AddFile(viewPath, fileContent); var compilationService = GetRoslynCompilationService(fileProvider: fileProvider); var relativeFileInfo = new RelativeFileInfo(fileInfo, "some-relative-path"); // Act var result = compilationService.Compile(relativeFileInfo, content); // Assert Assert.IsType <CompilationResult>(result); Assert.Null(result.CompiledType); var compilationFailure = Assert.Single(result.CompilationFailures); Assert.Equal(relativeFileInfo.RelativePath, compilationFailure.SourceFilePath); Assert.Equal(fileContent, compilationFailure.SourceFileContent); }
public void Compile_ThrowsIfDependencyContextIsNullAndTheApplicationFailsToCompileWithNoReferences() { // Arrange var content = "public class MyTestType {}"; var compilationService = new DefaultRoslynCompilationService( dependencyContext: null, viewEngineOptions: GetOptions(), fileProviderAccessor: GetFileProviderAccessor(), loggerFactory: NullLoggerFactory.Instance); var relativeFileInfo = new RelativeFileInfo( new TestFileInfo { PhysicalPath = "SomePath" }, "some-relative-path.cshtml"); var expected = "The Razor page 'some-relative-path.cshtml' failed to compile. Ensure that your " + "application's project.json sets the 'preserveCompilationContext' compilation property."; // Act and Assert var ex = Assert.Throws <InvalidOperationException>(() => compilationService.Compile(relativeFileInfo, content)); Assert.Equal(expected, ex.Message); }
/// <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); }
private CompilationResult GetCompilation(RelativeFileInfo relativeFileInfo, IRazorCompilationService razorCompilationService) { CompilationResult compilationResult = razorCompilationService.Compile(relativeFileInfo); compilationResult.EnsureSuccessful(); return(compilationResult); }
public void CompileSetsEnableInstrumentationOnHost(bool enableInstrumentation) { // Arrange var host = new Mock <IMvcRazorHost>(); host.SetupAllProperties(); host.Setup(h => h.GenerateCode(It.IsAny <string>(), It.IsAny <Stream>())) .Returns(GetGeneratorResult()); var compiler = new Mock <ICompilationService>(); compiler.Setup(c => c.Compile(It.IsAny <IFileInfo>(), It.IsAny <string>())) .Returns(CompilationResult.Successful(GetType())); var razorService = new RazorCompilationService(compiler.Object, host.Object); var relativeFileInfo = new RelativeFileInfo() { FileInfo = Mock.Of <IFileInfo>(), RelativePath = @"views\index\home.cshtml", }; // Act razorService.Compile(relativeFileInfo, isInstrumented: enableInstrumentation); // Assert Assert.Equal(enableInstrumentation, host.Object.EnableInstrumentation); }
public ViewCompilationInfo( RelativeFileInfo relativeFileInfo, GeneratorResults generatorResults) { RelativeFileInfo = relativeFileInfo; GeneratorResults = generatorResults; }
public void GetOrAdd_ReturnsCompilationResultFromFactory() { // Arrange var cache = new CompilerCache(); var fileInfo = new Mock <IFileInfo>(); fileInfo .SetupGet(i => i.LastModified) .Returns(DateTime.FromFileTimeUtc(10000)); var type = GetType(); var expected = UncachedCompilationResult.Successful(type, "hello world"); var runtimeFileInfo = new RelativeFileInfo() { FileInfo = fileInfo.Object, RelativePath = "ab", }; // Act var actual = cache.GetOrAdd(runtimeFileInfo, false, () => expected); // Assert Assert.Same(expected, actual); Assert.Equal("hello world", actual.CompiledContent); Assert.Same(type, actual.CompiledType); }
public void CompileCalculatesRootRelativePath(string appPath, string viewPath) { // Arrange var host = new Mock <IMvcRazorHost>(); host.Setup(h => h.GenerateCode(@"Views\index\home.cshtml", It.IsAny <Stream>())) .Returns(GetGeneratorResult()) .Verifiable(); var fileInfo = new Mock <IFileInfo>(); fileInfo.Setup(f => f.PhysicalPath).Returns(viewPath); fileInfo.Setup(f => f.CreateReadStream()).Returns(Stream.Null); var relativeFileInfo = new RelativeFileInfo(fileInfo.Object, @"Views\index\home.cshtml"); var compiler = new Mock <ICompilationService>(); compiler.Setup(c => c.Compile(relativeFileInfo, It.IsAny <string>())) .Returns(new CompilationResult(typeof(RazorCompilationServiceTest))); var razorService = new RazorCompilationService(compiler.Object, host.Object, GetFileProviderAccessor(), NullLoggerFactory.Instance); // Act razorService.Compile(relativeFileInfo); // Assert host.Verify(); }
public void Compile_DoesNotThrow_IfFileCannotBeRead() { // Arrange var path = "some-relative-path"; var content = $@" #line 1 ""{path}"" this should fail"; var mockFileInfo = new Mock <IFileInfo>(); mockFileInfo.Setup(f => f.CreateReadStream()) .Throws(new Exception()); var fileProvider = new TestFileProvider(); fileProvider.AddFile(path, mockFileInfo.Object); var compilationService = GetRoslynCompilationService(fileProvider: fileProvider); var relativeFileInfo = new RelativeFileInfo(mockFileInfo.Object, path); // Act var result = compilationService.Compile(relativeFileInfo, content); // Assert Assert.IsType <CompilationResult>(result); Assert.Null(result.CompiledType); var compilationFailure = Assert.Single(result.CompilationFailures); Assert.Equal(path, compilationFailure.SourceFilePath); Assert.Null(compilationFailure.SourceFileContent); }
public void Compile_UsesApplicationsCompilationSettings_ForParsingAndCompilation() { // Arrange var content = @" #if MY_CUSTOM_DEFINE public class MyCustomDefinedClass {} #else public class MyNonCustomDefinedClass {} #endif "; var options = GetOptions(); options.ParseOptions = options.ParseOptions.WithPreprocessorSymbols("MY_CUSTOM_DEFINE"); var compilationService = GetRoslynCompilationService(options: options); var relativeFileInfo = new RelativeFileInfo( new TestFileInfo { PhysicalPath = "SomePath" }, "some-relative-path"); // Act var result = compilationService.Compile(relativeFileInfo, content); // Assert Assert.NotNull(result.CompiledType); Assert.Equal("MyCustomDefinedClass", result.CompiledType.Name); }
/// <inheritdoc /> public CompilationResult Compile([NotNull] RelativeFileInfo fileInfo, [NotNull] string compilationContent) { var assemblyName = Path.GetRandomFileName(); var compilationSettings = _compilerOptionsProvider.GetCompilationSettings(_environment); var syntaxTree = SyntaxTreeGenerator.Generate(compilationContent, assemblyName, compilationSettings); var references = _applicationReferences.Value; var compilationOptions = compilationSettings.CompilationOptions .WithOutputKind(OutputKind.DynamicallyLinkedLibrary); var compilation = CSharpCompilation.Create(assemblyName, options: compilationOptions, syntaxTrees: new[] { syntaxTree }, references: references); using (var ms = new MemoryStream()) { using (var pdb = new MemoryStream()) { EmitResult result; if (_supportsPdbGeneration.Value) { result = compilation.Emit(ms, pdbStream: pdb); } else { result = compilation.Emit(ms); } if (!result.Success) { return(GetCompilationFailedResult( fileInfo.RelativePath, compilationContent, assemblyName, result.Diagnostics)); } Assembly assembly; ms.Seek(0, SeekOrigin.Begin); if (_supportsPdbGeneration.Value) { pdb.Seek(0, SeekOrigin.Begin); assembly = _loader.LoadStream(ms, pdb); } else { assembly = _loader.LoadStream(ms, assemblySymbols: null); } var type = assembly.GetExportedTypes() .First(t => t.Name.StartsWith(_classPrefix, StringComparison.Ordinal)); return(UncachedCompilationResult.Successful(type, compilationContent)); } } }
public CompilationResult Compile(RelativeFileInfo fileInfo) { var result = _inner.Compile(fileInfo); _log.Add(new CompileEntry { FileInfo = fileInfo, Result = result }); return(result); }
/// <inheritdoc /> public CompilationResult Compile(RelativeFileInfo fileInfo, string compilationContent) { var assemblyName = Path.GetRandomFileName(); var compilationSettings = _compilerOptionsProvider.GetCompilationSettings(_environment); var syntaxTree = SyntaxTreeGenerator.Generate(compilationContent, assemblyName, compilationSettings); var references = _applicationReferences.Value; var compilationOptions = compilationSettings.CompilationOptions .WithOutputKind(OutputKind.DynamicallyLinkedLibrary); var compilation = CSharpCompilation.Create(assemblyName, options: compilationOptions, syntaxTrees: new[] { syntaxTree }, references: references); using (var ms = new MemoryStream()) { using (var pdb = new MemoryStream()) { EmitResult result; if (_supportsPdbGeneration.Value) { result = compilation.Emit(ms, pdbStream: pdb); } else { result = compilation.Emit(ms); } if (!result.Success) { return GetCompilationFailedResult( fileInfo.RelativePath, compilationContent, assemblyName, result.Diagnostics); } Assembly assembly; ms.Seek(0, SeekOrigin.Begin); if (_supportsPdbGeneration.Value) { pdb.Seek(0, SeekOrigin.Begin); assembly = _loader.LoadStream(ms, pdb); } else { assembly = _loader.LoadStream(ms, assemblySymbols: null); } var type = assembly.GetExportedTypes() .First(t => t.Name.StartsWith(_classPrefix, StringComparison.Ordinal)); return UncachedCompilationResult.Successful(type, compilationContent); } } }
private MemoryCacheEntryOptions GetMemoryCacheEntryOptions( RelativeFileInfo fileInfo, PrecompilationCacheEntry cacheEntry) { var options = new MemoryCacheEntryOptions(); options.AddExpirationToken(FileProvider.Watch(fileInfo.RelativePath)); foreach (var path in ViewHierarchyUtility.GetViewImportsLocations(fileInfo.RelativePath)) { options.AddExpirationToken(FileProvider.Watch(path)); } return(options); }
/// <inheritdoc /> public CompilationResult Compile(RelativeFileInfo fileInfo, string compilationContent) { if (fileInfo == null) { throw new ArgumentNullException(nameof(fileInfo)); } if (compilationContent == null) { throw new ArgumentNullException(nameof(compilationContent)); } _logger.GeneratedCodeToAssemblyCompilationStart(fileInfo.RelativePath); var startTimestamp = _logger.IsEnabled(LogLevel.Debug) ? Stopwatch.GetTimestamp() : 0; var assemblyName = Path.GetRandomFileName(); var compilation = CreateCompilation(compilationContent, assemblyName); using (var assemblyStream = new MemoryStream()) { using (var pdbStream = new MemoryStream()) { var result = compilation.Emit( assemblyStream, pdbStream, options: _compiler.EmitOptions); if (!result.Success) { return(GetCompilationFailedResult( fileInfo.RelativePath, compilationContent, assemblyName, result.Diagnostics)); } assemblyStream.Seek(0, SeekOrigin.Begin); pdbStream.Seek(0, SeekOrigin.Begin); var assembly = LoadAssembly(assemblyStream, pdbStream); var type = assembly.GetExportedTypes().FirstOrDefault(a => !a.IsNested); _logger.GeneratedCodeToAssemblyCompilationEnd(fileInfo.RelativePath, startTimestamp); SaveAssembly(fileInfo, assemblyStream, pdbStream); return(new CompilationResult(type)); } } }
public IRazorPage CreateInstance([NotNull] string relativePath, Stream stream) { if (relativePath.StartsWith("~/", StringComparison.Ordinal)) { // For tilde slash paths, drop the leading ~ to make it work with the underlying IFileProvider. relativePath = relativePath.Substring(1); } // Code below is taken from CompilerCache (specifically OnCacheMiss) which is responsible for managing the compilation step in MVC // Check the file var fileProvider = stream == null ? (IFileProvider)_fileProvider : new WyamStreamFileProvider(_fileProvider, stream); var fileInfo = fileProvider.GetFileInfo(relativePath); if (!fileInfo.Exists) { return(null); } // If relative path is the root, it probably means this isn't from reading a file so don't bother with caching IExecutionCache cache = relativePath == "/" ? null : _executionContext.ExecutionCache; string key = null; Type pageType = null; if (cache != null) { key = relativePath + " " + RazorFileHash.GetHash(fileInfo); if (!cache.TryGetValue(key, out pageType)) { pageType = null; } } // Compile and store in cache if not found if (pageType == null) { var relativeFileInfo = new RelativeFileInfo(fileInfo, relativePath); pageType = _razorcompilationService.Compile(relativeFileInfo); cache?.Set(key, pageType); } // Create an return a new page instance IRazorPage page = (IRazorPage)Activator.CreateInstance(pageType); page.Path = relativePath; return(page); }
public void FileWithTheSameLengthAndDifferentTime_DoesNot_OverridesPrecompilation( Type resultViewType, long fileTimeUTC, bool swapsPreCompile) { // Arrange var instance = (View)Activator.CreateInstance(resultViewType); var length = Encoding.UTF8.GetByteCount(instance.Content); var collection = new ViewCollection(); var cache = new CompilerCache(new[] { new ViewCollection() }); var fileInfo = new Mock <IFileInfo>(); fileInfo .SetupGet(i => i.Length) .Returns(length); fileInfo .SetupGet(i => i.LastModified) .Returns(DateTime.FromFileTimeUtc(fileTimeUTC)); fileInfo.Setup(i => i.CreateReadStream()) .Returns(GetMemoryStream(instance.Content)); var preCompileType = typeof(PreCompile); var runtimeFileInfo = new RelativeFileInfo() { FileInfo = fileInfo.Object, RelativePath = "ab", }; // Act var actual = cache.GetOrAdd(runtimeFileInfo, enableInstrumentation: false, compile: () => CompilationResult.Successful(resultViewType)); // Assert if (swapsPreCompile) { Assert.Equal(actual.CompiledType, resultViewType); } else { Assert.Equal(actual.CompiledType, typeof(PreCompile)); } }
protected virtual PrecompilationCacheEntry GetCacheEntry(RelativeFileInfo fileInfo) { if (fileInfo == null) { throw new ArgumentNullException(nameof(fileInfo)); } using (var stream = fileInfo.FileInfo.CreateReadStream()) { using (var host = GetRazorHost()) { var results = host.GenerateCode(fileInfo.RelativePath, stream); if (results.Success) { var syntaxTree = SyntaxTreeGenerator.Generate( results.GeneratedCode, fileInfo.FileInfo.PhysicalPath, CompilationSettings); var fullTypeName = results.GetMainClassName(host, syntaxTree); if (fullTypeName != null) { var razorFileInfo = new RazorFileInfo { RelativePath = fileInfo.RelativePath, FullTypeName = fullTypeName }; return(new PrecompilationCacheEntry(razorFileInfo, syntaxTree)); } } else { var diagnostics = results .ParserErrors .Select(error => error.ToDiagnostics(fileInfo.FileInfo.PhysicalPath)) .ToList(); return(new PrecompilationCacheEntry(diagnostics)); } } } return(null); }
protected virtual PrecompilationCacheEntry GetCacheEntry([NotNull] RelativeFileInfo fileInfo) { using (var stream = fileInfo.FileInfo.CreateReadStream()) { var host = GetRazorHost(); var results = host.GenerateCode(fileInfo.RelativePath, stream); if (results.Success) { var syntaxTree = SyntaxTreeGenerator.Generate(results.GeneratedCode, fileInfo.FileInfo.PhysicalPath, CompilationSettings); var fullTypeName = results.GetMainClassName(host, syntaxTree); if (fullTypeName != null) { var hashAlgorithmVersion = RazorFileHash.HashAlgorithmVersion1; var hash = RazorFileHash.GetHash(fileInfo.FileInfo, hashAlgorithmVersion); var razorFileInfo = new RazorFileInfo { RelativePath = fileInfo.RelativePath, LastModified = fileInfo.FileInfo.LastModified, Length = fileInfo.FileInfo.Length, FullTypeName = fullTypeName, Hash = hash, HashAlgorithmVersion = hashAlgorithmVersion }; return(new PrecompilationCacheEntry(razorFileInfo, syntaxTree)); } } else { var diagnostics = results.ParserErrors .Select(error => error.ToDiagnostics(fileInfo.FileInfo.PhysicalPath)) .ToList(); return(new PrecompilationCacheEntry(diagnostics)); } } return(null); }
public void Compile_ReturnsResultFromCompilationServiceIfParseSucceeds() { // Arrange var code = "compiled-content"; var generatorResult = new GeneratorResults( new Block(new BlockBuilder { Type = BlockType.Comment }), Enumerable.Empty<TagHelperDescriptor>(), new ParserErrorSink(), new CodeBuilderResult(code, new LineMapping[0]), new CodeTree()); var host = new Mock<IMvcRazorHost>(); host.Setup(h => h.GenerateCode(It.IsAny<string>(), It.IsAny<Stream>())) .Returns(generatorResult); var fileInfo = new Mock<IFileInfo>(); fileInfo.Setup(f => f.CreateReadStream()) .Returns(Stream.Null); var relativeFileInfo = new RelativeFileInfo(fileInfo.Object, @"Views\index\home.cshtml"); var compilationResult = CompilationResult.Successful(typeof(object)); var compiler = new Mock<ICompilationService>(); compiler.Setup(c => c.Compile(relativeFileInfo, code)) .Returns(compilationResult) .Verifiable(); var razorService = new RazorCompilationService(compiler.Object, host.Object); // Act var result = razorService.Compile(relativeFileInfo); // Assert Assert.Same(compilationResult, result); compiler.Verify(); }