// Wyam - Use the Roslyn scripting engine for compilation // In MVC, this part is done in RoslynCompilationService private Type Compile([NotNull] RelativeFileInfo file, [NotNull] string compilationContent) { HashSet <Assembly> assemblies = new HashSet <Assembly>(new AssemblyEqualityComparer()) { Assembly.GetAssembly(typeof(Wyam.Razor.Razor)) // Wyam.Razor }; if (_executionContext.Assemblies != null) { assemblies.UnionWith(_executionContext.Assemblies); } var assemblyName = Path.GetRandomFileName(); var parseOptions = new CSharpParseOptions(); var syntaxTree = CSharpSyntaxTree.ParseText(SourceText.From(compilationContent, Encoding.UTF8), parseOptions, assemblyName); var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary); var assemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location); var metadataReferences = assemblies .Where(x => !x.IsDynamic && !string.IsNullOrEmpty(x.Location)) .Select(x => _metadataReferences.GetOrAdd(x.Location, y => MetadataReference.CreateFromFile(y))); var compilation = CSharpCompilation.Create(assemblyName, new[] { syntaxTree }, metadataReferences, compilationOptions) .AddReferences( // For some reason, Roslyn really wants these added by filename // See http://stackoverflow.com/questions/23907305/roslyn-has-no-reference-to-system-runtime _metadataReferences.GetOrAdd(Path.Combine(assemblyPath, "mscorlib.dll"), x => MetadataReference.CreateFromFile(x)), _metadataReferences.GetOrAdd(Path.Combine(assemblyPath, "System.dll"), x => MetadataReference.CreateFromFile(x)), _metadataReferences.GetOrAdd(Path.Combine(assemblyPath, "System.Core.dll"), x => MetadataReference.CreateFromFile(x)), _metadataReferences.GetOrAdd(Path.Combine(assemblyPath, "System.Runtime.dll"), x => MetadataReference.CreateFromFile(x)) ); if (_executionContext.DynamicAssemblies.Count > 0) { compilation = compilation.AddReferences(_executionContext.DynamicAssemblies.Select(x => MetadataReference.CreateFromImage(x))); } using (var ms = new MemoryStream()) { EmitResult result = compilation.Emit(ms); if (!result.Success) { Trace.Error("{0} errors compiling {1}:{2}{3}", result.Diagnostics.Length, file.RelativePath, Environment.NewLine, string.Join(Environment.NewLine, result.Diagnostics)); throw new AggregateException(result.Diagnostics.Select(x => new Exception(x.ToString()))); } ms.Seek(0, SeekOrigin.Begin); byte[] assemblyBytes = ms.ToArray(); Assembly assembly = Assembly.Load(assemblyBytes); var type = assembly.GetExportedTypes().First(t => t.Name.StartsWith(_razorHost.MainClassNamePrefix, StringComparison.Ordinal)); return(type); } }
/// <inheritdoc /> public Type Compile([NotNull] RelativeFileInfo file) { GeneratorResults results; using (var inputStream = file.FileInfo.CreateReadStreamWithRetry()) { results = GenerateCode(file.RelativePath, inputStream); } if (!results.Success) { Trace.Error("{0} errors parsing {1}:{2}{3}", results.ParserErrors.Count(), file.RelativePath, Environment.NewLine, string.Join(Environment.NewLine, results.ParserErrors)); throw new AggregateException(results.ParserErrors.Select(x => new Exception(x.Message))); } return(Compile(file, results.GeneratedCode)); }
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; }