Adding support for flowing compilation settings to views

Fixes #871
This commit is contained in:
Pranav K 2014-12-04 19:18:26 -08:00
parent 62b9db93b6
commit 110ee28e3e
21 changed files with 420 additions and 62 deletions

View File

@ -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);
}
}
}

View File

@ -15,7 +15,7 @@ using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.Framework.Runtime;
namespace Microsoft.AspNet.Mvc.Razor.Compilation
namespace Microsoft.AspNet.Mvc.Razor
{
/// <summary>
/// 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 IApplicationEnvironment _environment;
private readonly IAssemblyLoadContext _loader;
private readonly ICompilerOptionsProvider _compilerOptionsProvider;
private readonly Lazy<List<MetadataReference>> _applicationReferences;
@ -44,12 +45,14 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
public RoslynCompilationService(IApplicationEnvironment environment,
IAssemblyLoadContextAccessor loaderAccessor,
ILibraryManager libraryManager,
ICompilerOptionsProvider compilerOptionsProvider,
IMvcRazorHost host)
{
_environment = environment;
_loader = loaderAccessor.GetLoadContext(typeof(RoslynCompilationService).GetTypeInfo().Assembly);
_libraryManager = libraryManager;
_applicationReferences = new Lazy<List<MetadataReference>>(GetApplicationReferences);
_compilerOptionsProvider = compilerOptionsProvider;
_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.
// This prevents files that exist in a non-physical file system from being debugged.
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 assemblyName = Path.GetRandomFileName();
var compilationOptions = compilationSettings.CompilationOptions
.WithOutputKind(OutputKind.DynamicallyLinkedLibrary);
var compilation = CSharpCompilation.Create(assemblyName,
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary),
syntaxTrees: syntaxTrees,
options: compilationOptions,
syntaxTrees: new[] { syntaxTree },
references: references);
using (var ms = new MemoryStream())
@ -115,7 +122,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
.First(t => t.Name.
StartsWith(_classPrefix, StringComparison.Ordinal));
return UncachedCompilationResult.Successful(type);
return UncachedCompilationResult.Successful(type, compilationContent);
}
}
}

View File

@ -5,48 +5,29 @@ using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
using Microsoft.Framework.Runtime.Roslyn;
namespace Microsoft.AspNet.Mvc.Razor
{
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,
[NotNull] string path,
[NotNull] CSharpParseOptions options)
{
return GenerateCore(text, path, options);
}
public static SyntaxTree GenerateCore([NotNull] string text,
[NotNull] string path,
[NotNull] CSharpParseOptions options)
[NotNull] CompilationSettings compilationSettings)
{
var sourceText = SourceText.From(text, Encoding.UTF8);
var syntaxTree = CSharpSyntaxTree.ParseText(sourceText,
path: path,
options: options);
options: GetParseOptions(compilationSettings));
return syntaxTree;
}
public static CSharpParseOptions GetParseOptions(CSharpCompilation compilation)
public static CSharpParseOptions GetParseOptions(CompilationSettings compilationSettings)
{
return CSharpParseOptions.Default
.WithLanguageVersion(compilation.LanguageVersion);
return new CSharpParseOptions(
languageVersion: compilationSettings.LanguageVersion,
preprocessorSymbols: compilationSettings.Defines.AsImmutable());
}
}
}

View File

@ -4,7 +4,7 @@
using System.Collections.Generic;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.Framework.Runtime.Roslyn;
namespace Microsoft.AspNet.Mvc.Razor
{
@ -13,13 +13,13 @@ namespace Microsoft.AspNet.Mvc.Razor
private string _fileFormat;
protected IReadOnlyList<RazorFileInfo> FileInfos { get; private set; }
protected CSharpParseOptions Options { get; private set; }
protected CompilationSettings CompilationSettings { get; }
public RazorFileInfoCollectionGenerator([NotNull] IReadOnlyList<RazorFileInfo> fileInfos,
[NotNull] CSharpParseOptions options)
[NotNull] CompilationSettings compilationSettings)
{
FileInfos = fileInfos;
Options = options;
CompilationSettings = compilationSettings;
}
public virtual SyntaxTree GenerateCollection()
@ -38,7 +38,7 @@ namespace Microsoft.AspNet.Mvc.Razor
var sourceCode = builder.ToString();
var syntaxTree = SyntaxTreeGenerator.Generate(sourceCode,
"__AUTO__GeneratedViewsCollection.cs",
Options);
CompilationSettings);
return syntaxTree;
}

View File

@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.CSharp;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.OptionsModel;
using Microsoft.Framework.Runtime;
using Microsoft.Framework.Runtime.Roslyn;
namespace Microsoft.AspNet.Mvc.Razor
{
@ -19,24 +20,28 @@ namespace Microsoft.AspNet.Mvc.Razor
private readonly IFileSystem _fileSystem;
private readonly IMvcRazorHost _host;
public RazorPreCompiler([NotNull] IServiceProvider designTimeServiceProvider) :
public RazorPreCompiler([NotNull] IServiceProvider designTimeServiceProvider,
[NotNull] CompilationSettings compilationSettings) :
this(designTimeServiceProvider,
designTimeServiceProvider.GetRequiredService<IMvcRazorHost>(),
designTimeServiceProvider.GetRequiredService<IOptions<RazorViewEngineOptions>>())
designTimeServiceProvider.GetRequiredService<IOptions<RazorViewEngineOptions>>(),
compilationSettings)
{
}
public RazorPreCompiler([NotNull] IServiceProvider designTimeServiceProvider,
[NotNull] IMvcRazorHost host,
[NotNull] IOptions<RazorViewEngineOptions> optionsAccessor)
[NotNull] IOptions<RazorViewEngineOptions> optionsAccessor,
[NotNull] CompilationSettings compilationSettings)
{
_serviceProvider = designTimeServiceProvider;
_host = host;
var appEnv = _serviceProvider.GetRequiredService<IApplicationEnvironment>();
_fileSystem = optionsAccessor.Options.FileSystem;
CompilationSettings = compilationSettings;
}
protected CompilationSettings CompilationSettings { get; }
protected virtual string FileExtension { get; } = ".cshtml";
public virtual void CompileViews([NotNull] IBeforeCompileContext context)
@ -47,7 +52,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{
var collectionGenerator = new RazorFileInfoCollectionGenerator(
descriptors,
SyntaxTreeGenerator.GetParseOptions(context.CSharpCompilation));
CompilationSettings);
var tree = collectionGenerator.GenerateCollection();
context.CSharpCompilation = context.CSharpCompilation.AddSyntaxTrees(tree);
@ -57,14 +62,11 @@ namespace Microsoft.AspNet.Mvc.Razor
protected virtual IReadOnlyList<RazorFileInfo> CreateCompilationDescriptors(
[NotNull] IBeforeCompileContext context)
{
var options = SyntaxTreeGenerator.GetParseOptions(context.CSharpCompilation);
var list = new List<RazorFileInfo>();
foreach (var info in GetFileInfosRecursive(string.Empty))
{
var descriptor = ParseView(info,
context,
options);
var descriptor = ParseView(info, context);
if (descriptor != null)
{
@ -107,8 +109,7 @@ namespace Microsoft.AspNet.Mvc.Razor
}
protected virtual RazorFileInfo ParseView([NotNull] RelativeFileInfo fileInfo,
[NotNull] IBeforeCompileContext context,
[NotNull] CSharpParseOptions options)
[NotNull] IBeforeCompileContext context)
{
using (var stream = fileInfo.FileInfo.CreateReadStream())
{
@ -124,7 +125,9 @@ namespace Microsoft.AspNet.Mvc.Razor
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);
if (fullTypeName != null)

View File

@ -8,7 +8,7 @@
"Microsoft.AspNet.Mvc.Common": { "version": "6.0.0-*", "type": "build" },
"Microsoft.AspNet.Mvc.Core": "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": {
"aspnet50": {

View File

@ -9,7 +9,6 @@ using Microsoft.AspNet.Mvc.Internal;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.OptionDescriptors;
using Microsoft.AspNet.Mvc.Razor;
using Microsoft.AspNet.Mvc.Razor.Compilation;
using Microsoft.AspNet.Mvc.Razor.OptionDescriptors;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;

View File

@ -29,14 +29,17 @@ namespace Microsoft.AspNet.Mvc
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();
sc.ConfigureOptions(setup);
sc.AddMvc();
var viewCompiler = new RazorPreCompiler(BuildFallbackServiceProvider(sc, _appServices));
var serviceProvider = BuildFallbackServiceProvider(sc, _appServices);
var viewCompiler = new RazorPreCompiler(serviceProvider, compilationSettings);
viewCompiler.CompileViews(context);
}

View File

@ -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());
}
}
}

View File

@ -11,6 +11,7 @@ using Microsoft.AspNet.Builder;
using Microsoft.AspNet.TestHost;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Runtime;
using PrecompilationWebSite;
using Xunit;
namespace Microsoft.AspNet.Mvc.FunctionalTests
@ -18,8 +19,8 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
public class PrecompilationTest
{
private static readonly TimeSpan _cacheDelayInterval = TimeSpan.FromSeconds(2);
private readonly IServiceProvider _services = TestHelper.CreateServices("PrecompilationWebSite");
private readonly Action<IApplicationBuilder> _app = new PrecompilationWebSite.Startup().Configure;
private readonly IServiceProvider _services = TestHelper.CreateServices(nameof(PrecompilationWebSite));
private readonly Action<IApplicationBuilder> _app = new Startup().Configure;
[Fact]
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
// 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
{
@ -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)
{
File.AppendAllText(Path.Combine(viewsDir, file), " ");

View 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;
}
}
}

View File

@ -11,5 +11,10 @@ namespace PrecompilationWebSite.Controllers
{
return View();
}
public IActionResult PrecompiledViewsCanConsumeCompilationOptions()
{
return View("~/Views/ViewsConsumingCompilationOptions/Index");
}
}
}

View File

@ -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

View File

@ -12,8 +12,16 @@
"Microsoft.AspNet.StaticFiles": "1.0.0-*"
},
"frameworks": {
"aspnet50": { },
"aspnetcore50": { }
"aspnet50": {
"compilationOptions": {
"define": [ "CUSTOM_ASPNET50_DEFINE" ]
}
},
"aspnetcore50": {
"compilationOptions": {
"define": [ "CUSTOM_ASPNETCORE50_DEFINE" ]
}
}
},
"webroot": "wwwroot"
}

View File

@ -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();
}
}
}

View File

@ -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
}
}

View File

@ -21,6 +21,7 @@ namespace RazorWebSite
services.AddMvc(configuration);
services.AddTransient<InjectedHelper>();
services.AddTransient<TaskReturningService>();
services.AddTransient<FrameworkSpecificHelper>();
services.Configure<RazorViewEngineOptions>(options =>
{
var expander = new LanguageViewLocationExpander(

View File

@ -0,0 +1,3 @@
@inject FrameworkSpecificHelper MyHelper
@MyHelper.ExecuteOperation()
@Html.Partial("_Partial")

View File

@ -0,0 +1,11 @@
@inject FrameworkSpecificHelper MyHelper
@{
string value =
#if ASPNET50_CUSTOM_DEFINE
MyHelper.ExecuteAspNet50Operation();
#endif
#if ASPNETCORE50_CUSTOM_DEFINE
MyHelper.ExecuteAspNetCore50Operation();
#endif
}
@value

View File

@ -12,8 +12,16 @@
"Microsoft.AspNet.StaticFiles": "1.0.0-*"
},
"frameworks": {
"aspnet50": { },
"aspnetcore50": { }
"aspnet50": {
"compilationOptions": {
"define": [ "ASPNET50_CUSTOM_DEFINE" ]
}
},
"aspnetcore50": {
"compilationOptions": {
"define": [ "ASPNETCORE50_CUSTOM_DEFINE" ]
}
}
},
"webroot": "wwwroot"
}