diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs b/src/Microsoft.AspNetCore.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs index 4342741b67..0ea907a2ce 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs @@ -134,14 +134,8 @@ internal static void AddRazorViewEngineServices(IServiceCollection services) services.TryAddEnumerable( ServiceDescriptor.Transient, MvcRazorMvcViewOptionsSetup>()); - // DependencyContextRazorViewEngineOptionsSetup needs to run after RazorViewEngineOptionsSetup. - // The ordering of the following two lines is important to ensure this behavior. services.TryAddEnumerable( ServiceDescriptor.Transient, RazorViewEngineOptionsSetup>()); - services.TryAddEnumerable( - ServiceDescriptor.Transient< - IConfigureOptions, - DependencyContextRazorViewEngineOptionsSetup>()); services.TryAddSingleton< IRazorViewEngineFileProviderAccessor, diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/CSharpCompiler.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/CSharpCompiler.cs index b611cc8964..d43b7868cd 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/CSharpCompiler.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/CSharpCompiler.cs @@ -1,47 +1,146 @@ // 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 DebugInformationFormat _pdbFormat = SymbolsUtility.SupportsFullPdbGeneration() ? DebugInformationFormat.Pdb : DebugInformationFormat.PortablePdb; - public CSharpCompiler(RazorReferenceManager manager, IOptions optionsAccessor) + public CSharpCompiler(RazorReferenceManager manager, IHostingEnvironment hostingEnvironment) + : this(manager, hostingEnvironment, GetDependencyContextCompilationOptions(hostingEnvironment)) { - _referenceManager = manager; - _compilationOptions = optionsAccessor.Value.CompilationOptions; - _parseOptions = optionsAccessor.Value.ParseOptions; + } + + internal CSharpCompiler( + RazorReferenceManager manager, + IHostingEnvironment hostingEnvironment, + DependencyContextCompilationOptions dependencyContextOptions) + { + _referenceManager = manager ?? throw new ArgumentNullException(nameof(manager)); + if (hostingEnvironment == null) + { + throw new ArgumentNullException(nameof(hostingEnvironment)); + } + + ParseOptions = GetParseOptions(hostingEnvironment, dependencyContextOptions); + CSharpCompilationOptions = GetCompilationOptions(hostingEnvironment, dependencyContextOptions); EmitOptions = new EmitOptions(debugInformationFormat: _pdbFormat); } + public CSharpParseOptions ParseOptions { get; } + + public CSharpCompilationOptions CSharpCompilationOptions { get; } + public EmitOptions EmitOptions { get; } + 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 + { + {"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( + LanguageVersion.CSharp7_1, + preprocessorSymbols: defines); + + return parseOptions; + } + 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. + internal static DependencyContextCompilationOptions GetDependencyContextCompilationOptions( + IHostingEnvironment hostingEnvironment) + { + 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; + } } } diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/DependencyContextRazorViewEngineOptionsSetup.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/DependencyContextRazorViewEngineOptionsSetup.cs deleted file mode 100644 index 41913d8173..0000000000 --- a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/DependencyContextRazorViewEngineOptionsSetup.cs +++ /dev/null @@ -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 -{ - /// - /// Sets up compilation and parse option default options for using - /// - /// - public class DependencyContextRazorViewEngineOptionsSetup : IConfigureOptions - { - private readonly IHostingEnvironment _hostingEnvironment; - - /// - /// Initializes a new instance of . - /// - public DependencyContextRazorViewEngineOptionsSetup(IHostingEnvironment hostingEnvironment) - { - _hostingEnvironment = hostingEnvironment; - } - - /// - 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 - { - {"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; - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorViewEngineOptionsSetup.cs b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorViewEngineOptionsSetup.cs index 593db1b7b9..e8c49113ba 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorViewEngineOptionsSetup.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/Internal/RazorViewEngineOptionsSetup.cs @@ -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 @@ public class RazorViewEngineOptionsSetup : IConfigureOptions for the application. 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 @@ public void Configure(RazorViewEngineOptions options) 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); diff --git a/src/Microsoft.AspNetCore.Mvc.Razor/RazorViewEngineOptions.cs b/src/Microsoft.AspNetCore.Mvc.Razor/RazorViewEngineOptions.cs index 07c9a36b73..6f5ed745bb 100644 --- a/src/Microsoft.AspNetCore.Mvc.Razor/RazorViewEngineOptions.cs +++ b/src/Microsoft.AspNetCore.Mvc.Razor/RazorViewEngineOptions.cs @@ -6,7 +6,6 @@ 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 /// public class RazorViewEngineOptions { - private CSharpParseOptions _parseOptions = new CSharpParseOptions(LanguageVersion.CSharp7); - private CSharpCompilationOptions _compilationOptions = - new CSharpCompilationOptions(CodeAnalysis.OutputKind.DynamicallyLinkedLibrary); private Action _compilationCallback = c => { }; /// /// Gets a used by the . /// - public IList ViewLocationExpanders { get; } - = new List(); + public IList ViewLocationExpanders { get; } = new List(); /// /// Gets the sequence of instances used by to @@ -92,6 +87,34 @@ public class RazorViewEngineOptions /// public IList AreaViewLocationFormats { get; } = new List(); + /// + /// Gets the locations where will search for views (such as layouts and partials) + /// when searched from the context of rendering a Razor Page. + /// + /// + /// + /// Locations are format strings (see https://msdn.microsoft.com/en-us/library/txafckwd.aspx) which may contain + /// the following format items: + /// + /// + /// + /// {0} - View Name + /// + /// + /// {1} - Page Name + /// + /// + /// + /// 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 + /// + /// public IList PageViewLocationFormats { get; } = new List(); /// @@ -120,39 +143,5 @@ public Action CompilationCallback _compilationCallback = value; } } - - /// - /// Gets or sets the options used by Razor view compilation. - /// - public CSharpParseOptions ParseOptions - { - get => _parseOptions; - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - _parseOptions = value; - } - } - - /// - /// Gets or sets the used by Razor view compilation. - /// - public CSharpCompilationOptions CompilationOptions - { - get => _compilationOptions; - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - _compilationOptions = value; - } - } } } diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/CSharpCompilerTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/CSharpCompilerTest.cs index 9bb71e41c9..05ec25ad55 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/CSharpCompilerTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/CSharpCompilerTest.cs @@ -1,27 +1,272 @@ // 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(e => e.ApplicationName == name); + var compiler = CSharpCompiler.GetDependencyContextCompilationOptions(hostingEnvironment); + + // Act & Assert + Assert.Same(DependencyContextCompilationOptions.Default, compiler); + } + + [Fact] + public void GetCompilationOptions_ReturnsDefaultOptionsIfApplicationDoesNotHaveDependencyContext() + { + // Arrange + var hostingEnvironment = new Mock(); + hostingEnvironment.SetupGet(e => e.ApplicationName) + .Returns(typeof(Controller).GetTypeInfo().Assembly.GetName().Name); + var compiler = CSharpCompiler.GetDependencyContextCompilationOptions(hostingEnvironment.Object); + + // Act & Assert + Assert.Same(DependencyContextCompilationOptions.Default, compiler); + } + + [Fact] + public void Constructor_SetsCompilationOptionsFromDependencyContext() + { + // Arrange + var hostingEnvironment = new Mock(); + hostingEnvironment.SetupGet(e => e.ApplicationName) + .Returns(GetType().GetTypeInfo().Assembly.GetName().Name); + var compiler = new CSharpCompiler(Mock.Of(), 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(); + hostingEnvironment.SetupGet(e => e.EnvironmentName) + .Returns(environment); + var compiler = new CSharpCompiler(Mock.Of(), 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 Constructor_SetsPreprocessorSymbols(string environment, string expectedConfiguration) + { + // Arrange + var options = new RazorViewEngineOptions(); + var hostingEnvironment = new Mock(); + hostingEnvironment.SetupGet(e => e.EnvironmentName) + .Returns(environment); + var compiler = new CSharpCompiler(Mock.Of(), hostingEnvironment.Object); + + // Act & Assert + var parseOptions = compiler.ParseOptions; + Assert.Equal(new[] { expectedConfiguration }, parseOptions.PreprocessorSymbolNames); + } + + [Fact] + public void Constructor_ConfiguresDefaultCompilationOptions() + { + // Arrange + var hostingEnvironment = Mock.Of(h => h.EnvironmentName == "Development"); + var compiler = new CSharpCompiler(Mock.Of(), 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 Constructor_ConfiguresDefaultParseOptions() + { + // Arrange + var hostingEnvironment = Mock.Of(h => h.EnvironmentName == "Development"); + var compiler = new CSharpCompiler(Mock.Of(), hostingEnvironment); + + // Act & Assert + var parseOptions = compiler.ParseOptions; + Assert.Equal(LanguageVersion.CSharp7_1, parseOptions.LanguageVersion); + Assert.Equal(new[] { "DEBUG" }, parseOptions.PreprocessorSymbolNames); + } + + [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(); + var hostingEnvironment = Mock.Of(); + + var compiler = new CSharpCompiler(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(); + var hostingEnvironment = Mock.Of(); + + var compiler = new CSharpCompiler(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(); + var hostingEnvironment = Mock.Of(); + + var compiler = new CSharpCompiler(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(); + var hostingEnvironment = Mock.Of(); + + var compiler = new CSharpCompiler(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(); - 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(); + var hostingEnvironment = Mock.Of(); + var compiler = new CSharpCompiler(referenceManager, hostingEnvironment, dependencyContextOptions); // Act var syntaxTree = compiler.CreateSyntaxTree(SourceText.From(content)); @@ -29,15 +274,5 @@ public void Compile_UsesApplicationsCompilationSettings_ForParsingAndCompilation // Assert Assert.Contains(define, syntaxTree.Options.PreprocessorSymbolNames); } - - private static ApplicationPartManager GetApplicationPartManager() - { - var applicationPartManager = new ApplicationPartManager(); - var assembly = typeof(CSharpCompilerTest).GetTypeInfo().Assembly; - applicationPartManager.ApplicationParts.Add(new AssemblyPart(assembly)); - applicationPartManager.FeatureProviders.Add(new MetadataReferenceFeatureProvider()); - - return applicationPartManager; - } } } diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/DependencyContextRazorViewEngineOptionsSetupTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/DependencyContextRazorViewEngineOptionsSetupTest.cs deleted file mode 100644 index de3d7956c1..0000000000 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/DependencyContextRazorViewEngineOptionsSetupTest.cs +++ /dev/null @@ -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(); - 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(); - 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(); - 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(); - 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(); - 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()) - { - _options = options; - } - - protected internal override DependencyContextOptions GetCompilationOptions() - { - return _options ?? base.GetCompilationOptions(); - } - - public DependencyContextOptions GetCompilationOptionsPublic() => base.GetCompilationOptions(); - } - } -} diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/RazorViewCompilerProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/RazorViewCompilerProviderTest.cs index b05d4b16df..de5a67a97a 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/RazorViewCompilerProviderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/RazorViewCompilerProviderTest.cs @@ -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; @@ -26,12 +27,13 @@ public void GetCompiler_ThrowsIfNullFileProvider() var applicationManager = new ApplicationPartManager(); var options = new TestOptionsManager(); var referenceManager = new DefaultRazorReferenceManager(applicationManager, options); + var hostingEnvironment = Mock.Of(); accessor.Setup(a => a.FileProvider).Returns(fileProvider); var provider = new RazorViewCompilerProvider( applicationManager, new RazorTemplateEngine(RazorEngine.Create(), new FileProviderRazorProject(fileProvider)), accessor.Object, - new CSharpCompiler(referenceManager, options), + new CSharpCompiler(referenceManager, hostingEnvironment), options, NullLoggerFactory.Instance); diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/RazorViewCompilerTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/RazorViewCompilerTest.cs index 0abaceed4b..3d85a8d886 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/RazorViewCompilerTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/RazorViewCompilerTest.cs @@ -5,11 +5,13 @@ 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; using Microsoft.CodeAnalysis; using Microsoft.Extensions.Logging.Abstractions; +using Moq; using Xunit; namespace Microsoft.AspNetCore.Mvc.Razor.Internal @@ -551,7 +553,7 @@ private static TestRazorViewCompiler GetViewCompiler( var viewCompiler = new TestRazorViewCompiler( fileProvider, templateEngine, - new CSharpCompiler(referenceManager, options), + new CSharpCompiler(referenceManager, Mock.Of()), compilationCallback, precompiledViews); return viewCompiler; diff --git a/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/RazorViewEngineOptionsSetupTest.cs b/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/RazorViewEngineOptionsSetupTest.cs index d6824057c0..1351b64fa5 100644 --- a/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/RazorViewEngineOptionsSetupTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Razor.Test/Internal/RazorViewEngineOptionsSetupTest.cs @@ -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 @@ public void RazorViewEngineOptionsSetup_SetsUpFileProvider() var hostingEnv = new Mock(); 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 @@ public void RazorViewEngineOptionsSetup_SetsUpFileProvider() 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(); - 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(); - 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); - } } -} \ No newline at end of file +} diff --git a/test/Microsoft.AspNetCore.Mvc.Test/MvcServiceCollectionExtensionsTest.cs b/test/Microsoft.AspNetCore.Mvc.Test/MvcServiceCollectionExtensionsTest.cs index 018fab9678..dfdc65274c 100644 --- a/test/Microsoft.AspNetCore.Mvc.Test/MvcServiceCollectionExtensionsTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Test/MvcServiceCollectionExtensionsTest.cs @@ -362,7 +362,6 @@ private Dictionary MutliRegistrationServiceTypes new[] { typeof(RazorViewEngineOptionsSetup), - typeof(DependencyContextRazorViewEngineOptionsSetup), typeof(RazorPagesRazorViewEngineOptionsSetup), } },