First stab Roslyn based compilation service for razor pages
- Flow the host service provider to MvcServices - Use assembly neutral interfaces to access host services - Added RoslynCompilationService to Microsoft.AspNet.Mvc.Razor - Modified self host sample as helios needs to be updated to flow more services
This commit is contained in:
parent
5c07c6a07b
commit
346f02e37c
|
|
@ -9,11 +9,17 @@ namespace MvcSample
|
|||
public class Program
|
||||
{
|
||||
const string baseUrl = "http://localhost:9001/";
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public static void Main()
|
||||
public Program(IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public void Main()
|
||||
{
|
||||
#if NET45
|
||||
using (WebApp.Start<Startup>(new StartOptions(baseUrl)))
|
||||
using (WebApp.Start(baseUrl, app => new Startup(_serviceProvider).Configuration(app)))
|
||||
{
|
||||
Console.WriteLine("Listening at {0}", baseUrl);
|
||||
Process.Start(baseUrl);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,13 @@ namespace MvcSample
|
|||
{
|
||||
public class Startup
|
||||
{
|
||||
private IServiceProvider _serviceProvider;
|
||||
|
||||
public Startup(IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public void Configuration(IAppBuilder app)
|
||||
{
|
||||
app.UseErrorPage();
|
||||
|
|
@ -28,7 +35,7 @@ namespace MvcSample
|
|||
{
|
||||
string appRoot = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
|
||||
|
||||
var mvcServices = new MvcServices(appRoot);
|
||||
var mvcServices = new MvcServices(appRoot, _serviceProvider);
|
||||
|
||||
var router = builder.UseRouter();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.Net.Runtime.Services;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
||||
{
|
||||
public class RoslynCompilationService : ICompilationService
|
||||
{
|
||||
private readonly IMetadataReferenceProvider _provider;
|
||||
private readonly IApplicationEnvironment _environment;
|
||||
|
||||
public RoslynCompilationService(IServiceProvider serviceProvider)
|
||||
{
|
||||
// TODO: Get these services via ctor injection when we get container chaining implemented
|
||||
_provider = (IMetadataReferenceProvider)serviceProvider.GetService(typeof(IMetadataReferenceProvider));
|
||||
_environment = (IApplicationEnvironment)serviceProvider.GetService(typeof(IApplicationEnvironment));
|
||||
}
|
||||
|
||||
public Task<CompilationResult> Compile(string content)
|
||||
{
|
||||
var syntaxTrees = new[] { CSharpSyntaxTree.ParseText(content) };
|
||||
var targetFramework = _environment.TargetFramework;
|
||||
|
||||
// Get references from the application itself and from
|
||||
// this assembly for the base types etc
|
||||
var referenceNames = new[] {
|
||||
_environment.ApplicationName,
|
||||
typeof(RoslynCompilationService).GetTypeInfo().Assembly.GetName().Name
|
||||
};
|
||||
|
||||
var references = referenceNames.SelectMany(name => _provider.GetReferences(name, targetFramework))
|
||||
.Cast<MetadataReference>();
|
||||
|
||||
var assemblyName = Path.GetRandomFileName();
|
||||
|
||||
var compilation = CSharpCompilation.Create(assemblyName,
|
||||
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary),
|
||||
syntaxTrees: syntaxTrees,
|
||||
references: references);
|
||||
|
||||
var ms = new MemoryStream();
|
||||
var result = compilation.Emit(ms);
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
var messages = result.Diagnostics.Where(IsError).Select(d => GetCompilationMessage(d));
|
||||
|
||||
return Task.FromResult(CompilationResult.Failed(content, messages));
|
||||
}
|
||||
|
||||
// TODO: Flow loader to this code so we're not using Load() directly
|
||||
var type = Assembly.Load(ms.ToArray())
|
||||
.GetExportedTypes()
|
||||
.First();
|
||||
|
||||
return Task.FromResult(CompilationResult.Successful(String.Empty, type));
|
||||
}
|
||||
|
||||
private CompilationMessage GetCompilationMessage(Diagnostic diagnostic)
|
||||
{
|
||||
#if NET45
|
||||
var formatter = DiagnosticFormatter.Instance;
|
||||
#else
|
||||
var formatter = new DiagnosticFormatter();
|
||||
#endif
|
||||
return new CompilationMessage(formatter.Format(diagnostic));
|
||||
}
|
||||
|
||||
private bool IsError(Diagnostic diagnostic)
|
||||
{
|
||||
return diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Microsoft.Net.Runtime.Services
|
||||
{
|
||||
[AssemblyNeutral]
|
||||
public interface IApplicationEnvironment
|
||||
{
|
||||
string ApplicationName { get; }
|
||||
string Version { get; }
|
||||
string ApplicationBasePath { get; }
|
||||
FrameworkName TargetFramework { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace Microsoft.Net.Runtime.Services
|
||||
{
|
||||
[AssemblyNeutral]
|
||||
public interface IMetadataReferenceProvider
|
||||
{
|
||||
// REVIEW: This is object because we don't have a reference to roslyn in this assembly
|
||||
IEnumerable<object> GetReferences(string name, FrameworkName targetFramework);
|
||||
}
|
||||
|
||||
[AssemblyNeutral]
|
||||
public class AssemblyNeutralAttribute : Attribute { }
|
||||
}
|
||||
|
|
@ -8,10 +8,21 @@
|
|||
"Microsoft.AspNet.Mvc" : "",
|
||||
"Microsoft.AspNet.Mvc.ModelBinding" : "",
|
||||
"Microsoft.AspNet.Mvc.Rendering" : "",
|
||||
"Microsoft.AspNet.Mvc.Razor.Host" : ""
|
||||
"Microsoft.AspNet.Mvc.Razor.Host" : "",
|
||||
"Microsoft.CodeAnalysis" : "0.6.31123.2",
|
||||
"Microsoft.CodeAnalysis.CSharp" : "0.6.31123.2",
|
||||
"System.Reflection.Metadata.Ecma335": "0.6.31123.2",
|
||||
"System.Collections.Immutable" : "1.1.15.0"
|
||||
},
|
||||
"configurations": {
|
||||
"net45": {},
|
||||
"net45" : {
|
||||
"dependencies": {
|
||||
"System.Xml.Linq": "",
|
||||
"System.Xml": "",
|
||||
"System.Runtime" : "",
|
||||
"System.Collections" : ""
|
||||
}
|
||||
},
|
||||
"k10" : {}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
using Microsoft.AspNet.DependencyInjection;
|
||||
using System;
|
||||
using Microsoft.AspNet.DependencyInjection;
|
||||
using Microsoft.AspNet.DependencyInjection.NestedProviders;
|
||||
using Microsoft.AspNet.FileSystems;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.Razor;
|
||||
using Microsoft.AspNet.Mvc.Razor.Compilation;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Startup
|
||||
{
|
||||
|
|
@ -11,6 +13,11 @@ namespace Microsoft.AspNet.Mvc.Startup
|
|||
public ServiceProvider Services { get; private set; }
|
||||
|
||||
public MvcServices(string appRoot)
|
||||
: this(appRoot, null)
|
||||
{
|
||||
}
|
||||
|
||||
public MvcServices(string appRoot, IServiceProvider hostServiceProvider)
|
||||
{
|
||||
Services = new ServiceProvider();
|
||||
|
||||
|
|
@ -29,7 +36,16 @@ namespace Microsoft.AspNet.Mvc.Startup
|
|||
AddInstance<IMvcRazorHost>(new MvcRazorHost(typeof(RazorView).FullName));
|
||||
|
||||
#if NET45
|
||||
Add<ICompilationService, CscBasedCompilationService>();
|
||||
// TODO: Container chaining to flow services from the host to this container
|
||||
if (hostServiceProvider == null)
|
||||
{
|
||||
Add<ICompilationService, CscBasedCompilationService>();
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Make this work like normal when we get container chaining
|
||||
AddInstance<ICompilationService>(new RoslynCompilationService(hostServiceProvider));
|
||||
}
|
||||
#endif
|
||||
Add<IRazorCompilationService, RazorCompilationService>();
|
||||
Add<IVirtualPathViewFactory, VirtualPathViewFactory>();
|
||||
|
|
|
|||
Loading…
Reference in New Issue