Remove ParseOptions and CompilationOptions from RazorViewEngineOptions (#6487)

* Remove ParseOptions and CompilationOptions from RazorViewEngineOptions

Fixes #6009
This commit is contained in:
Pranav K 2017-07-05 14:18:49 -07:00 committed by GitHub
parent 1eb7f9e032
commit 8963b83dd3
11 changed files with 462 additions and 565 deletions

View File

@ -134,14 +134,8 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<MvcViewOptions>, MvcRazorMvcViewOptionsSetup>());
// DependencyContextRazorViewEngineOptionsSetup needs to run after RazorViewEngineOptionsSetup.
// The ordering of the following two lines is important to ensure this behavior.
services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<RazorViewEngineOptions>, RazorViewEngineOptionsSetup>());
services.TryAddEnumerable(
ServiceDescriptor.Transient<
IConfigureOptions<RazorViewEngineOptions>,
DependencyContextRazorViewEngineOptionsSetup>());
services.TryAddSingleton<
IRazorViewEngineFileProviderAccessor,

View File

@ -1,47 +1,167 @@
// Copyright (c) .NET Foundation. 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.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Text;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.DependencyModel;
using DependencyContextCompilationOptions = Microsoft.Extensions.DependencyModel.CompilationOptions;
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
{
public class CSharpCompiler
{
private readonly CSharpCompilationOptions _compilationOptions;
private readonly CSharpParseOptions _parseOptions;
private readonly RazorReferenceManager _referenceManager;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly DebugInformationFormat _pdbFormat = SymbolsUtility.SupportsFullPdbGeneration() ?
DebugInformationFormat.Pdb :
DebugInformationFormat.PortablePdb;
private bool _optionsInitialized;
private CSharpParseOptions _parseOptions;
private CSharpCompilationOptions _compilationOptions;
public CSharpCompiler(RazorReferenceManager manager, IOptions<RazorViewEngineOptions> optionsAccessor)
public CSharpCompiler(RazorReferenceManager manager, IHostingEnvironment hostingEnvironment)
{
_referenceManager = manager;
_compilationOptions = optionsAccessor.Value.CompilationOptions;
_parseOptions = optionsAccessor.Value.ParseOptions;
_referenceManager = manager ?? throw new ArgumentNullException(nameof(manager));
_hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment));
EmitOptions = new EmitOptions(debugInformationFormat: _pdbFormat);
}
public virtual CSharpParseOptions ParseOptions
{
get
{
EnsureOptions();
return _parseOptions;
}
}
public virtual CSharpCompilationOptions CSharpCompilationOptions
{
get
{
EnsureOptions();
return _compilationOptions;
}
}
public EmitOptions EmitOptions { get; }
public SyntaxTree CreateSyntaxTree(SourceText sourceText)
{
return CSharpSyntaxTree.ParseText(
sourceText,
options: _parseOptions);
options: ParseOptions);
}
public CSharpCompilation CreateCompilation(string assemblyName)
{
return CSharpCompilation.Create(
assemblyName,
options: _compilationOptions,
options: CSharpCompilationOptions,
references: _referenceManager.CompilationReferences);
}
// Internal for unit testing.
protected internal virtual DependencyContextCompilationOptions GetDependencyContextCompilationOptions()
{
if (!string.IsNullOrEmpty(_hostingEnvironment.ApplicationName))
{
var applicationAssembly = Assembly.Load(new AssemblyName(_hostingEnvironment.ApplicationName));
var dependencyContext = DependencyContext.Load(applicationAssembly);
if (dependencyContext?.CompilationOptions != null)
{
return dependencyContext.CompilationOptions;
}
}
return DependencyContextCompilationOptions.Default;
}
private void EnsureOptions()
{
if (!_optionsInitialized)
{
var dependencyContextOptions = GetDependencyContextCompilationOptions();
_parseOptions = GetParseOptions(_hostingEnvironment, dependencyContextOptions);
_compilationOptions = GetCompilationOptions(_hostingEnvironment, dependencyContextOptions);
_optionsInitialized = true;
}
}
private static CSharpCompilationOptions GetCompilationOptions(
IHostingEnvironment hostingEnvironment,
DependencyContextCompilationOptions dependencyContextOptions)
{
var csharpCompilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
// Disable 1702 until roslyn turns this off by default
csharpCompilationOptions = csharpCompilationOptions.WithSpecificDiagnosticOptions(
new Dictionary<string, ReportDiagnostic>
{
{"CS1701", ReportDiagnostic.Suppress}, // Binding redirects
{"CS1702", ReportDiagnostic.Suppress},
{"CS1705", ReportDiagnostic.Suppress}
});
if (dependencyContextOptions.AllowUnsafe.HasValue)
{
csharpCompilationOptions = csharpCompilationOptions.WithAllowUnsafe(
dependencyContextOptions.AllowUnsafe.Value);
}
OptimizationLevel optimizationLevel;
if (dependencyContextOptions.Optimize.HasValue)
{
optimizationLevel = dependencyContextOptions.Optimize.Value ?
OptimizationLevel.Release :
OptimizationLevel.Debug;
}
else
{
optimizationLevel = hostingEnvironment.IsDevelopment() ?
OptimizationLevel.Debug :
OptimizationLevel.Release;
}
csharpCompilationOptions = csharpCompilationOptions.WithOptimizationLevel(optimizationLevel);
if (dependencyContextOptions.WarningsAsErrors.HasValue)
{
var reportDiagnostic = dependencyContextOptions.WarningsAsErrors.Value ?
ReportDiagnostic.Error :
ReportDiagnostic.Default;
csharpCompilationOptions = csharpCompilationOptions.WithGeneralDiagnosticOption(reportDiagnostic);
}
return csharpCompilationOptions;
}
private static CSharpParseOptions GetParseOptions(
IHostingEnvironment hostingEnvironment,
DependencyContextCompilationOptions dependencyContextOptions)
{
var configurationSymbol = hostingEnvironment.IsDevelopment() ? "DEBUG" : "RELEASE";
var defines = dependencyContextOptions.Defines.Concat(new[] { configurationSymbol });
var parseOptions = new CSharpParseOptions(preprocessorSymbols: defines);
LanguageVersion languageVersion;
if (!string.IsNullOrEmpty(dependencyContextOptions.LanguageVersion) &&
Enum.TryParse(dependencyContextOptions.LanguageVersion, ignoreCase: true, result: out languageVersion))
{
parseOptions = parseOptions.WithLanguageVersion(languageVersion);
}
return parseOptions;
}
}
}

View File

@ -1,115 +0,0 @@
// Copyright (c) .NET Foundation. 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.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.Extensions.DependencyModel;
using Microsoft.Extensions.Options;
using DependencyContextOptions = Microsoft.Extensions.DependencyModel.CompilationOptions;
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
{
/// <summary>
/// Sets up compilation and parse option default options for <see cref="RazorViewEngineOptions"/> using
/// <see cref="DependencyContext"/>
/// </summary>
public class DependencyContextRazorViewEngineOptionsSetup : IConfigureOptions<RazorViewEngineOptions>
{
private readonly IHostingEnvironment _hostingEnvironment;
/// <summary>
/// Initializes a new instance of <see cref="DependencyContextRazorViewEngineOptionsSetup"/>.
/// </summary>
public DependencyContextRazorViewEngineOptionsSetup(IHostingEnvironment hostingEnvironment)
{
_hostingEnvironment = hostingEnvironment;
}
/// <inheritdoc />
public void Configure(RazorViewEngineOptions options)
{
var compilationOptions = GetCompilationOptions();
SetParseOptions(options, compilationOptions);
SetCompilationOptions(options, compilationOptions);
}
// Internal for unit testing.
protected internal virtual DependencyContextOptions GetCompilationOptions()
{
if (!string.IsNullOrEmpty(_hostingEnvironment.ApplicationName))
{
var applicationAssembly = Assembly.Load(new AssemblyName(_hostingEnvironment.ApplicationName));
var dependencyContext = DependencyContext.Load(applicationAssembly);
if (dependencyContext?.CompilationOptions != null)
{
return dependencyContext.CompilationOptions;
}
}
return DependencyContextOptions.Default;
}
private static void SetCompilationOptions(
RazorViewEngineOptions options,
DependencyContextOptions compilationOptions)
{
var roslynOptions = options.CompilationOptions;
// Disable 1702 until roslyn turns this off by default
roslynOptions = roslynOptions.WithSpecificDiagnosticOptions(
new Dictionary<string, ReportDiagnostic>
{
{"CS1701", ReportDiagnostic.Suppress}, // Binding redirects
{"CS1702", ReportDiagnostic.Suppress},
{"CS1705", ReportDiagnostic.Suppress}
});
if (compilationOptions.AllowUnsafe.HasValue)
{
roslynOptions = roslynOptions.WithAllowUnsafe(compilationOptions.AllowUnsafe.Value);
}
if (compilationOptions.Optimize.HasValue)
{
var optimizationLevel = compilationOptions.Optimize.Value ?
OptimizationLevel.Release :
OptimizationLevel.Debug;
roslynOptions = roslynOptions.WithOptimizationLevel(optimizationLevel);
}
if (compilationOptions.WarningsAsErrors.HasValue)
{
var reportDiagnostic = compilationOptions.WarningsAsErrors.Value ?
ReportDiagnostic.Error :
ReportDiagnostic.Default;
roslynOptions = roslynOptions.WithGeneralDiagnosticOption(reportDiagnostic);
}
options.CompilationOptions = roslynOptions;
}
private static void SetParseOptions(
RazorViewEngineOptions options,
DependencyContextOptions compilationOptions)
{
var parseOptions = options.ParseOptions;
parseOptions = parseOptions.WithPreprocessorSymbols(
parseOptions.PreprocessorSymbolNames.Concat(compilationOptions.Defines));
LanguageVersion languageVersion;
if (!string.IsNullOrEmpty(compilationOptions.LanguageVersion) &&
Enum.TryParse(compilationOptions.LanguageVersion, ignoreCase: true, result: out languageVersion))
{
parseOptions = parseOptions.WithLanguageVersion(languageVersion);
}
options.ParseOptions = parseOptions;
}
}
}

View File

@ -2,9 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using Microsoft.AspNetCore.Hosting;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
@ -22,12 +20,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
/// <param name="hostingEnvironment"><see cref="IHostingEnvironment"/> for the application.</param>
public RazorViewEngineOptionsSetup(IHostingEnvironment hostingEnvironment)
{
if (hostingEnvironment == null)
{
throw new ArgumentNullException(nameof(hostingEnvironment));
}
_hostingEnvironment = hostingEnvironment;
_hostingEnvironment = hostingEnvironment ?? throw new ArgumentNullException(nameof(hostingEnvironment));
}
public void Configure(RazorViewEngineOptions options)
@ -42,24 +35,6 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
options.FileProviders.Add(_hostingEnvironment.ContentRootFileProvider);
}
var compilationOptions = options.CompilationOptions;
string configurationSymbol;
if (_hostingEnvironment.IsDevelopment())
{
configurationSymbol = "DEBUG";
options.CompilationOptions = compilationOptions.WithOptimizationLevel(OptimizationLevel.Debug);
}
else
{
configurationSymbol = "RELEASE";
options.CompilationOptions = compilationOptions.WithOptimizationLevel(OptimizationLevel.Release);
}
var parseOptions = options.ParseOptions;
options.ParseOptions = parseOptions.WithPreprocessorSymbols(
parseOptions.PreprocessorSymbolNames.Concat(new[] { configurationSymbol }));
options.ViewLocationFormats.Add("/Views/{1}/{0}" + RazorViewEngine.ViewExtension);
options.ViewLocationFormats.Add("/Views/Shared/{0}" + RazorViewEngine.ViewExtension);

View File

@ -6,7 +6,6 @@ using System.Collections.Generic;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.Extensions.FileProviders;
namespace Microsoft.AspNetCore.Mvc.Razor
@ -16,16 +15,12 @@ namespace Microsoft.AspNetCore.Mvc.Razor
/// </summary>
public class RazorViewEngineOptions
{
private CSharpParseOptions _parseOptions = new CSharpParseOptions(LanguageVersion.CSharp7);
private CSharpCompilationOptions _compilationOptions =
new CSharpCompilationOptions(CodeAnalysis.OutputKind.DynamicallyLinkedLibrary);
private Action<RoslynCompilationContext> _compilationCallback = c => { };
/// <summary>
/// Gets a <see cref="IList{IViewLocationExpander}"/> used by the <see cref="RazorViewEngine"/>.
/// </summary>
public IList<IViewLocationExpander> ViewLocationExpanders { get; }
= new List<IViewLocationExpander>();
public IList<IViewLocationExpander> ViewLocationExpanders { get; } = new List<IViewLocationExpander>();
/// <summary>
/// Gets the sequence of <see cref="IFileProvider" /> instances used by <see cref="RazorViewEngine"/> to
@ -92,6 +87,34 @@ namespace Microsoft.AspNetCore.Mvc.Razor
/// </remarks>
public IList<string> AreaViewLocationFormats { get; } = new List<string>();
/// <summary>
/// Gets the locations where <see cref="RazorViewEngine"/> will search for views (such as layouts and partials)
/// when searched from the context of rendering a Razor Page.
/// </summary>
/// <remarks>
/// <para>
/// Locations are format strings (see https://msdn.microsoft.com/en-us/library/txafckwd.aspx) which may contain
/// the following format items:
/// </para>
/// <list type="bullet">
/// <item>
/// <description>{0} - View Name</description>
/// </item>
/// <item>
/// <description>{1} - Page Name</description>
/// </item>
/// </list>
/// <para>
/// <see cref="PageViewLocationFormats"/> work in tandem with a view location expander to perform hierarchical
/// path lookups. For instance, given a Page like /Account/Manage/Index using /Pages as the root, the view engine
/// will search for views in the following locations:
///
/// /Pages/Account/Manage/{0}.cshtml
/// /Pages/Account/{0}.cshtml
/// /Pages/{0}.cshtml
/// /Views/Shared/{0}.cshtml
/// </para>
/// </remarks>
public IList<string> PageViewLocationFormats { get; } = new List<string>();
/// <summary>
@ -120,39 +143,5 @@ namespace Microsoft.AspNetCore.Mvc.Razor
_compilationCallback = value;
}
}
/// <summary>
/// Gets or sets the <see cref="CSharpParseOptions"/> options used by Razor view compilation.
/// </summary>
public CSharpParseOptions ParseOptions
{
get => _parseOptions;
set
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
_parseOptions = value;
}
}
/// <summary>
/// Gets or sets the <see cref="CSharpCompilationOptions"/> used by Razor view compilation.
/// </summary>
public CSharpCompilationOptions CompilationOptions
{
get => _compilationOptions;
set
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
_compilationOptions = value;
}
}
}
}

View File

@ -1,27 +1,307 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Text;
using Moq;
using Xunit;
using DependencyContextCompilationOptions = Microsoft.Extensions.DependencyModel.CompilationOptions;
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
{
public class CSharpCompilerTest
{
[Theory]
[InlineData(null)]
[InlineData("")]
public void GetCompilationOptions_ReturnsDefaultOptionsIfApplicationNameIsNullOrEmpty(string name)
{
// Arrange
var hostingEnvironment = Mock.Of<IHostingEnvironment>(e => e.ApplicationName == name);
var referenceManager = Mock.Of<RazorReferenceManager>();
var compiler = new CSharpCompiler(referenceManager, hostingEnvironment);
// Act
var options = compiler.GetDependencyContextCompilationOptions();
// Assert
Assert.Same(DependencyContextCompilationOptions.Default, options);
}
[Fact]
public void GetCompilationOptions_ReturnsDefaultOptionsIfApplicationDoesNotHaveDependencyContext()
{
// Arrange
var hostingEnvironment = new Mock<IHostingEnvironment>();
hostingEnvironment.SetupGet(e => e.ApplicationName)
.Returns(typeof(Controller).GetTypeInfo().Assembly.GetName().Name);
var referenceManager = Mock.Of<RazorReferenceManager>();
var compiler = new CSharpCompiler(referenceManager, hostingEnvironment.Object);
// Act
var options = compiler.GetDependencyContextCompilationOptions();
// Assert
Assert.Same(DependencyContextCompilationOptions.Default, options);
}
[Fact]
public void Constructor_SetsCompilationOptionsFromDependencyContext()
{
// Arrange
var hostingEnvironment = new Mock<IHostingEnvironment>();
hostingEnvironment.SetupGet(e => e.ApplicationName)
.Returns(GetType().GetTypeInfo().Assembly.GetName().Name);
var compiler = new CSharpCompiler(Mock.Of<RazorReferenceManager>(), hostingEnvironment.Object);
// Act & Assert
var parseOptions = compiler.ParseOptions;
Assert.Contains("SOME_TEST_DEFINE", parseOptions.PreprocessorSymbolNames);
}
[Theory]
[InlineData("Development", OptimizationLevel.Debug)]
[InlineData("Staging", OptimizationLevel.Release)]
[InlineData("Production", OptimizationLevel.Release)]
public void Constructor_SetsOptimizationLevelBasedOnEnvironment(
string environment,
OptimizationLevel expected)
{
// Arrange
var options = new RazorViewEngineOptions();
var hostingEnvironment = new Mock<IHostingEnvironment>();
hostingEnvironment.SetupGet(e => e.EnvironmentName)
.Returns(environment);
var compiler = new CSharpCompiler(Mock.Of<RazorReferenceManager>(), hostingEnvironment.Object);
// Act & Assert
var compilationOptions = compiler.CSharpCompilationOptions;
Assert.Equal(expected, compilationOptions.OptimizationLevel);
}
[Theory]
[InlineData("Development", "DEBUG")]
[InlineData("Staging", "RELEASE")]
[InlineData("Production", "RELEASE")]
public void EnsureOptions_SetsPreprocessorSymbols(string environment, string expectedConfiguration)
{
// Arrange
var options = new RazorViewEngineOptions();
var hostingEnvironment = new Mock<IHostingEnvironment>();
hostingEnvironment.SetupGet(e => e.EnvironmentName)
.Returns(environment);
var compiler = new CSharpCompiler(Mock.Of<RazorReferenceManager>(), hostingEnvironment.Object);
// Act & Assert
var parseOptions = compiler.ParseOptions;
Assert.Equal(new[] { expectedConfiguration }, parseOptions.PreprocessorSymbolNames);
}
[Fact]
public void EnsureOptions_ConfiguresDefaultCompilationOptions()
{
// Arrange
var hostingEnvironment = Mock.Of<IHostingEnvironment>(h => h.EnvironmentName == "Development");
var compiler = new CSharpCompiler(Mock.Of<RazorReferenceManager>(), hostingEnvironment);
// Act & Assert
var compilationOptions = compiler.CSharpCompilationOptions;
Assert.False(compilationOptions.AllowUnsafe);
Assert.Equal(ReportDiagnostic.Default, compilationOptions.GeneralDiagnosticOption);
Assert.Equal(OptimizationLevel.Debug, compilationOptions.OptimizationLevel);
Assert.Collection(compilationOptions.SpecificDiagnosticOptions.OrderBy(d => d.Key),
item =>
{
Assert.Equal("CS1701", item.Key);
Assert.Equal(ReportDiagnostic.Suppress, item.Value);
},
item =>
{
Assert.Equal("CS1702", item.Key);
Assert.Equal(ReportDiagnostic.Suppress, item.Value);
},
item =>
{
Assert.Equal("CS1705", item.Key);
Assert.Equal(ReportDiagnostic.Suppress, item.Value);
});
}
[Fact]
public void EnsureOptions_ConfiguresDefaultParseOptions()
{
// Arrange
var hostingEnvironment = Mock.Of<IHostingEnvironment>(h => h.EnvironmentName == "Development");
var compiler = new CSharpCompiler(Mock.Of<RazorReferenceManager>(), hostingEnvironment);
// Act & Assert
var parseOptions = compiler.ParseOptions;
Assert.Equal(LanguageVersion.CSharp7, parseOptions.LanguageVersion);
Assert.Equal(new[] { "DEBUG" }, parseOptions.PreprocessorSymbolNames);
}
[Fact]
public void Constructor_ConfiguresLanguageVersion()
{
// Arrange
var dependencyContextOptions = new DependencyContextCompilationOptions(
new[] { "MyDefine" },
languageVersion: "CSharp7_1",
platform: null,
allowUnsafe: true,
warningsAsErrors: null,
optimize: null,
keyFile: null,
delaySign: null,
publicSign: null,
debugType: null,
emitEntryPoint: null,
generateXmlDocumentation: null);
var referenceManager = Mock.Of<RazorReferenceManager>();
var hostingEnvironment = Mock.Of<IHostingEnvironment>();
var compiler = new TestCSharpCompiler(referenceManager, hostingEnvironment, dependencyContextOptions);
// Act & Assert
var compilationOptions = compiler.ParseOptions;
Assert.Equal(LanguageVersion.CSharp7_1, compilationOptions.LanguageVersion);
}
[Fact]
public void Constructor_ConfiguresAllowUnsafe()
{
// Arrange
var dependencyContextOptions = new DependencyContextCompilationOptions(
new[] { "MyDefine" },
languageVersion: null,
platform: null,
allowUnsafe: true,
warningsAsErrors: null,
optimize: null,
keyFile: null,
delaySign: null,
publicSign: null,
debugType: null,
emitEntryPoint: null,
generateXmlDocumentation: null);
var referenceManager = Mock.Of<RazorReferenceManager>();
var hostingEnvironment = Mock.Of<IHostingEnvironment>();
var compiler = new TestCSharpCompiler(referenceManager, hostingEnvironment, dependencyContextOptions);
// Act & Assert
var compilationOptions = compiler.CSharpCompilationOptions;
Assert.True(compilationOptions.AllowUnsafe);
}
[Fact]
public void Constructor_SetsDiagnosticOption()
{
// Arrange
var dependencyContextOptions = new DependencyContextCompilationOptions(
new[] { "MyDefine" },
languageVersion: null,
platform: null,
allowUnsafe: null,
warningsAsErrors: true,
optimize: null,
keyFile: null,
delaySign: null,
publicSign: null,
debugType: null,
emitEntryPoint: null,
generateXmlDocumentation: null);
var referenceManager = Mock.Of<RazorReferenceManager>();
var hostingEnvironment = Mock.Of<IHostingEnvironment>();
var compiler = new TestCSharpCompiler(referenceManager, hostingEnvironment, dependencyContextOptions);
// Act & Assert
var compilationOptions = compiler.CSharpCompilationOptions;
Assert.Equal(ReportDiagnostic.Error, compilationOptions.GeneralDiagnosticOption);
}
[Fact]
public void Constructor_SetsOptimizationLevel()
{
// Arrange
var dependencyContextOptions = new DependencyContextCompilationOptions(
new[] { "MyDefine" },
languageVersion: null,
platform: null,
allowUnsafe: null,
warningsAsErrors: null,
optimize: true,
keyFile: null,
delaySign: null,
publicSign: null,
debugType: null,
emitEntryPoint: null,
generateXmlDocumentation: null);
var referenceManager = Mock.Of<RazorReferenceManager>();
var hostingEnvironment = Mock.Of<IHostingEnvironment>();
var compiler = new TestCSharpCompiler(referenceManager, hostingEnvironment, dependencyContextOptions);
// Act & Assert
var compilationOptions = compiler.CSharpCompilationOptions;
Assert.Equal(OptimizationLevel.Release, compilationOptions.OptimizationLevel);
}
[Fact]
public void Constructor_SetsDefines()
{
// Arrange
var dependencyContextOptions = new DependencyContextCompilationOptions(
new[] { "MyDefine" },
languageVersion: null,
platform: null,
allowUnsafe: null,
warningsAsErrors: null,
optimize: true,
keyFile: null,
delaySign: null,
publicSign: null,
debugType: null,
emitEntryPoint: null,
generateXmlDocumentation: null);
var referenceManager = Mock.Of<RazorReferenceManager>();
var hostingEnvironment = Mock.Of<IHostingEnvironment>();
var compiler = new TestCSharpCompiler(referenceManager, hostingEnvironment, dependencyContextOptions);
// Act & Assert
var parseOptions = compiler.ParseOptions;
Assert.Equal(new[] { "MyDefine", "RELEASE" }, parseOptions.PreprocessorSymbolNames);
}
[Fact]
public void Compile_UsesApplicationsCompilationSettings_ForParsingAndCompilation()
{
// Arrange
var content = "public class Test {}";
var define = "MY_CUSTOM_DEFINE";
var options = new TestOptionsManager<RazorViewEngineOptions>();
options.Value.ParseOptions = options.Value.ParseOptions.WithPreprocessorSymbols(define);
var razorReferenceManager = new DefaultRazorReferenceManager(GetApplicationPartManager(), options);
var compiler = new CSharpCompiler(razorReferenceManager, options);
var dependencyContextOptions = new DependencyContextCompilationOptions(
new[] { define },
languageVersion: null,
platform: null,
allowUnsafe: null,
warningsAsErrors: null,
optimize: true,
keyFile: null,
delaySign: null,
publicSign: null,
debugType: null,
emitEntryPoint: null,
generateXmlDocumentation: null);
var referenceManager = Mock.Of<RazorReferenceManager>();
var hostingEnvironment = Mock.Of<IHostingEnvironment>();
var compiler = new TestCSharpCompiler(referenceManager, hostingEnvironment, dependencyContextOptions);
// Act
var syntaxTree = compiler.CreateSyntaxTree(SourceText.From(content));
@ -30,14 +310,21 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
Assert.Contains(define, syntaxTree.Options.PreprocessorSymbolNames);
}
private static ApplicationPartManager GetApplicationPartManager()
private class TestCSharpCompiler : CSharpCompiler
{
var applicationPartManager = new ApplicationPartManager();
var assembly = typeof(CSharpCompilerTest).GetTypeInfo().Assembly;
applicationPartManager.ApplicationParts.Add(new AssemblyPart(assembly));
applicationPartManager.FeatureProviders.Add(new MetadataReferenceFeatureProvider());
private readonly DependencyContextCompilationOptions _options;
return applicationPartManager;
public TestCSharpCompiler(
RazorReferenceManager referenceManager,
IHostingEnvironment hostingEnvironment,
DependencyContextCompilationOptions options)
: base(referenceManager, hostingEnvironment)
{
_options = options;
}
protected internal override DependencyContextCompilationOptions GetDependencyContextCompilationOptions()
=> _options;
}
}
}

View File

@ -1,303 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Moq;
using Xunit;
using DependencyContextOptions = Microsoft.Extensions.DependencyModel.CompilationOptions;
namespace Microsoft.AspNetCore.Mvc.Razor.Internal
{
public class DependencyContextRazorViewEngineOptionsSetupTest
{
[Theory]
[InlineData(null)]
[InlineData("")]
public void GetCompilationOptions_ReturnsDefaultOptionsIfApplicationNameIsNullOrEmpty(string name)
{
// Arrange
var hostingEnvironment = new Mock<IHostingEnvironment>();
hostingEnvironment.SetupGet(e => e.ApplicationName)
.Returns(name);
var setup = new TestableDependencyContextOptionsSetup(hostingEnvironment.Object);
// Act
var options = setup.GetCompilationOptionsPublic();
// Assert
Assert.Same(DependencyContextOptions.Default, options);
}
[Fact]
public void GetCompilationOptions_ReturnsDefaultOptionsIfApplicationDoesNotHaveDependencyContext()
{
// Arrange
var hostingEnvironment = new Mock<IHostingEnvironment>();
hostingEnvironment.SetupGet(e => e.ApplicationName)
.Returns(typeof(Controller).GetTypeInfo().Assembly.GetName().Name);
var setup = new TestableDependencyContextOptionsSetup(hostingEnvironment.Object);
// Act
var options = setup.GetCompilationOptionsPublic();
// Assert
Assert.Same(DependencyContextOptions.Default, options);
}
[Fact]
public void GetCompilationOptions_ReturnsCompilationOptionsFromDependencyContext()
{
// Arrange
var hostingEnvironment = new Mock<IHostingEnvironment>();
hostingEnvironment.SetupGet(e => e.ApplicationName)
.Returns(GetType().GetTypeInfo().Assembly.GetName().Name);
var setup = new TestableDependencyContextOptionsSetup(hostingEnvironment.Object);
// Act
var options = setup.GetCompilationOptionsPublic();
// Assert
Assert.Contains("SOME_TEST_DEFINE", options.Defines);
}
[Fact]
public void Configure_UsesDefaultCompilationOptions()
{
// Arrange
var hostingEnvironment = new Mock<IHostingEnvironment>();
var setup = new DependencyContextRazorViewEngineOptionsSetup(hostingEnvironment.Object);
var options = new RazorViewEngineOptions();
// Act
setup.Configure(options);
// Assert
var compilationOptions = options.CompilationOptions;
var parseOptions = options.ParseOptions;
Assert.False(compilationOptions.AllowUnsafe);
Assert.Equal(ReportDiagnostic.Default, compilationOptions.GeneralDiagnosticOption);
Assert.Equal(OptimizationLevel.Debug, compilationOptions.OptimizationLevel);
Assert.Collection(compilationOptions.SpecificDiagnosticOptions.OrderBy(d => d.Key),
item =>
{
Assert.Equal("CS1701", item.Key);
Assert.Equal(ReportDiagnostic.Suppress, item.Value);
},
item =>
{
Assert.Equal("CS1702", item.Key);
Assert.Equal(ReportDiagnostic.Suppress, item.Value);
},
item =>
{
Assert.Equal("CS1705", item.Key);
Assert.Equal(ReportDiagnostic.Suppress, item.Value);
});
Assert.Empty(parseOptions.PreprocessorSymbolNames);
Assert.Equal(LanguageVersion.CSharp7, parseOptions.LanguageVersion);
}
[Fact]
public void Configure_SetsAllowUnsafe()
{
// Arrange
var dependencyContextOptions = new DependencyContextOptions(
new[] { "MyDefine" },
languageVersion: null,
platform: null,
allowUnsafe: true,
warningsAsErrors: null,
optimize: null,
keyFile: null,
delaySign: null,
publicSign: null,
debugType: null,
emitEntryPoint: null,
generateXmlDocumentation: null);
var setup = new TestableDependencyContextOptionsSetup(dependencyContextOptions);
var options = new RazorViewEngineOptions();
// Act
setup.Configure(options);
// Assert
Assert.True(options.CompilationOptions.AllowUnsafe);
Assert.Equal(ReportDiagnostic.Default, options.CompilationOptions.GeneralDiagnosticOption);
Assert.Equal(OptimizationLevel.Debug, options.CompilationOptions.OptimizationLevel);
}
[Fact]
public void Configure_SetsDiagnosticOption()
{
// Arrange
var dependencyContextOptions = new DependencyContextOptions(
new[] { "MyDefine" },
languageVersion: null,
platform: null,
allowUnsafe: null,
warningsAsErrors: true,
optimize: null,
keyFile: null,
delaySign: null,
publicSign: null,
debugType: null,
emitEntryPoint: null,
generateXmlDocumentation: null);
var setup = new TestableDependencyContextOptionsSetup(dependencyContextOptions);
var options = new RazorViewEngineOptions();
// Act
setup.Configure(options);
// Assert
Assert.False(options.CompilationOptions.AllowUnsafe);
Assert.Equal(ReportDiagnostic.Error, options.CompilationOptions.GeneralDiagnosticOption);
Assert.Equal(OptimizationLevel.Debug, options.CompilationOptions.OptimizationLevel);
}
[Fact]
public void Configure_SetsOptimizationLevel()
{
// Arrange
var dependencyContextOptions = new DependencyContextOptions(
new[] { "MyDefine" },
languageVersion: null,
platform: null,
allowUnsafe: null,
warningsAsErrors: null,
optimize: true,
keyFile: null,
delaySign: null,
publicSign: null,
debugType: null,
emitEntryPoint: null,
generateXmlDocumentation: null);
var setup = new TestableDependencyContextOptionsSetup(dependencyContextOptions);
var options = new RazorViewEngineOptions();
// Act
setup.Configure(options);
// Assert
Assert.False(options.CompilationOptions.AllowUnsafe);
Assert.Equal(ReportDiagnostic.Default, options.CompilationOptions.GeneralDiagnosticOption);
Assert.Equal(OptimizationLevel.Release, options.CompilationOptions.OptimizationLevel);
}
[Fact]
public void Configure_SetsLanguageVersion()
{
// Arrange
var dependencyContextOptions = new DependencyContextOptions(
new[] { "MyDefine" },
languageVersion: "csharp4",
platform: null,
allowUnsafe: null,
warningsAsErrors: null,
optimize: true,
keyFile: null,
delaySign: null,
publicSign: null,
debugType: null,
emitEntryPoint: null,
generateXmlDocumentation: null);
var setup = new TestableDependencyContextOptionsSetup(dependencyContextOptions);
var options = new RazorViewEngineOptions();
// Act
setup.Configure(options);
// Assert
Assert.Equal(LanguageVersion.CSharp4, options.ParseOptions.LanguageVersion);
}
[Fact]
public void Configure_SetsDefines()
{
// Arrange
var dependencyContextOptions = new DependencyContextOptions(
new[] { "MyDefine" },
languageVersion: "csharp4",
platform: null,
allowUnsafe: null,
warningsAsErrors: null,
optimize: true,
keyFile: null,
delaySign: null,
publicSign: null,
debugType: null,
emitEntryPoint: null,
generateXmlDocumentation: null);
var setup = new TestableDependencyContextOptionsSetup(dependencyContextOptions);
var options = new RazorViewEngineOptions();
// Act
setup.Configure(options);
// Assert
Assert.Equal(new[] { "MyDefine" }, options.ParseOptions.PreprocessorSymbolNames);
}
[Fact]
public void ConfigureAfterRazorViewEngineOptionsSetupIsExecuted_CorrectlySetsUpOptimizationLevel()
{
// Arrange
var dependencyContextOptions = new DependencyContextOptions(
new[] { "MyDefine" },
languageVersion: null,
platform: null,
allowUnsafe: null,
warningsAsErrors: null,
optimize: true,
keyFile: null,
delaySign: null,
publicSign: null,
debugType: null,
emitEntryPoint: null,
generateXmlDocumentation: null);
var dependencyContextSetup = new TestableDependencyContextOptionsSetup(dependencyContextOptions);
var options = new RazorViewEngineOptions();
var hostingEnvironment = new Mock<IHostingEnvironment>();
hostingEnvironment.SetupGet(e => e.EnvironmentName)
.Returns("Development");
#pragma warning disable 0618
var viewEngineSetup = new RazorViewEngineOptionsSetup(hostingEnvironment.Object);
#pragma warning restore 0618
// Act
viewEngineSetup.Configure(options);
dependencyContextSetup.Configure(options);
// Assert
Assert.Equal(OptimizationLevel.Release, options.CompilationOptions.OptimizationLevel);
}
private class TestableDependencyContextOptionsSetup : DependencyContextRazorViewEngineOptionsSetup
{
private readonly DependencyContextOptions _options;
public TestableDependencyContextOptionsSetup(IHostingEnvironment hostingEnvironment)
: base(hostingEnvironment)
{
}
public TestableDependencyContextOptionsSetup(DependencyContextOptions options)
: base(Mock.Of<IHostingEnvironment>())
{
_options = options;
}
protected internal override DependencyContextOptions GetCompilationOptions()
{
return _options ?? base.GetCompilationOptions();
}
public DependencyContextOptions GetCompilationOptionsPublic() => base.GetCompilationOptions();
}
}
}

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.Extensions.FileProviders;
@ -35,7 +36,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
RazorEngine.Create(),
new FileProviderRazorProject(accessor)),
accessor,
new CSharpCompiler(referenceManager, options),
new CSharpCompiler(referenceManager, Mock.Of<IHostingEnvironment>()),
options,
NullLoggerFactory.Instance);

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Mvc.Razor.Compilation;
using Microsoft.AspNetCore.Razor.Language;
@ -554,7 +555,7 @@ this should fail";
var viewCompiler = new TestRazorViewCompiler(
fileProvider,
templateEngine,
new CSharpCompiler(referenceManager, options),
new CSharpCompiler(referenceManager, Mock.Of<IHostingEnvironment>()),
compilationCallback,
precompiledViews);
return viewCompiler;

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Hosting;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.FileProviders;
using Moq;
using Xunit;
@ -20,11 +19,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
var hostingEnv = new Mock<IHostingEnvironment>();
hostingEnv.SetupGet(e => e.ContentRootFileProvider)
.Returns(expected);
hostingEnv.SetupGet(e => e.EnvironmentName)
.Returns("Development");
#pragma warning disable 0618
var optionsSetup = new RazorViewEngineOptionsSetup(hostingEnv.Object);
#pragma warning restore 0618
// Act
optionsSetup.Configure(options);
@ -33,51 +28,5 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
var fileProvider = Assert.Single(options.FileProviders);
Assert.Same(expected, fileProvider);
}
[Theory]
[InlineData("Development", "DEBUG")]
[InlineData("Staging", "RELEASE")]
[InlineData("Production", "RELEASE")]
public void RazorViewEngineOptionsSetup_SetsPreprocessorSymbols(string environment, string expectedConfiguration)
{
// Arrange
var options = new RazorViewEngineOptions();
var hostingEnv = new Mock<IHostingEnvironment>();
hostingEnv.SetupGet(e => e.EnvironmentName)
.Returns(environment);
#pragma warning disable 0618
var optionsSetup = new RazorViewEngineOptionsSetup(hostingEnv.Object);
#pragma warning restore 0618
// Act
optionsSetup.Configure(options);
// Assert
Assert.Equal(new[] { expectedConfiguration }, options.ParseOptions.PreprocessorSymbolNames);
}
[Theory]
[InlineData("Development", OptimizationLevel.Debug)]
[InlineData("Staging", OptimizationLevel.Release)]
[InlineData("Production", OptimizationLevel.Release)]
public void RazorViewEngineOptionsSetup_SetsOptimizationLevel(
string environment,
OptimizationLevel expectedOptimizationLevel)
{
// Arrange
var options = new RazorViewEngineOptions();
var hostingEnv = new Mock<IHostingEnvironment>();
hostingEnv.SetupGet(e => e.EnvironmentName)
.Returns(environment);
#pragma warning disable 0618
var optionsSetup = new RazorViewEngineOptionsSetup(hostingEnv.Object);
#pragma warning restore 0618
// Act
optionsSetup.Configure(options);
// Assert
Assert.Equal(expectedOptimizationLevel, options.CompilationOptions.OptimizationLevel);
}
}
}
}

View File

@ -362,7 +362,6 @@ namespace Microsoft.AspNetCore.Mvc
new[]
{
typeof(RazorViewEngineOptionsSetup),
typeof(DependencyContextRazorViewEngineOptionsSetup),
typeof(RazorPagesRazorViewEngineOptionsSetup),
}
},