// 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));
        }
Esempio n. 3
0
        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;
        }