From 2b9dd765351ca08adba63080b3ede65e2aae7a09 Mon Sep 17 00:00:00 2001 From: Pranav K Date: Tue, 29 Dec 2015 09:08:04 -0800 Subject: [PATCH] Make RazorViewEngineOptions.FileProvider a list instead of a single item Fixes #3806 --- samples/EmbeddedViewSample.Web/Startup.cs | 6 +- .../DefaultCompilerCacheProvider.cs | 7 +- .../PrecompiledViewsCompilerCacheProvider.cs | 8 +-- .../Compilation/RazorCompilationService.cs | 11 ++- .../Compilation/RoslynCompilationService.cs | 10 +-- ...aultRazorViewEngineFileProviderAccessor.cs | 36 ++++++++++ .../MvcRazorMvcCoreBuilderExtensions.cs | 7 +- .../IRazorViewEngineFileProviderAccessor.cs | 18 +++++ .../RazorViewEngineOptions.cs | 38 ++++------- .../RazorViewEngineOptionsSetup.cs | 2 +- src/Microsoft.AspNet.Mvc.Razor/project.json | 4 +- .../RazorCompilationServiceTest.cs | 20 +++--- .../RoslynCompilationServiceTest.cs | 56 ++++++++++------ ...RazorViewEngineFileProviderAccessorTest.cs | 67 +++++++++++++++++++ .../RazorViewEngineOptionsTest.cs | 18 +---- .../RazorViewEngineOptionsSetupTest.cs | 12 ++-- .../TestRazorCompilationService.cs | 5 +- 17 files changed, 216 insertions(+), 109 deletions(-) create mode 100644 src/Microsoft.AspNet.Mvc.Razor/DefaultRazorViewEngineFileProviderAccessor.cs create mode 100644 src/Microsoft.AspNet.Mvc.Razor/IRazorViewEngineFileProviderAccessor.cs create mode 100644 test/Microsoft.AspNet.Mvc.Razor.Test/DefaultRazorViewEngineFileProviderAccessorTest.cs diff --git a/samples/EmbeddedViewSample.Web/Startup.cs b/samples/EmbeddedViewSample.Web/Startup.cs index c0c065e7de..4d24da892b 100644 --- a/samples/EmbeddedViewSample.Web/Startup.cs +++ b/samples/EmbeddedViewSample.Web/Startup.cs @@ -20,10 +20,12 @@ namespace EmbeddedViewSample.Web services.Configure(options => { + options.FileProviders.Clear(); + // Base namespace matches the resources added to the assembly from the EmbeddedResources folder. - options.FileProvider = new EmbeddedFileProvider( + options.FileProviders.Add(new EmbeddedFileProvider( GetType().GetTypeInfo().Assembly, - baseNamespace: "EmbeddedViewSample.Web.EmbeddedResources"); + baseNamespace: "EmbeddedViewSample.Web.EmbeddedResources")); }); } diff --git a/src/Microsoft.AspNet.Mvc.Razor/Compilation/DefaultCompilerCacheProvider.cs b/src/Microsoft.AspNet.Mvc.Razor/Compilation/DefaultCompilerCacheProvider.cs index c98070ce75..bf5edb574f 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/Compilation/DefaultCompilerCacheProvider.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/Compilation/DefaultCompilerCacheProvider.cs @@ -13,11 +13,10 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation /// /// Initializes a new instance of . /// - /// An accessor to the . - public DefaultCompilerCacheProvider(IOptions mvcViewOptions) + /// The . + public DefaultCompilerCacheProvider(IRazorViewEngineFileProviderAccessor fileProviderAccessor) { - var fileProvider = mvcViewOptions.Value.FileProvider; - Cache = new CompilerCache(fileProvider); + Cache = new CompilerCache(fileProviderAccessor.FileProvider); } /// diff --git a/src/Microsoft.AspNet.Mvc.Razor/Compilation/PrecompiledViewsCompilerCacheProvider.cs b/src/Microsoft.AspNet.Mvc.Razor/Compilation/PrecompiledViewsCompilerCacheProvider.cs index 2db34f9a26..6ca1bca1a0 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/Compilation/PrecompiledViewsCompilerCacheProvider.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/Compilation/PrecompiledViewsCompilerCacheProvider.cs @@ -33,16 +33,16 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation /// /// Initializes a new instance of . /// - /// The . - /// An accessor to the . + /// The . + /// The . /// instances to scan for precompiled views. public PrecompiledViewsCompilerCacheProvider( IAssemblyLoadContextAccessor loadContextAccessor, - IOptions mvcViewOptions, + IRazorViewEngineFileProviderAccessor fileProviderAccessor, IEnumerable assemblies) { _loadContextAccessor = loadContextAccessor; - _fileProvider = mvcViewOptions.Value.FileProvider; + _fileProvider = fileProviderAccessor.FileProvider; _createCache = CreateCache; _assemblies = assemblies.ToArray(); } diff --git a/src/Microsoft.AspNet.Mvc.Razor/Compilation/RazorCompilationService.cs b/src/Microsoft.AspNet.Mvc.Razor/Compilation/RazorCompilationService.cs index 0005730bc0..d745173257 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/Compilation/RazorCompilationService.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/Compilation/RazorCompilationService.cs @@ -27,17 +27,15 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation /// /// The to compile generated code. /// The to generate code from Razor files. - /// - /// The to read Razor files referenced in error messages. - /// + /// The . public RazorCompilationService( ICompilationService compilationService, IMvcRazorHost razorHost, - IOptions viewEngineOptions) + IRazorViewEngineFileProviderAccessor fileProviderAccessor) { _compilationService = compilationService; _razorHost = razorHost; - _fileProvider = viewEngineOptions.Value.FileProvider; + _fileProvider = fileProviderAccessor.FileProvider; } /// @@ -105,9 +103,10 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation private DiagnosticMessage CreateDiagnosticMessage(RazorError error, string filePath) { + var location = error.Location; return new DiagnosticMessage( message: error.Message, - formattedMessage: $"{error} ({error.Location.LineIndex},{error.Location.CharacterIndex}) {error.Message}", + formattedMessage: $"{error} ({location.LineIndex},{location.CharacterIndex}) {error.Message}", filePath: filePath, startLine: error.Location.LineIndex + 1, startColumn: error.Location.CharacterIndex, diff --git a/src/Microsoft.AspNet.Mvc.Razor/Compilation/RoslynCompilationService.cs b/src/Microsoft.AspNet.Mvc.Razor/Compilation/RoslynCompilationService.cs index 0736bed2ed..3e011f0d23 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/Compilation/RoslynCompilationService.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/Compilation/RoslynCompilationService.cs @@ -51,21 +51,21 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation /// Initalizes a new instance of the class. /// /// The environment for the executing application. - /// - /// The accessor for the used to load compiled assemblies. - /// /// The library manager that provides export and reference information. /// The that was used to generate the code. + /// Accessor to . + /// The . public RoslynCompilationService( IApplicationEnvironment environment, Extensions.CompilationAbstractions.ILibraryExporter libraryExporter, IMvcRazorHost host, - IOptions optionsAccessor) + IOptions optionsAccessor, + IRazorViewEngineFileProviderAccessor fileProviderAccessor) { _environment = environment; _libraryExporter = libraryExporter; _applicationReferences = new Lazy>(GetApplicationReferences); - _fileProvider = optionsAccessor.Value.FileProvider; + _fileProvider = fileProviderAccessor.FileProvider; _classPrefix = host.MainClassNamePrefix; _compilationCallback = optionsAccessor.Value.CompilationCallback; _parseOptions = optionsAccessor.Value.ParseOptions; diff --git a/src/Microsoft.AspNet.Mvc.Razor/DefaultRazorViewEngineFileProviderAccessor.cs b/src/Microsoft.AspNet.Mvc.Razor/DefaultRazorViewEngineFileProviderAccessor.cs new file mode 100644 index 0000000000..3d098227f3 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Razor/DefaultRazorViewEngineFileProviderAccessor.cs @@ -0,0 +1,36 @@ +// 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 Microsoft.AspNet.FileProviders; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNet.Mvc.Razor +{ + /// + /// Default implementation of . + /// + public class DefaultRazorViewEngineFileProviderAccessor : IRazorViewEngineFileProviderAccessor + { + /// + /// Initializes a new instance of . + /// + /// Accessor to . + public DefaultRazorViewEngineFileProviderAccessor(IOptions optionsAccessor) + { + var fileProviders = optionsAccessor.Value.FileProviders; + if (fileProviders.Count == 1) + { + FileProvider = fileProviders[0]; + } + else + { + FileProvider = new CompositeFileProvider(fileProviders); + } + } + + /// + /// Gets the used to look up Razor files. + /// + public IFileProvider FileProvider { get; } + } +} diff --git a/src/Microsoft.AspNet.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs b/src/Microsoft.AspNet.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs index dd7cc28fe7..fbd46c3d09 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs @@ -14,7 +14,6 @@ using Microsoft.AspNet.Razor.TagHelpers; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.CompilationAbstractions; using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.MemoryPool; using Microsoft.Extensions.Options; using Microsoft.Extensions.PlatformAbstractions; @@ -130,12 +129,14 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAddEnumerable( ServiceDescriptor.Transient, RazorViewEngineOptionsSetup>()); + services.TryAddSingleton(); + services.TryAddSingleton(); services.TryAdd(ServiceDescriptor.Singleton(serviceProvider => { - var cachedFileProvider = serviceProvider.GetRequiredService>(); - return new DefaultChunkTreeCache(cachedFileProvider.Value.FileProvider); + var accessor = serviceProvider.GetRequiredService(); + return new DefaultChunkTreeCache(accessor.FileProvider); })); // Caches compilation artifacts across the lifetime of the application. diff --git a/src/Microsoft.AspNet.Mvc.Razor/IRazorViewEngineFileProviderAccessor.cs b/src/Microsoft.AspNet.Mvc.Razor/IRazorViewEngineFileProviderAccessor.cs new file mode 100644 index 0000000000..1d23ff01a4 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Razor/IRazorViewEngineFileProviderAccessor.cs @@ -0,0 +1,18 @@ +// 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 Microsoft.AspNet.FileProviders; + +namespace Microsoft.AspNet.Mvc.Razor +{ + /// + /// Accessor to the used by . + /// + public interface IRazorViewEngineFileProviderAccessor + { + /// + /// Gets the used to look up Razor files. + /// + IFileProvider FileProvider { get; } + } +} diff --git a/src/Microsoft.AspNet.Mvc.Razor/RazorViewEngineOptions.cs b/src/Microsoft.AspNet.Mvc.Razor/RazorViewEngineOptions.cs index cb8c63ed54..c2b8134733 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/RazorViewEngineOptions.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/RazorViewEngineOptions.cs @@ -14,12 +14,9 @@ namespace Microsoft.AspNet.Mvc.Razor /// public class RazorViewEngineOptions { - private IFileProvider _fileProvider; - private CSharpParseOptions _parseOptions = new CSharpParseOptions(LanguageVersion.CSharp6); - - private CSharpCompilationOptions _compilationOptions = new CSharpCompilationOptions(CodeAnalysis.OutputKind.DynamicallyLinkedLibrary); - + private CSharpCompilationOptions _compilationOptions = + new CSharpCompilationOptions(CodeAnalysis.OutputKind.DynamicallyLinkedLibrary); private Action _compilationCallback = c => { }; /// @@ -29,33 +26,22 @@ namespace Microsoft.AspNet.Mvc.Razor = new List(); /// - /// Gets or sets the used by to locate Razor files on - /// disk. + /// Gets the sequence of instances used by to + /// locate Razor files. /// /// - /// At startup, this is initialized to an instance of that is rooted at the - /// application root. + /// At startup, this is initialized to include an instance of that is + /// rooted at the application root. /// - public IFileProvider FileProvider - { - get { return _fileProvider; } - - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - _fileProvider = value; - } - } + public IList FileProviders { get; } = new List(); /// /// Gets or sets the callback that is used to customize Razor compilation /// to change compilation settings you can update property. - /// Customizations made here would not reflect in tooling (Intellisense). /// + /// + /// Customizations made here would not reflect in tooling (Intellisense). + /// public Action CompilationCallback { get { return _compilationCallback; } @@ -65,6 +51,7 @@ namespace Microsoft.AspNet.Mvc.Razor { throw new ArgumentNullException(nameof(value)); } + _compilationCallback = value; } } @@ -81,6 +68,7 @@ namespace Microsoft.AspNet.Mvc.Razor { throw new ArgumentNullException(nameof(value)); } + _parseOptions = value; } } @@ -97,9 +85,9 @@ namespace Microsoft.AspNet.Mvc.Razor { throw new ArgumentNullException(nameof(value)); } + _compilationOptions = value; } } - } } diff --git a/src/Microsoft.AspNet.Mvc.Razor/RazorViewEngineOptionsSetup.cs b/src/Microsoft.AspNet.Mvc.Razor/RazorViewEngineOptionsSetup.cs index 905dceada0..6f72117d3f 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/RazorViewEngineOptionsSetup.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/RazorViewEngineOptionsSetup.cs @@ -31,7 +31,7 @@ namespace Microsoft.AspNet.Mvc IApplicationEnvironment applicationEnvironment, IHostingEnvironment hostingEnvironment) { - razorOptions.FileProvider = new PhysicalFileProvider(applicationEnvironment.ApplicationBasePath); + razorOptions.FileProviders.Add(new PhysicalFileProvider(applicationEnvironment.ApplicationBasePath)); var parseOptions = new CSharpParseOptions(LanguageVersion.CSharp6); var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary); diff --git a/src/Microsoft.AspNet.Mvc.Razor/project.json b/src/Microsoft.AspNet.Mvc.Razor/project.json index 58f3b8322a..4c84eebeea 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/project.json +++ b/src/Microsoft.AspNet.Mvc.Razor/project.json @@ -10,6 +10,7 @@ "keyFile": "../../tools/Key.snk" }, "dependencies": { + "Microsoft.AspNet.FileProviders.Composite": "1.0.0-*", "Microsoft.AspNet.Mvc.Razor.Host": "6.0.0-*", "Microsoft.AspNet.Mvc.ViewFeatures": "6.0.0-*", "Microsoft.AspNet.Razor.Runtime.Precompilation": "4.0.0-*", @@ -26,8 +27,7 @@ "type": "build" }, "Microsoft.Dnx.Compilation.CSharp.Common": "1.0.0-*", - "Microsoft.Dnx.Compilation.CSharp.Abstractions": "1.0.0-*", - "Microsoft.Extensions.MemoryPool": "1.0.0-*" + "Microsoft.Dnx.Compilation.CSharp.Abstractions": "1.0.0-*" }, "frameworks": { "net451": { diff --git a/test/Microsoft.AspNet.Mvc.Razor.Test/Compilation/RazorCompilationServiceTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Test/Compilation/RazorCompilationServiceTest.cs index e45598d0cf..83acc7359d 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Test/Compilation/RazorCompilationServiceTest.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Test/Compilation/RazorCompilationServiceTest.cs @@ -38,7 +38,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation compiler.Setup(c => c.Compile(relativeFileInfo, It.IsAny())) .Returns(new CompilationResult(typeof(RazorCompilationServiceTest))); - var razorService = new RazorCompilationService(compiler.Object, host.Object, GetOptions()); + var razorService = new RazorCompilationService(compiler.Object, host.Object, GetFileProviderAccessor()); // Act razorService.Compile(relativeFileInfo); @@ -70,7 +70,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation var compiler = new Mock(MockBehavior.Strict); var relativeFileInfo = new RelativeFileInfo(fileInfo.Object, @"Views\index\home.cshtml"); - var razorService = new RazorCompilationService(compiler.Object, host.Object, GetOptions()); + var razorService = new RazorCompilationService(compiler.Object, host.Object, GetFileProviderAccessor()); // Act var result = razorService.Compile(relativeFileInfo); @@ -111,7 +111,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation compiler.Setup(c => c.Compile(relativeFileInfo, code)) .Returns(compilationResult) .Verifiable(); - var razorService = new RazorCompilationService(compiler.Object, host.Object, GetOptions()); + var razorService = new RazorCompilationService(compiler.Object, host.Object, GetFileProviderAccessor()); // Act var result = razorService.Compile(relativeFileInfo); @@ -136,7 +136,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation var razorService = new RazorCompilationService( Mock.Of(), Mock.Of(), - GetOptions(fileProvider)); + GetFileProviderAccessor(fileProvider)); var errors = new[] { new RazorError("message-1", new SourceLocation(1, 2, 17), length: 1), @@ -211,15 +211,11 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation new ChunkTree()); } - private static IOptions GetOptions(IFileProvider fileProvider = null) + private static IRazorViewEngineFileProviderAccessor GetFileProviderAccessor(IFileProvider fileProvider = null) { - var razorViewEngineOptions = new RazorViewEngineOptions - { - FileProvider = fileProvider ?? new TestFileProvider() - }; - var options = new Mock>(); - options.SetupGet(o => o.Value) - .Returns(razorViewEngineOptions); + var options = new Mock(); + options.SetupGet(o => o.FileProvider) + .Returns(fileProvider ?? new TestFileProvider()); return options.Object; } diff --git a/test/Microsoft.AspNet.Mvc.Razor.Test/Compilation/RoslynCompilationServiceTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Test/Compilation/RoslynCompilationServiceTest.cs index 8eea92a5ca..577f3320ce 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Test/Compilation/RoslynCompilationServiceTest.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Test/Compilation/RoslynCompilationServiceTest.cs @@ -2,11 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Runtime.Versioning; using Microsoft.AspNet.FileProviders; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text; -using Microsoft.Dnx.Runtime; using Microsoft.Extensions.CompilationAbstractions; using Microsoft.Extensions.Options; using Microsoft.Extensions.PlatformAbstractions; @@ -35,7 +33,8 @@ public class MyTestType {}"; applicationEnvironment, libraryExporter, mvcRazorHost.Object, - GetOptions()); + GetOptions(), + GetFileProviderAccessor()); var relativeFileInfo = new RelativeFileInfo( new TestFileInfo { PhysicalPath = "SomePath" }, "some-relative-path"); @@ -66,7 +65,8 @@ this should fail"; applicationEnvironment, libraryExporter, mvcRazorHost, - GetOptions(fileProvider)); + GetOptions(), + GetFileProviderAccessor(fileProvider)); var relativeFileInfo = new RelativeFileInfo(fileInfo, "some-relative-path"); // Act @@ -94,7 +94,8 @@ this should fail"; applicationEnvironment, libraryExporter, mvcRazorHost, - GetOptions()); + GetOptions(), + GetFileProviderAccessor()); var relativeFileInfo = new RelativeFileInfo( new TestFileInfo { Content = fileContent }, "some-relative-path"); @@ -125,7 +126,7 @@ this should fail"; var mockFileInfo = new Mock(); mockFileInfo.Setup(f => f.CreateReadStream()) - .Throws(new Exception()); + .Throws(new Exception()); var fileProvider = new TestFileProvider(); fileProvider.AddFile(path, mockFileInfo.Object); @@ -133,7 +134,8 @@ this should fail"; applicationEnvironment, libraryExporter, mvcRazorHost, - GetOptions(fileProvider)); + GetOptions(), + GetFileProviderAccessor(fileProvider)); var relativeFileInfo = new RelativeFileInfo(mockFileInfo.Object, path); @@ -163,7 +165,7 @@ public class MyNonCustomDefinedClass {} var libraryExporter = CompilationServices.Default.LibraryExporter; var mvcRazorHost = new Mock(); mvcRazorHost.SetupGet(m => m.MainClassNamePrefix) - .Returns("My"); + .Returns("My"); var options = GetOptions(); options.Value.ParseOptions = options.Value.ParseOptions.WithPreprocessorSymbols("MY_CUSTOM_DEFINE"); @@ -172,7 +174,8 @@ public class MyNonCustomDefinedClass {} applicationEnvironment, libraryExporter, mvcRazorHost.Object, - options); + options, + GetFileProviderAccessor()); var relativeFileInfo = new RelativeFileInfo( new TestFileInfo { PhysicalPath = "SomePath" }, "some-relative-path"); @@ -202,7 +205,8 @@ public class NotRazorPrefixType {}"; applicationEnvironment, libraryExporter, mvcRazorHost.Object, - GetOptions()); + GetOptions(), + GetFileProviderAccessor()); var relativeFileInfo = new RelativeFileInfo( new TestFileInfo { PhysicalPath = "SomePath" }, @@ -224,17 +228,17 @@ public class NotRazorPrefixType {}"; var generatedCodeFileName = "Generated Code"; var fileProvider = new TestFileProvider(); fileProvider.AddFile(viewPath, "view-content"); - var options = new Mock>(); - options.SetupGet(o => o.Value) - .Returns(new RazorViewEngineOptions - { - FileProvider = fileProvider - }); + var options = new RazorViewEngineOptions(); + options.FileProviders.Add(fileProvider); + var optionsAccessor = new Mock>(); + optionsAccessor.SetupGet(o => o.Value) + .Returns(options); var compilationService = new RoslynCompilationService( PlatformServices.Default.Application, CompilationServices.Default.LibraryExporter, Mock.Of(), - options.Object); + optionsAccessor.Object, + GetFileProviderAccessor(fileProvider)); var assemblyName = "random-assembly-name"; @@ -325,7 +329,8 @@ public class NotRazorPrefixType {}"; applicationEnvironment, libraryExporter, mvcRazorHost.Object, - GetOptions(callback: c => usedCompilation = c)); + GetOptions(callback: c => usedCompilation = c), + GetFileProviderAccessor()); var relativeFileInfo = new RelativeFileInfo( new TestFileInfo { PhysicalPath = "SomePath" }, @@ -350,13 +355,11 @@ public class NotRazorPrefixType {}"; isEnabledByDefault: true); } - private static IOptions GetOptions(IFileProvider fileProvider = null, - Action callback = null) + private static IOptions GetOptions(Action callback = null) { var razorViewEngineOptions = new RazorViewEngineOptions { - FileProvider = fileProvider ?? new TestFileProvider(), - CompilationCallback = callback ?? (c => { }) + CompilationCallback = callback ?? (c => { }), }; var options = new Mock>(); options @@ -365,5 +368,14 @@ public class NotRazorPrefixType {}"; return options.Object; } + + private IRazorViewEngineFileProviderAccessor GetFileProviderAccessor(IFileProvider fileProvider = null) + { + var options = new Mock(); + options.SetupGet(o => o.FileProvider) + .Returns(fileProvider ?? new TestFileProvider()); + + return options.Object; + } } } diff --git a/test/Microsoft.AspNet.Mvc.Razor.Test/DefaultRazorViewEngineFileProviderAccessorTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Test/DefaultRazorViewEngineFileProviderAccessorTest.cs new file mode 100644 index 0000000000..01bd8dad2c --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.Razor.Test/DefaultRazorViewEngineFileProviderAccessorTest.cs @@ -0,0 +1,67 @@ +// 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 Microsoft.AspNet.FileProviders; +using Microsoft.AspNet.Mvc.Internal; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Moq; +using Xunit; + +namespace Microsoft.AspNet.Mvc.Razor +{ + public class DefaultRazorViewEngineFileProviderAccessorTest + { + [Fact] + public void FileProvider_ReturnsInstanceIfExactlyOneFileProviderIsSpecified() + { + // Arrange + var fileProvider = new TestFileProvider(); + var options = new RazorViewEngineOptions(); + options.FileProviders.Add(fileProvider); + var optionsAccessor = new Mock>(); + optionsAccessor.SetupGet(o => o.Value).Returns(options); + var fileProviderAccessor = new DefaultRazorViewEngineFileProviderAccessor(optionsAccessor.Object); + + // Act + var actual = fileProviderAccessor.FileProvider; + + // Assert + Assert.Same(fileProvider, actual); + } + + [Fact] + public void FileProvider_ReturnsCompositeFileProviderIfNoInstancesAreRegistered() + { + // Arrange + var options = new RazorViewEngineOptions(); + var optionsAccessor = new Mock>(); + optionsAccessor.SetupGet(o => o.Value).Returns(options); + var fileProviderAccessor = new DefaultRazorViewEngineFileProviderAccessor(optionsAccessor.Object); + + // Act + var actual = fileProviderAccessor.FileProvider; + + // Assert + Assert.IsType(actual); + } + + [Fact] + public void FileProvider_ReturnsCompositeFileProviderIfMoreThanOneInstanceIsRegistered() + { + // Arrange + var options = new RazorViewEngineOptions(); + options.FileProviders.Add(new TestFileProvider()); + options.FileProviders.Add(new TestFileProvider()); + var optionsAccessor = new Mock>(); + optionsAccessor.SetupGet(o => o.Value).Returns(options); + var fileProviderAccessor = new DefaultRazorViewEngineFileProviderAccessor(optionsAccessor.Object); + + // Act + var actual = fileProviderAccessor.FileProvider; + + // Assert + Assert.IsType(actual); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.Razor.Test/RazorViewEngineOptionsTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Test/RazorViewEngineOptionsTest.cs index 4f2fc1c814..4c49d35558 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Test/RazorViewEngineOptionsTest.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Test/RazorViewEngineOptionsTest.cs @@ -1,7 +1,6 @@ // 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 Microsoft.AspNet.Mvc.Internal; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -12,18 +11,7 @@ namespace Microsoft.AspNet.Mvc.Razor public class RazorViewEngineOptionsTest { [Fact] - public void FileProviderThrows_IfNullIsAssigned() - { - // Arrange - var options = new RazorViewEngineOptions(); - - // Act and Assert - var ex = Assert.Throws(() => options.FileProvider = null); - Assert.Equal("value", ex.ParamName); - } - - [Fact] - public void AddRazorOptions_ConfiguresOptionsProperly() + public void AddRazorOptions_ConfiguresOptionsAsExpected() { // Arrange var services = new ServiceCollection().AddOptions(); @@ -33,13 +21,13 @@ namespace Microsoft.AspNet.Mvc.Razor var builder = new MvcBuilder(services); builder.AddRazorOptions(options => { - options.FileProvider = fileProvider; + options.FileProviders.Add(fileProvider); }); var serviceProvider = services.BuildServiceProvider(); // Assert var accessor = serviceProvider.GetRequiredService>(); - Assert.Same(fileProvider, accessor.Value.FileProvider); + Assert.Same(fileProvider, accessor.Value.FileProviders[0]); } } } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.Test/RazorViewEngineOptionsSetupTest.cs b/test/Microsoft.AspNet.Mvc.Test/RazorViewEngineOptionsSetupTest.cs index b0921c51ec..0bd74da724 100644 --- a/test/Microsoft.AspNet.Mvc.Test/RazorViewEngineOptionsSetupTest.cs +++ b/test/Microsoft.AspNet.Mvc.Test/RazorViewEngineOptionsSetupTest.cs @@ -21,18 +21,18 @@ namespace Microsoft.AspNet.Mvc var options = new RazorViewEngineOptions(); var appEnv = new Mock(); appEnv.SetupGet(e => e.ApplicationBasePath) - .Returns(Directory.GetCurrentDirectory()); + .Returns(Directory.GetCurrentDirectory()); var hostingEnv = new Mock(); hostingEnv.SetupGet(e => e.EnvironmentName) - .Returns("Development"); + .Returns("Development"); var optionsSetup = new RazorViewEngineOptionsSetup(appEnv.Object, hostingEnv.Object); // Act optionsSetup.Configure(options); // Assert - Assert.NotNull(options.FileProvider); - Assert.IsType(options.FileProvider); + var fileProvider = Assert.Single(options.FileProviders); + Assert.IsType(fileProvider); } [Theory] @@ -62,7 +62,9 @@ namespace Microsoft.AspNet.Mvc [InlineData("Development", OptimizationLevel.Debug)] [InlineData("Staging", OptimizationLevel.Release)] [InlineData("Production", OptimizationLevel.Release)] - public void RazorViewEngineOptionsSetup_SetsOptimizationLevel(string environment, OptimizationLevel expectedOptimizationLevel) + public void RazorViewEngineOptionsSetup_SetsOptimizationLevel( + string environment, + OptimizationLevel expectedOptimizationLevel) { // Arrange var options = new RazorViewEngineOptions(); diff --git a/test/WebSites/RazorPageExecutionInstrumentationWebSite/TestRazorCompilationService.cs b/test/WebSites/RazorPageExecutionInstrumentationWebSite/TestRazorCompilationService.cs index 705ca50388..e92423b604 100644 --- a/test/WebSites/RazorPageExecutionInstrumentationWebSite/TestRazorCompilationService.cs +++ b/test/WebSites/RazorPageExecutionInstrumentationWebSite/TestRazorCompilationService.cs @@ -6,7 +6,6 @@ using System.Text; using Microsoft.AspNet.Mvc.Razor; using Microsoft.AspNet.Mvc.Razor.Compilation; using Microsoft.AspNet.Razor.CodeGenerators; -using Microsoft.Extensions.Options; namespace RazorPageExecutionInstrumentationWebSite { @@ -15,8 +14,8 @@ namespace RazorPageExecutionInstrumentationWebSite public TestRazorCompilationService( ICompilationService compilationService, IMvcRazorHost razorHost, - IOptions viewEngineOptions) - : base(compilationService, razorHost, viewEngineOptions) + IRazorViewEngineFileProviderAccessor fileProviderAccessor) + : base(compilationService, razorHost, fileProviderAccessor) { }