parent
62b9db93b6
commit
110ee28e3e
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.Framework.Runtime;
|
||||||
|
using Microsoft.Framework.Runtime.Roslyn;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Razor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Extension methods for <see cref="ICompilerOptionsProvider"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static class CompilationOptionsProviderExtension
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Parses the <see cref="ICompilerOptions"/> for the current executing application and returns a
|
||||||
|
/// <see cref="CompilationSettings"/> used for Roslyn compilation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="compilerOptionsProvider">A <see cref="ICompilerOptionsProvider"/> that reads compiler options.</param>
|
||||||
|
/// <param name="applicationEnvironment">The <see cref="IApplicationEnvironment"/> for the executing application.</param>
|
||||||
|
/// <returns>The <see cref="CompilationSettings"/> for the current application.</returns>
|
||||||
|
public static CompilationSettings GetCompilationSettings(
|
||||||
|
[NotNull] this ICompilerOptionsProvider compilerOptionsProvider,
|
||||||
|
[NotNull] IApplicationEnvironment applicationEnvironment)
|
||||||
|
{
|
||||||
|
return compilerOptionsProvider.GetCompilerOptions(applicationEnvironment.ApplicationBasePath,
|
||||||
|
applicationEnvironment.RuntimeFramework,
|
||||||
|
applicationEnvironment.Configuration)
|
||||||
|
.ToCompilationSettings(applicationEnvironment.RuntimeFramework);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.CSharp;
|
||||||
using Microsoft.CodeAnalysis.Emit;
|
using Microsoft.CodeAnalysis.Emit;
|
||||||
using Microsoft.Framework.Runtime;
|
using Microsoft.Framework.Runtime;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
namespace Microsoft.AspNet.Mvc.Razor
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A type that uses Roslyn to compile C# content.
|
/// A type that uses Roslyn to compile C# content.
|
||||||
|
|
@ -29,6 +29,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly IApplicationEnvironment _environment;
|
private readonly IApplicationEnvironment _environment;
|
||||||
private readonly IAssemblyLoadContext _loader;
|
private readonly IAssemblyLoadContext _loader;
|
||||||
|
private readonly ICompilerOptionsProvider _compilerOptionsProvider;
|
||||||
|
|
||||||
private readonly Lazy<List<MetadataReference>> _applicationReferences;
|
private readonly Lazy<List<MetadataReference>> _applicationReferences;
|
||||||
|
|
||||||
|
|
@ -44,12 +45,14 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
||||||
public RoslynCompilationService(IApplicationEnvironment environment,
|
public RoslynCompilationService(IApplicationEnvironment environment,
|
||||||
IAssemblyLoadContextAccessor loaderAccessor,
|
IAssemblyLoadContextAccessor loaderAccessor,
|
||||||
ILibraryManager libraryManager,
|
ILibraryManager libraryManager,
|
||||||
|
ICompilerOptionsProvider compilerOptionsProvider,
|
||||||
IMvcRazorHost host)
|
IMvcRazorHost host)
|
||||||
{
|
{
|
||||||
_environment = environment;
|
_environment = environment;
|
||||||
_loader = loaderAccessor.GetLoadContext(typeof(RoslynCompilationService).GetTypeInfo().Assembly);
|
_loader = loaderAccessor.GetLoadContext(typeof(RoslynCompilationService).GetTypeInfo().Assembly);
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_applicationReferences = new Lazy<List<MetadataReference>>(GetApplicationReferences);
|
_applicationReferences = new Lazy<List<MetadataReference>>(GetApplicationReferences);
|
||||||
|
_compilerOptionsProvider = compilerOptionsProvider;
|
||||||
_classPrefix = host.MainClassNamePrefix;
|
_classPrefix = host.MainClassNamePrefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,15 +63,19 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
||||||
// map to the source file. If a file does not exist on a physical file system, PhysicalPath will be null.
|
// map to the source file. If a file does not exist on a physical file system, PhysicalPath will be null.
|
||||||
// This prevents files that exist in a non-physical file system from being debugged.
|
// This prevents files that exist in a non-physical file system from being debugged.
|
||||||
var path = fileInfo.PhysicalPath ?? fileInfo.Name;
|
var path = fileInfo.PhysicalPath ?? fileInfo.Name;
|
||||||
var syntaxTrees = new[] { SyntaxTreeGenerator.Generate(compilationContent, path) };
|
var compilationSettings = _compilerOptionsProvider.GetCompilationSettings(_environment);
|
||||||
|
var syntaxTree = SyntaxTreeGenerator.Generate(compilationContent,
|
||||||
|
path,
|
||||||
|
compilationSettings);
|
||||||
var references = _applicationReferences.Value;
|
var references = _applicationReferences.Value;
|
||||||
|
|
||||||
var assemblyName = Path.GetRandomFileName();
|
var assemblyName = Path.GetRandomFileName();
|
||||||
|
var compilationOptions = compilationSettings.CompilationOptions
|
||||||
|
.WithOutputKind(OutputKind.DynamicallyLinkedLibrary);
|
||||||
|
|
||||||
var compilation = CSharpCompilation.Create(assemblyName,
|
var compilation = CSharpCompilation.Create(assemblyName,
|
||||||
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary),
|
options: compilationOptions,
|
||||||
syntaxTrees: syntaxTrees,
|
syntaxTrees: new[] { syntaxTree },
|
||||||
references: references);
|
references: references);
|
||||||
|
|
||||||
using (var ms = new MemoryStream())
|
using (var ms = new MemoryStream())
|
||||||
|
|
@ -115,7 +122,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
||||||
.First(t => t.Name.
|
.First(t => t.Name.
|
||||||
StartsWith(_classPrefix, StringComparison.Ordinal));
|
StartsWith(_classPrefix, StringComparison.Ordinal));
|
||||||
|
|
||||||
return UncachedCompilationResult.Successful(type);
|
return UncachedCompilationResult.Successful(type, compilationContent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,48 +5,29 @@ using System.Text;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.CodeAnalysis.CSharp;
|
using Microsoft.CodeAnalysis.CSharp;
|
||||||
using Microsoft.CodeAnalysis.Text;
|
using Microsoft.CodeAnalysis.Text;
|
||||||
|
using Microsoft.Framework.Runtime.Roslyn;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Razor
|
namespace Microsoft.AspNet.Mvc.Razor
|
||||||
{
|
{
|
||||||
public static class SyntaxTreeGenerator
|
public static class SyntaxTreeGenerator
|
||||||
{
|
{
|
||||||
private static CSharpParseOptions DefaultOptions
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return CSharpParseOptions.Default
|
|
||||||
.WithLanguageVersion(LanguageVersion.CSharp6);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SyntaxTree Generate([NotNull] string text, [NotNull] string path)
|
|
||||||
{
|
|
||||||
return GenerateCore(text, path, DefaultOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SyntaxTree Generate([NotNull] string text,
|
public static SyntaxTree Generate([NotNull] string text,
|
||||||
[NotNull] string path,
|
[NotNull] string path,
|
||||||
[NotNull] CSharpParseOptions options)
|
[NotNull] CompilationSettings compilationSettings)
|
||||||
{
|
|
||||||
return GenerateCore(text, path, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SyntaxTree GenerateCore([NotNull] string text,
|
|
||||||
[NotNull] string path,
|
|
||||||
[NotNull] CSharpParseOptions options)
|
|
||||||
{
|
{
|
||||||
var sourceText = SourceText.From(text, Encoding.UTF8);
|
var sourceText = SourceText.From(text, Encoding.UTF8);
|
||||||
var syntaxTree = CSharpSyntaxTree.ParseText(sourceText,
|
var syntaxTree = CSharpSyntaxTree.ParseText(sourceText,
|
||||||
path: path,
|
path: path,
|
||||||
options: options);
|
options: GetParseOptions(compilationSettings));
|
||||||
|
|
||||||
return syntaxTree;
|
return syntaxTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CSharpParseOptions GetParseOptions(CSharpCompilation compilation)
|
public static CSharpParseOptions GetParseOptions(CompilationSettings compilationSettings)
|
||||||
{
|
{
|
||||||
return CSharpParseOptions.Default
|
return new CSharpParseOptions(
|
||||||
.WithLanguageVersion(compilation.LanguageVersion);
|
languageVersion: compilationSettings.LanguageVersion,
|
||||||
|
preprocessorSymbols: compilationSettings.Defines.AsImmutable());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.CodeAnalysis.CSharp;
|
using Microsoft.Framework.Runtime.Roslyn;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Razor
|
namespace Microsoft.AspNet.Mvc.Razor
|
||||||
{
|
{
|
||||||
|
|
@ -13,13 +13,13 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
private string _fileFormat;
|
private string _fileFormat;
|
||||||
|
|
||||||
protected IReadOnlyList<RazorFileInfo> FileInfos { get; private set; }
|
protected IReadOnlyList<RazorFileInfo> FileInfos { get; private set; }
|
||||||
protected CSharpParseOptions Options { get; private set; }
|
protected CompilationSettings CompilationSettings { get; }
|
||||||
|
|
||||||
public RazorFileInfoCollectionGenerator([NotNull] IReadOnlyList<RazorFileInfo> fileInfos,
|
public RazorFileInfoCollectionGenerator([NotNull] IReadOnlyList<RazorFileInfo> fileInfos,
|
||||||
[NotNull] CSharpParseOptions options)
|
[NotNull] CompilationSettings compilationSettings)
|
||||||
{
|
{
|
||||||
FileInfos = fileInfos;
|
FileInfos = fileInfos;
|
||||||
Options = options;
|
CompilationSettings = compilationSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual SyntaxTree GenerateCollection()
|
public virtual SyntaxTree GenerateCollection()
|
||||||
|
|
@ -38,7 +38,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
var sourceCode = builder.ToString();
|
var sourceCode = builder.ToString();
|
||||||
var syntaxTree = SyntaxTreeGenerator.Generate(sourceCode,
|
var syntaxTree = SyntaxTreeGenerator.Generate(sourceCode,
|
||||||
"__AUTO__GeneratedViewsCollection.cs",
|
"__AUTO__GeneratedViewsCollection.cs",
|
||||||
Options);
|
CompilationSettings);
|
||||||
|
|
||||||
return syntaxTree;
|
return syntaxTree;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.CSharp;
|
||||||
using Microsoft.Framework.DependencyInjection;
|
using Microsoft.Framework.DependencyInjection;
|
||||||
using Microsoft.Framework.OptionsModel;
|
using Microsoft.Framework.OptionsModel;
|
||||||
using Microsoft.Framework.Runtime;
|
using Microsoft.Framework.Runtime;
|
||||||
|
using Microsoft.Framework.Runtime.Roslyn;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Razor
|
namespace Microsoft.AspNet.Mvc.Razor
|
||||||
{
|
{
|
||||||
|
|
@ -19,24 +20,28 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
private readonly IFileSystem _fileSystem;
|
private readonly IFileSystem _fileSystem;
|
||||||
private readonly IMvcRazorHost _host;
|
private readonly IMvcRazorHost _host;
|
||||||
|
|
||||||
public RazorPreCompiler([NotNull] IServiceProvider designTimeServiceProvider) :
|
public RazorPreCompiler([NotNull] IServiceProvider designTimeServiceProvider,
|
||||||
|
[NotNull] CompilationSettings compilationSettings) :
|
||||||
this(designTimeServiceProvider,
|
this(designTimeServiceProvider,
|
||||||
designTimeServiceProvider.GetRequiredService<IMvcRazorHost>(),
|
designTimeServiceProvider.GetRequiredService<IMvcRazorHost>(),
|
||||||
designTimeServiceProvider.GetRequiredService<IOptions<RazorViewEngineOptions>>())
|
designTimeServiceProvider.GetRequiredService<IOptions<RazorViewEngineOptions>>(),
|
||||||
|
compilationSettings)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public RazorPreCompiler([NotNull] IServiceProvider designTimeServiceProvider,
|
public RazorPreCompiler([NotNull] IServiceProvider designTimeServiceProvider,
|
||||||
[NotNull] IMvcRazorHost host,
|
[NotNull] IMvcRazorHost host,
|
||||||
[NotNull] IOptions<RazorViewEngineOptions> optionsAccessor)
|
[NotNull] IOptions<RazorViewEngineOptions> optionsAccessor,
|
||||||
|
[NotNull] CompilationSettings compilationSettings)
|
||||||
{
|
{
|
||||||
_serviceProvider = designTimeServiceProvider;
|
_serviceProvider = designTimeServiceProvider;
|
||||||
_host = host;
|
_host = host;
|
||||||
|
|
||||||
var appEnv = _serviceProvider.GetRequiredService<IApplicationEnvironment>();
|
|
||||||
_fileSystem = optionsAccessor.Options.FileSystem;
|
_fileSystem = optionsAccessor.Options.FileSystem;
|
||||||
|
CompilationSettings = compilationSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected CompilationSettings CompilationSettings { get; }
|
||||||
|
|
||||||
protected virtual string FileExtension { get; } = ".cshtml";
|
protected virtual string FileExtension { get; } = ".cshtml";
|
||||||
|
|
||||||
public virtual void CompileViews([NotNull] IBeforeCompileContext context)
|
public virtual void CompileViews([NotNull] IBeforeCompileContext context)
|
||||||
|
|
@ -47,7 +52,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
{
|
{
|
||||||
var collectionGenerator = new RazorFileInfoCollectionGenerator(
|
var collectionGenerator = new RazorFileInfoCollectionGenerator(
|
||||||
descriptors,
|
descriptors,
|
||||||
SyntaxTreeGenerator.GetParseOptions(context.CSharpCompilation));
|
CompilationSettings);
|
||||||
|
|
||||||
var tree = collectionGenerator.GenerateCollection();
|
var tree = collectionGenerator.GenerateCollection();
|
||||||
context.CSharpCompilation = context.CSharpCompilation.AddSyntaxTrees(tree);
|
context.CSharpCompilation = context.CSharpCompilation.AddSyntaxTrees(tree);
|
||||||
|
|
@ -57,14 +62,11 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
protected virtual IReadOnlyList<RazorFileInfo> CreateCompilationDescriptors(
|
protected virtual IReadOnlyList<RazorFileInfo> CreateCompilationDescriptors(
|
||||||
[NotNull] IBeforeCompileContext context)
|
[NotNull] IBeforeCompileContext context)
|
||||||
{
|
{
|
||||||
var options = SyntaxTreeGenerator.GetParseOptions(context.CSharpCompilation);
|
|
||||||
var list = new List<RazorFileInfo>();
|
var list = new List<RazorFileInfo>();
|
||||||
|
|
||||||
foreach (var info in GetFileInfosRecursive(string.Empty))
|
foreach (var info in GetFileInfosRecursive(string.Empty))
|
||||||
{
|
{
|
||||||
var descriptor = ParseView(info,
|
var descriptor = ParseView(info, context);
|
||||||
context,
|
|
||||||
options);
|
|
||||||
|
|
||||||
if (descriptor != null)
|
if (descriptor != null)
|
||||||
{
|
{
|
||||||
|
|
@ -107,8 +109,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual RazorFileInfo ParseView([NotNull] RelativeFileInfo fileInfo,
|
protected virtual RazorFileInfo ParseView([NotNull] RelativeFileInfo fileInfo,
|
||||||
[NotNull] IBeforeCompileContext context,
|
[NotNull] IBeforeCompileContext context)
|
||||||
[NotNull] CSharpParseOptions options)
|
|
||||||
{
|
{
|
||||||
using (var stream = fileInfo.FileInfo.CreateReadStream())
|
using (var stream = fileInfo.FileInfo.CreateReadStream())
|
||||||
{
|
{
|
||||||
|
|
@ -124,7 +125,9 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
|
|
||||||
if (generatedCode != null)
|
if (generatedCode != null)
|
||||||
{
|
{
|
||||||
var syntaxTree = SyntaxTreeGenerator.Generate(generatedCode, fileInfo.FileInfo.PhysicalPath, options);
|
var syntaxTree = SyntaxTreeGenerator.Generate(generatedCode,
|
||||||
|
fileInfo.FileInfo.PhysicalPath,
|
||||||
|
CompilationSettings);
|
||||||
var fullTypeName = results.GetMainClassName(_host, syntaxTree);
|
var fullTypeName = results.GetMainClassName(_host, syntaxTree);
|
||||||
|
|
||||||
if (fullTypeName != null)
|
if (fullTypeName != null)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
"Microsoft.AspNet.Mvc.Common": { "version": "6.0.0-*", "type": "build" },
|
"Microsoft.AspNet.Mvc.Common": { "version": "6.0.0-*", "type": "build" },
|
||||||
"Microsoft.AspNet.Mvc.Core": "6.0.0-*",
|
"Microsoft.AspNet.Mvc.Core": "6.0.0-*",
|
||||||
"Microsoft.AspNet.Mvc.Razor.Host": "6.0.0-*",
|
"Microsoft.AspNet.Mvc.Razor.Host": "6.0.0-*",
|
||||||
"Microsoft.CodeAnalysis.CSharp": "1.0.0-beta2-*"
|
"Microsoft.Framework.Runtime.Roslyn.Common": "1.0.0-*"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
"aspnet50": {
|
"aspnet50": {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ using Microsoft.AspNet.Mvc.Internal;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNet.Mvc.OptionDescriptors;
|
using Microsoft.AspNet.Mvc.OptionDescriptors;
|
||||||
using Microsoft.AspNet.Mvc.Razor;
|
using Microsoft.AspNet.Mvc.Razor;
|
||||||
using Microsoft.AspNet.Mvc.Razor.Compilation;
|
|
||||||
using Microsoft.AspNet.Mvc.Razor.OptionDescriptors;
|
using Microsoft.AspNet.Mvc.Razor.OptionDescriptors;
|
||||||
using Microsoft.AspNet.Mvc.Rendering;
|
using Microsoft.AspNet.Mvc.Rendering;
|
||||||
using Microsoft.AspNet.Mvc.Routing;
|
using Microsoft.AspNet.Mvc.Routing;
|
||||||
|
|
|
||||||
|
|
@ -29,14 +29,17 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
public virtual void BeforeCompile(IBeforeCompileContext context)
|
public virtual void BeforeCompile(IBeforeCompileContext context)
|
||||||
{
|
{
|
||||||
var appEnv = _appServices.GetRequiredService<IApplicationEnvironment>();
|
var applicationEnvironment = _appServices.GetRequiredService<IApplicationEnvironment>();
|
||||||
|
var compilerOptionsProvider = _appServices.GetRequiredService<ICompilerOptionsProvider>();
|
||||||
|
var compilationSettings = compilerOptionsProvider.GetCompilationSettings(applicationEnvironment);
|
||||||
|
|
||||||
var setup = new RazorViewEngineOptionsSetup(appEnv);
|
var setup = new RazorViewEngineOptionsSetup(applicationEnvironment);
|
||||||
var sc = new ServiceCollection();
|
var sc = new ServiceCollection();
|
||||||
sc.ConfigureOptions(setup);
|
sc.ConfigureOptions(setup);
|
||||||
sc.AddMvc();
|
sc.AddMvc();
|
||||||
|
|
||||||
var viewCompiler = new RazorPreCompiler(BuildFallbackServiceProvider(sc, _appServices));
|
var serviceProvider = BuildFallbackServiceProvider(sc, _appServices);
|
||||||
|
var viewCompiler = new RazorPreCompiler(serviceProvider, compilationSettings);
|
||||||
viewCompiler.CompileViews(context);
|
viewCompiler.CompileViews(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.Builder;
|
||||||
|
using Microsoft.AspNet.TestHost;
|
||||||
|
using RazorWebSite;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
|
{
|
||||||
|
// Test to verify compilation options from the application are used to compile
|
||||||
|
// precompiled and dynamically compiled views.
|
||||||
|
public class CompilationOptionsTests
|
||||||
|
{
|
||||||
|
private readonly IServiceProvider _provider = TestHelper.CreateServices(nameof(RazorWebSite));
|
||||||
|
private readonly Action<IApplicationBuilder> _app = new Startup().Configure;
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CompilationOptions_AreUsedByViewsAndPartials()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
#if ASPNET50
|
||||||
|
var expected =
|
||||||
|
@"This method is running from ASPNET50
|
||||||
|
|
||||||
|
This method is only defined in ASPNET50";
|
||||||
|
#elif ASPNETCORE50
|
||||||
|
var expected =
|
||||||
|
@"This method is running from ASPNETCORE50
|
||||||
|
|
||||||
|
This method is only defined in ASPNETCORE50";
|
||||||
|
#endif
|
||||||
|
var server = TestServer.Create(_provider, _app);
|
||||||
|
var client = server.CreateClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var body = await client.GetStringAsync("http://localhost/ViewsConsumingCompilationOptions/");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expected, body.Trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,6 +11,7 @@ using Microsoft.AspNet.Builder;
|
||||||
using Microsoft.AspNet.TestHost;
|
using Microsoft.AspNet.TestHost;
|
||||||
using Microsoft.Framework.DependencyInjection;
|
using Microsoft.Framework.DependencyInjection;
|
||||||
using Microsoft.Framework.Runtime;
|
using Microsoft.Framework.Runtime;
|
||||||
|
using PrecompilationWebSite;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.FunctionalTests
|
namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
|
|
@ -18,8 +19,8 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
public class PrecompilationTest
|
public class PrecompilationTest
|
||||||
{
|
{
|
||||||
private static readonly TimeSpan _cacheDelayInterval = TimeSpan.FromSeconds(2);
|
private static readonly TimeSpan _cacheDelayInterval = TimeSpan.FromSeconds(2);
|
||||||
private readonly IServiceProvider _services = TestHelper.CreateServices("PrecompilationWebSite");
|
private readonly IServiceProvider _services = TestHelper.CreateServices(nameof(PrecompilationWebSite));
|
||||||
private readonly Action<IApplicationBuilder> _app = new PrecompilationWebSite.Startup().Configure;
|
private readonly Action<IApplicationBuilder> _app = new Startup().Configure;
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task PrecompiledView_RendersCorrectly()
|
public async Task PrecompiledView_RendersCorrectly()
|
||||||
|
|
@ -37,7 +38,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
|
|
||||||
// We will render a view that writes the fully qualified name of the Assembly containing the type of
|
// We will render a view that writes the fully qualified name of the Assembly containing the type of
|
||||||
// the view. If the view is precompiled, this assembly will be PrecompilationWebsite.
|
// the view. If the view is precompiled, this assembly will be PrecompilationWebsite.
|
||||||
var assemblyName = typeof(PrecompilationWebSite.Startup).GetTypeInfo().Assembly.GetName().ToString();
|
var assemblyName = typeof(Startup).GetTypeInfo().Assembly.GetName().ToString();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -142,6 +143,30 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task PrecompiledView_UsesCompilationOptionsFromApplication()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var assemblyName = typeof(Startup).GetTypeInfo().Assembly.GetName().ToString();
|
||||||
|
#if ASPNET50
|
||||||
|
var expected =
|
||||||
|
@"Value set inside ASPNET50 " + assemblyName;
|
||||||
|
#elif ASPNETCORE50
|
||||||
|
var expected =
|
||||||
|
@"Value set inside ASPNETCORE50 " + assemblyName;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
var server = TestServer.Create(_services, _app);
|
||||||
|
var client = server.CreateClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.GetAsync("http://localhost/Home/PrecompiledViewsCanConsumeCompilationOptions");
|
||||||
|
var responseContent = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(expected, responseContent.Trim());
|
||||||
|
}
|
||||||
|
|
||||||
private static Task TouchFile(string viewsDir, string file)
|
private static Task TouchFile(string viewsDir, string file)
|
||||||
{
|
{
|
||||||
File.AppendAllText(Path.Combine(viewsDir, file), " ");
|
File.AppendAllText(Path.Combine(viewsDir, file), " ");
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,170 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
using Microsoft.Framework.Runtime;
|
||||||
|
using Moq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Mvc.Razor
|
||||||
|
{
|
||||||
|
public class RoslynCompilationServiceTest
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void Compile_ReturnsUncachedCompilationResultWithCompiledContent()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var content = @"
|
||||||
|
public class MyTestType {}";
|
||||||
|
var applicationEnvironment = GetApplicationEnvironment();
|
||||||
|
var accessor = GetLoadContextAccessor();
|
||||||
|
var libraryManager = GetLibraryManager();
|
||||||
|
|
||||||
|
var compilerOptionsProvider = new Mock<ICompilerOptionsProvider>();
|
||||||
|
compilerOptionsProvider.Setup(p => p.GetCompilerOptions(applicationEnvironment.ApplicationBasePath,
|
||||||
|
applicationEnvironment.RuntimeFramework,
|
||||||
|
applicationEnvironment.Configuration))
|
||||||
|
.Returns(new CompilerOptions());
|
||||||
|
var mvcRazorHost = new Mock<IMvcRazorHost>();
|
||||||
|
mvcRazorHost.SetupGet(m => m.MainClassNamePrefix)
|
||||||
|
.Returns(string.Empty);
|
||||||
|
|
||||||
|
var compilationService = new RoslynCompilationService(applicationEnvironment,
|
||||||
|
accessor,
|
||||||
|
libraryManager,
|
||||||
|
compilerOptionsProvider.Object,
|
||||||
|
mvcRazorHost.Object);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = compilationService.Compile(new TestFileInfo { PhysicalPath = "SomePath" }, content);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
var uncachedResult = Assert.IsType<UncachedCompilationResult>(result);
|
||||||
|
Assert.Equal("MyTestType", result.CompiledType.Name);
|
||||||
|
Assert.Equal(content, result.CompiledContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compile_UsesApplicationsCompilationSettings_ForParsingAndCompilation()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var content = @"
|
||||||
|
#if MY_CUSTOM_DEFINE
|
||||||
|
public class MyCustomDefinedClass {}
|
||||||
|
#else
|
||||||
|
public class MyNonCustomDefinedClass {}
|
||||||
|
#endif
|
||||||
|
";
|
||||||
|
var applicationEnvironment = GetApplicationEnvironment();
|
||||||
|
var accessor = GetLoadContextAccessor();
|
||||||
|
var libraryManager = GetLibraryManager();
|
||||||
|
|
||||||
|
var compilerOptionsProvider = new Mock<ICompilerOptionsProvider>();
|
||||||
|
compilerOptionsProvider.Setup(p => p.GetCompilerOptions(applicationEnvironment.ApplicationBasePath,
|
||||||
|
applicationEnvironment.RuntimeFramework,
|
||||||
|
applicationEnvironment.Configuration))
|
||||||
|
.Returns(new CompilerOptions { Defines = new[] { "MY_CUSTOM_DEFINE" } });
|
||||||
|
var mvcRazorHost = new Mock<IMvcRazorHost>();
|
||||||
|
mvcRazorHost.SetupGet(m => m.MainClassNamePrefix)
|
||||||
|
.Returns("My");
|
||||||
|
|
||||||
|
var compilationService = new RoslynCompilationService(applicationEnvironment,
|
||||||
|
accessor,
|
||||||
|
libraryManager,
|
||||||
|
compilerOptionsProvider.Object,
|
||||||
|
mvcRazorHost.Object);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = compilationService.Compile(new TestFileInfo { PhysicalPath = "SomePath" }, content);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(result.CompiledType);
|
||||||
|
Assert.Equal("MyCustomDefinedClass", result.CompiledType.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Compile_ReturnsSingleTypeThatStartsWithMainClassNamePrefix()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var content = @"
|
||||||
|
public class RazorPrefixType {}
|
||||||
|
public class NotRazorPrefixType {}";
|
||||||
|
var applicationEnvironment = GetApplicationEnvironment();
|
||||||
|
var accessor = GetLoadContextAccessor();
|
||||||
|
var libraryManager = GetLibraryManager();
|
||||||
|
|
||||||
|
var compilerOptionsProvider = new Mock<ICompilerOptionsProvider>();
|
||||||
|
compilerOptionsProvider.Setup(p => p.GetCompilerOptions(applicationEnvironment.ApplicationBasePath,
|
||||||
|
applicationEnvironment.RuntimeFramework,
|
||||||
|
applicationEnvironment.Configuration))
|
||||||
|
.Returns(new CompilerOptions());
|
||||||
|
var mvcRazorHost = new Mock<IMvcRazorHost>();
|
||||||
|
mvcRazorHost.SetupGet(m => m.MainClassNamePrefix)
|
||||||
|
.Returns("RazorPrefix");
|
||||||
|
|
||||||
|
var compilationService = new RoslynCompilationService(applicationEnvironment,
|
||||||
|
accessor,
|
||||||
|
libraryManager,
|
||||||
|
compilerOptionsProvider.Object,
|
||||||
|
mvcRazorHost.Object);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var result = compilationService.Compile(new TestFileInfo { PhysicalPath = "SomePath" }, content);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.NotNull(result.CompiledType);
|
||||||
|
Assert.Equal("RazorPrefixType", result.CompiledType.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ILibraryManager GetLibraryManager()
|
||||||
|
{
|
||||||
|
var fileReference = new Mock<IMetadataFileReference>();
|
||||||
|
fileReference.SetupGet(f => f.Path)
|
||||||
|
.Returns(typeof(string).Assembly.Location);
|
||||||
|
var libraryExport = new Mock<ILibraryExport>();
|
||||||
|
libraryExport.SetupGet(e => e.MetadataReferences)
|
||||||
|
.Returns(new[] { fileReference.Object });
|
||||||
|
libraryExport.SetupGet(e => e.SourceReferences)
|
||||||
|
.Returns(new ISourceReference[0]);
|
||||||
|
|
||||||
|
var libraryManager = new Mock<ILibraryManager>();
|
||||||
|
libraryManager.Setup(l => l.GetAllExports(It.IsAny<string>()))
|
||||||
|
.Returns(libraryExport.Object);
|
||||||
|
return libraryManager.Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IAssemblyLoadContextAccessor GetLoadContextAccessor()
|
||||||
|
{
|
||||||
|
var loadContext = new Mock<IAssemblyLoadContext>();
|
||||||
|
loadContext.Setup(s => s.LoadStream(It.IsAny<Stream>(), It.IsAny<Stream>()))
|
||||||
|
.Returns((Stream stream, Stream pdb) =>
|
||||||
|
{
|
||||||
|
var memoryStream = (MemoryStream)stream;
|
||||||
|
return Assembly.Load(memoryStream.ToArray());
|
||||||
|
});
|
||||||
|
|
||||||
|
var accessor = new Mock<IAssemblyLoadContextAccessor>();
|
||||||
|
accessor.Setup(a => a.GetLoadContext(typeof(RoslynCompilationService).Assembly))
|
||||||
|
.Returns(loadContext.Object);
|
||||||
|
return accessor.Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IApplicationEnvironment GetApplicationEnvironment()
|
||||||
|
{
|
||||||
|
var applicationEnvironment = new Mock<IApplicationEnvironment>();
|
||||||
|
applicationEnvironment.SetupGet(a => a.ApplicationName)
|
||||||
|
.Returns("MyApp");
|
||||||
|
applicationEnvironment.SetupGet(a => a.RuntimeFramework)
|
||||||
|
.Returns(new FrameworkName("ASPNET", new Version(5, 0)));
|
||||||
|
applicationEnvironment.SetupGet(a => a.Configuration)
|
||||||
|
.Returns("Debug");
|
||||||
|
applicationEnvironment.SetupGet(a => a.ApplicationBasePath)
|
||||||
|
.Returns("MyBasePath");
|
||||||
|
|
||||||
|
return applicationEnvironment.Object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,5 +11,10 @@ namespace PrecompilationWebSite.Controllers
|
||||||
{
|
{
|
||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IActionResult PrecompiledViewsCanConsumeCompilationOptions()
|
||||||
|
{
|
||||||
|
return View("~/Views/ViewsConsumingCompilationOptions/Index");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
@{
|
||||||
|
string message =
|
||||||
|
#if ASPNET50
|
||||||
|
"Value set inside ASPNET50 " + GetType().Assembly.FullName;
|
||||||
|
#elif ASPNETCORE50
|
||||||
|
"Value set inside ASPNETCORE50 " + System.Reflection.IntrospectionExtensions.GetTypeInfo(GetType()).Assembly.FullName;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
@message
|
||||||
|
|
@ -12,8 +12,16 @@
|
||||||
"Microsoft.AspNet.StaticFiles": "1.0.0-*"
|
"Microsoft.AspNet.StaticFiles": "1.0.0-*"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
"aspnet50": { },
|
"aspnet50": {
|
||||||
"aspnetcore50": { }
|
"compilationOptions": {
|
||||||
|
"define": [ "CUSTOM_ASPNET50_DEFINE" ]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"aspnetcore50": {
|
||||||
|
"compilationOptions": {
|
||||||
|
"define": [ "CUSTOM_ASPNETCORE50_DEFINE" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"webroot": "wwwroot"
|
"webroot": "wwwroot"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.AspNet.Mvc;
|
||||||
|
|
||||||
|
namespace RazorWebSite.Controllers
|
||||||
|
{
|
||||||
|
// Views returned by this controller use #ifdefs for defines specified in project.json
|
||||||
|
// The intent of this controller is to verify that view compilation uses the app's compilation settings.
|
||||||
|
public class ViewsConsumingCompilationOptionsController : Controller
|
||||||
|
{
|
||||||
|
public ViewResult Index()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
namespace RazorWebSite
|
||||||
|
{
|
||||||
|
public class FrameworkSpecificHelper
|
||||||
|
{
|
||||||
|
public string ExecuteOperation()
|
||||||
|
{
|
||||||
|
#if ASPNET50
|
||||||
|
return "This method is running from ASPNET50";
|
||||||
|
#elif ASPNETCORE50
|
||||||
|
return "This method is running from ASPNETCORE50";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ASPNET50_CUSTOM_DEFINE
|
||||||
|
public string ExecuteAspNet50Operation()
|
||||||
|
{
|
||||||
|
return "This method is only defined in ASPNET50";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ASPNETCORE50_CUSTOM_DEFINE
|
||||||
|
public string ExecuteAspNetCore50Operation()
|
||||||
|
{
|
||||||
|
return "This method is only defined in ASPNETCORE50";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -21,6 +21,7 @@ namespace RazorWebSite
|
||||||
services.AddMvc(configuration);
|
services.AddMvc(configuration);
|
||||||
services.AddTransient<InjectedHelper>();
|
services.AddTransient<InjectedHelper>();
|
||||||
services.AddTransient<TaskReturningService>();
|
services.AddTransient<TaskReturningService>();
|
||||||
|
services.AddTransient<FrameworkSpecificHelper>();
|
||||||
services.Configure<RazorViewEngineOptions>(options =>
|
services.Configure<RazorViewEngineOptions>(options =>
|
||||||
{
|
{
|
||||||
var expander = new LanguageViewLocationExpander(
|
var expander = new LanguageViewLocationExpander(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
@inject FrameworkSpecificHelper MyHelper
|
||||||
|
@MyHelper.ExecuteOperation()
|
||||||
|
@Html.Partial("_Partial")
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
@inject FrameworkSpecificHelper MyHelper
|
||||||
|
@{
|
||||||
|
string value =
|
||||||
|
#if ASPNET50_CUSTOM_DEFINE
|
||||||
|
MyHelper.ExecuteAspNet50Operation();
|
||||||
|
#endif
|
||||||
|
#if ASPNETCORE50_CUSTOM_DEFINE
|
||||||
|
MyHelper.ExecuteAspNetCore50Operation();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
@value
|
||||||
|
|
@ -12,8 +12,16 @@
|
||||||
"Microsoft.AspNet.StaticFiles": "1.0.0-*"
|
"Microsoft.AspNet.StaticFiles": "1.0.0-*"
|
||||||
},
|
},
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
"aspnet50": { },
|
"aspnet50": {
|
||||||
"aspnetcore50": { }
|
"compilationOptions": {
|
||||||
|
"define": [ "ASPNET50_CUSTOM_DEFINE" ]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"aspnetcore50": {
|
||||||
|
"compilationOptions": {
|
||||||
|
"define": [ "ASPNETCORE50_CUSTOM_DEFINE" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"webroot": "wwwroot"
|
"webroot": "wwwroot"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue