Make RazorViewEngineOptions.FileProvider a list instead of a single item

Fixes #3806
This commit is contained in:
Pranav K 2015-12-29 09:08:04 -08:00
parent d222900662
commit 2b9dd76535
17 changed files with 216 additions and 109 deletions

View File

@ -20,10 +20,12 @@ namespace EmbeddedViewSample.Web
services.Configure<RazorViewEngineOptions>(options => services.Configure<RazorViewEngineOptions>(options =>
{ {
options.FileProviders.Clear();
// Base namespace matches the resources added to the assembly from the EmbeddedResources folder. // 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, GetType().GetTypeInfo().Assembly,
baseNamespace: "EmbeddedViewSample.Web.EmbeddedResources"); baseNamespace: "EmbeddedViewSample.Web.EmbeddedResources"));
}); });
} }

View File

@ -13,11 +13,10 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
/// <summary> /// <summary>
/// Initializes a new instance of <see cref="DefaultCompilerCacheProvider"/>. /// Initializes a new instance of <see cref="DefaultCompilerCacheProvider"/>.
/// </summary> /// </summary>
/// <param name="optionsAccessor">An accessor to the <see cref="RazorViewEngineOptions"/>.</param> /// <param name="fileProviderAccessor">The <see cref="IRazorViewEngineFileProviderAccessor"/>.</param>
public DefaultCompilerCacheProvider(IOptions<RazorViewEngineOptions> mvcViewOptions) public DefaultCompilerCacheProvider(IRazorViewEngineFileProviderAccessor fileProviderAccessor)
{ {
var fileProvider = mvcViewOptions.Value.FileProvider; Cache = new CompilerCache(fileProviderAccessor.FileProvider);
Cache = new CompilerCache(fileProvider);
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -33,16 +33,16 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
/// <summary> /// <summary>
/// Initializes a new instance of <see cref="DefaultCompilerCacheProvider"/>. /// Initializes a new instance of <see cref="DefaultCompilerCacheProvider"/>.
/// </summary> /// </summary>
/// <param name="loaderContextAccessor">The <see cref="IAssemblyLoadContextAccessor"/>.</param> /// <param name="loadContextAccessor">The <see cref="IAssemblyLoadContextAccessor"/>.</param>
/// <param name="optionsAccessor">An accessor to the <see cref="RazorViewEngineOptions"/>.</param> /// <param name="fileProviderAccessor">The <see cref="IRazorViewEngineFileProviderAccessor"/>.</param>
/// <param name="assemblies"><see cref="Assembly"/> instances to scan for precompiled views.</param> /// <param name="assemblies"><see cref="Assembly"/> instances to scan for precompiled views.</param>
public PrecompiledViewsCompilerCacheProvider( public PrecompiledViewsCompilerCacheProvider(
IAssemblyLoadContextAccessor loadContextAccessor, IAssemblyLoadContextAccessor loadContextAccessor,
IOptions<RazorViewEngineOptions> mvcViewOptions, IRazorViewEngineFileProviderAccessor fileProviderAccessor,
IEnumerable<Assembly> assemblies) IEnumerable<Assembly> assemblies)
{ {
_loadContextAccessor = loadContextAccessor; _loadContextAccessor = loadContextAccessor;
_fileProvider = mvcViewOptions.Value.FileProvider; _fileProvider = fileProviderAccessor.FileProvider;
_createCache = CreateCache; _createCache = CreateCache;
_assemblies = assemblies.ToArray(); _assemblies = assemblies.ToArray();
} }

View File

@ -27,17 +27,15 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
/// </summary> /// </summary>
/// <param name="compilationService">The <see cref="ICompilationService"/> to compile generated code.</param> /// <param name="compilationService">The <see cref="ICompilationService"/> to compile generated code.</param>
/// <param name="razorHost">The <see cref="IMvcRazorHost"/> to generate code from Razor files.</param> /// <param name="razorHost">The <see cref="IMvcRazorHost"/> to generate code from Razor files.</param>
/// <param name="viewEngineOptions"> /// <param name="fileProviderAccessor">The <see cref="IRazorViewEngineFileProviderAccessor"/>.</param>
/// The <see cref="IFileProvider"/> to read Razor files referenced in error messages.
/// </param>
public RazorCompilationService( public RazorCompilationService(
ICompilationService compilationService, ICompilationService compilationService,
IMvcRazorHost razorHost, IMvcRazorHost razorHost,
IOptions<RazorViewEngineOptions> viewEngineOptions) IRazorViewEngineFileProviderAccessor fileProviderAccessor)
{ {
_compilationService = compilationService; _compilationService = compilationService;
_razorHost = razorHost; _razorHost = razorHost;
_fileProvider = viewEngineOptions.Value.FileProvider; _fileProvider = fileProviderAccessor.FileProvider;
} }
/// <inheritdoc /> /// <inheritdoc />
@ -105,9 +103,10 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
private DiagnosticMessage CreateDiagnosticMessage(RazorError error, string filePath) private DiagnosticMessage CreateDiagnosticMessage(RazorError error, string filePath)
{ {
var location = error.Location;
return new DiagnosticMessage( return new DiagnosticMessage(
message: error.Message, message: error.Message,
formattedMessage: $"{error} ({error.Location.LineIndex},{error.Location.CharacterIndex}) {error.Message}", formattedMessage: $"{error} ({location.LineIndex},{location.CharacterIndex}) {error.Message}",
filePath: filePath, filePath: filePath,
startLine: error.Location.LineIndex + 1, startLine: error.Location.LineIndex + 1,
startColumn: error.Location.CharacterIndex, startColumn: error.Location.CharacterIndex,

View File

@ -51,21 +51,21 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
/// Initalizes a new instance of the <see cref="RoslynCompilationService"/> class. /// Initalizes a new instance of the <see cref="RoslynCompilationService"/> class.
/// </summary> /// </summary>
/// <param name="environment">The environment for the executing application.</param> /// <param name="environment">The environment for the executing application.</param>
/// <param name="loaderAccessor">
/// The accessor for the <see cref="IAssemblyLoadContext"/> used to load compiled assemblies.
/// </param>
/// <param name="libraryExporter">The library manager that provides export and reference information.</param> /// <param name="libraryExporter">The library manager that provides export and reference information.</param>
/// <param name="host">The <see cref="IMvcRazorHost"/> that was used to generate the code.</param> /// <param name="host">The <see cref="IMvcRazorHost"/> that was used to generate the code.</param>
/// <param name="optionsAccessor">Accessor to <see cref="RazorViewEngineOptions"/>.</param>
/// <param name="fileProviderAccessor">The <see cref="IRazorViewEngineFileProviderAccessor"/>.</param>
public RoslynCompilationService( public RoslynCompilationService(
IApplicationEnvironment environment, IApplicationEnvironment environment,
Extensions.CompilationAbstractions.ILibraryExporter libraryExporter, Extensions.CompilationAbstractions.ILibraryExporter libraryExporter,
IMvcRazorHost host, IMvcRazorHost host,
IOptions<RazorViewEngineOptions> optionsAccessor) IOptions<RazorViewEngineOptions> optionsAccessor,
IRazorViewEngineFileProviderAccessor fileProviderAccessor)
{ {
_environment = environment; _environment = environment;
_libraryExporter = libraryExporter; _libraryExporter = libraryExporter;
_applicationReferences = new Lazy<List<MetadataReference>>(GetApplicationReferences); _applicationReferences = new Lazy<List<MetadataReference>>(GetApplicationReferences);
_fileProvider = optionsAccessor.Value.FileProvider; _fileProvider = fileProviderAccessor.FileProvider;
_classPrefix = host.MainClassNamePrefix; _classPrefix = host.MainClassNamePrefix;
_compilationCallback = optionsAccessor.Value.CompilationCallback; _compilationCallback = optionsAccessor.Value.CompilationCallback;
_parseOptions = optionsAccessor.Value.ParseOptions; _parseOptions = optionsAccessor.Value.ParseOptions;

View File

@ -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
{
/// <summary>
/// Default implementation of <see cref="IRazorViewEngineFileProviderAccessor"/>.
/// </summary>
public class DefaultRazorViewEngineFileProviderAccessor : IRazorViewEngineFileProviderAccessor
{
/// <summary>
/// Initializes a new instance of <see cref="DefaultRazorViewEngineFileProviderAccessor"/>.
/// </summary>
/// <param name="optionsAccessor">Accessor to <see cref="RazorViewEngineOptions"/>.</param>
public DefaultRazorViewEngineFileProviderAccessor(IOptions<RazorViewEngineOptions> optionsAccessor)
{
var fileProviders = optionsAccessor.Value.FileProviders;
if (fileProviders.Count == 1)
{
FileProvider = fileProviders[0];
}
else
{
FileProvider = new CompositeFileProvider(fileProviders);
}
}
/// <summary>
/// Gets the <see cref="IFileProvider"/> used to look up Razor files.
/// </summary>
public IFileProvider FileProvider { get; }
}
}

View File

@ -14,7 +14,6 @@ using Microsoft.AspNet.Razor.TagHelpers;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.CompilationAbstractions; using Microsoft.Extensions.CompilationAbstractions;
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.MemoryPool;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.Extensions.PlatformAbstractions; using Microsoft.Extensions.PlatformAbstractions;
@ -130,12 +129,14 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddEnumerable( services.TryAddEnumerable(
ServiceDescriptor.Transient<IConfigureOptions<RazorViewEngineOptions>, RazorViewEngineOptionsSetup>()); ServiceDescriptor.Transient<IConfigureOptions<RazorViewEngineOptions>, RazorViewEngineOptionsSetup>());
services.TryAddSingleton<IRazorViewEngineFileProviderAccessor, DefaultRazorViewEngineFileProviderAccessor>();
services.TryAddSingleton<IRazorViewEngine, RazorViewEngine>(); services.TryAddSingleton<IRazorViewEngine, RazorViewEngine>();
services.TryAdd(ServiceDescriptor.Singleton<IChunkTreeCache>(serviceProvider => services.TryAdd(ServiceDescriptor.Singleton<IChunkTreeCache>(serviceProvider =>
{ {
var cachedFileProvider = serviceProvider.GetRequiredService<IOptions<RazorViewEngineOptions>>(); var accessor = serviceProvider.GetRequiredService<IRazorViewEngineFileProviderAccessor>();
return new DefaultChunkTreeCache(cachedFileProvider.Value.FileProvider); return new DefaultChunkTreeCache(accessor.FileProvider);
})); }));
// Caches compilation artifacts across the lifetime of the application. // Caches compilation artifacts across the lifetime of the application.

View File

@ -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
{
/// <summary>
/// Accessor to the <see cref="IFileProvider"/> used by <see cref="RazorViewEngine"/>.
/// </summary>
public interface IRazorViewEngineFileProviderAccessor
{
/// <summary>
/// Gets the <see cref="IFileProvider"/> used to look up Razor files.
/// </summary>
IFileProvider FileProvider { get; }
}
}

View File

@ -14,12 +14,9 @@ namespace Microsoft.AspNet.Mvc.Razor
/// </summary> /// </summary>
public class RazorViewEngineOptions public class RazorViewEngineOptions
{ {
private IFileProvider _fileProvider;
private CSharpParseOptions _parseOptions = new CSharpParseOptions(LanguageVersion.CSharp6); private CSharpParseOptions _parseOptions = new CSharpParseOptions(LanguageVersion.CSharp6);
private CSharpCompilationOptions _compilationOptions =
private CSharpCompilationOptions _compilationOptions = new CSharpCompilationOptions(CodeAnalysis.OutputKind.DynamicallyLinkedLibrary); new CSharpCompilationOptions(CodeAnalysis.OutputKind.DynamicallyLinkedLibrary);
private Action<RoslynCompilationContext> _compilationCallback = c => { }; private Action<RoslynCompilationContext> _compilationCallback = c => { };
/// <summary> /// <summary>
@ -29,33 +26,22 @@ namespace Microsoft.AspNet.Mvc.Razor
= new List<IViewLocationExpander>(); = new List<IViewLocationExpander>();
/// <summary> /// <summary>
/// Gets or sets the <see cref="IFileProvider" /> used by <see cref="RazorViewEngine"/> to locate Razor files on /// Gets the sequence of <see cref="IFileProvider" /> instances used by <see cref="RazorViewEngine"/> to
/// disk. /// locate Razor files.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// At startup, this is initialized to an instance of <see cref="PhysicalFileProvider"/> that is rooted at the /// At startup, this is initialized to include an instance of <see cref="PhysicalFileProvider"/> that is
/// application root. /// rooted at the application root.
/// </remarks> /// </remarks>
public IFileProvider FileProvider public IList<IFileProvider> FileProviders { get; } = new List<IFileProvider>();
{
get { return _fileProvider; }
set
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
_fileProvider = value;
}
}
/// <summary> /// <summary>
/// Gets or sets the callback that is used to customize Razor compilation /// Gets or sets the callback that is used to customize Razor compilation
/// to change compilation settings you can update <see cref="RoslynCompilationContext.Compilation"/> property. /// to change compilation settings you can update <see cref="RoslynCompilationContext.Compilation"/> property.
/// Customizations made here would not reflect in tooling (Intellisense).
/// </summary> /// </summary>
/// <remarks>
/// Customizations made here would not reflect in tooling (Intellisense).
/// </remarks>
public Action<RoslynCompilationContext> CompilationCallback public Action<RoslynCompilationContext> CompilationCallback
{ {
get { return _compilationCallback; } get { return _compilationCallback; }
@ -65,6 +51,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
throw new ArgumentNullException(nameof(value)); throw new ArgumentNullException(nameof(value));
} }
_compilationCallback = value; _compilationCallback = value;
} }
} }
@ -81,6 +68,7 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
throw new ArgumentNullException(nameof(value)); throw new ArgumentNullException(nameof(value));
} }
_parseOptions = value; _parseOptions = value;
} }
} }
@ -97,9 +85,9 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
throw new ArgumentNullException(nameof(value)); throw new ArgumentNullException(nameof(value));
} }
_compilationOptions = value; _compilationOptions = value;
} }
} }
} }
} }

View File

@ -31,7 +31,7 @@ namespace Microsoft.AspNet.Mvc
IApplicationEnvironment applicationEnvironment, IApplicationEnvironment applicationEnvironment,
IHostingEnvironment hostingEnvironment) IHostingEnvironment hostingEnvironment)
{ {
razorOptions.FileProvider = new PhysicalFileProvider(applicationEnvironment.ApplicationBasePath); razorOptions.FileProviders.Add(new PhysicalFileProvider(applicationEnvironment.ApplicationBasePath));
var parseOptions = new CSharpParseOptions(LanguageVersion.CSharp6); var parseOptions = new CSharpParseOptions(LanguageVersion.CSharp6);
var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary); var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);

View File

@ -10,6 +10,7 @@
"keyFile": "../../tools/Key.snk" "keyFile": "../../tools/Key.snk"
}, },
"dependencies": { "dependencies": {
"Microsoft.AspNet.FileProviders.Composite": "1.0.0-*",
"Microsoft.AspNet.Mvc.Razor.Host": "6.0.0-*", "Microsoft.AspNet.Mvc.Razor.Host": "6.0.0-*",
"Microsoft.AspNet.Mvc.ViewFeatures": "6.0.0-*", "Microsoft.AspNet.Mvc.ViewFeatures": "6.0.0-*",
"Microsoft.AspNet.Razor.Runtime.Precompilation": "4.0.0-*", "Microsoft.AspNet.Razor.Runtime.Precompilation": "4.0.0-*",
@ -26,8 +27,7 @@
"type": "build" "type": "build"
}, },
"Microsoft.Dnx.Compilation.CSharp.Common": "1.0.0-*", "Microsoft.Dnx.Compilation.CSharp.Common": "1.0.0-*",
"Microsoft.Dnx.Compilation.CSharp.Abstractions": "1.0.0-*", "Microsoft.Dnx.Compilation.CSharp.Abstractions": "1.0.0-*"
"Microsoft.Extensions.MemoryPool": "1.0.0-*"
}, },
"frameworks": { "frameworks": {
"net451": { "net451": {

View File

@ -38,7 +38,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
compiler.Setup(c => c.Compile(relativeFileInfo, It.IsAny<string>())) compiler.Setup(c => c.Compile(relativeFileInfo, It.IsAny<string>()))
.Returns(new CompilationResult(typeof(RazorCompilationServiceTest))); .Returns(new CompilationResult(typeof(RazorCompilationServiceTest)));
var razorService = new RazorCompilationService(compiler.Object, host.Object, GetOptions()); var razorService = new RazorCompilationService(compiler.Object, host.Object, GetFileProviderAccessor());
// Act // Act
razorService.Compile(relativeFileInfo); razorService.Compile(relativeFileInfo);
@ -70,7 +70,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
var compiler = new Mock<ICompilationService>(MockBehavior.Strict); var compiler = new Mock<ICompilationService>(MockBehavior.Strict);
var relativeFileInfo = new RelativeFileInfo(fileInfo.Object, @"Views\index\home.cshtml"); 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 // Act
var result = razorService.Compile(relativeFileInfo); var result = razorService.Compile(relativeFileInfo);
@ -111,7 +111,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
compiler.Setup(c => c.Compile(relativeFileInfo, code)) compiler.Setup(c => c.Compile(relativeFileInfo, code))
.Returns(compilationResult) .Returns(compilationResult)
.Verifiable(); .Verifiable();
var razorService = new RazorCompilationService(compiler.Object, host.Object, GetOptions()); var razorService = new RazorCompilationService(compiler.Object, host.Object, GetFileProviderAccessor());
// Act // Act
var result = razorService.Compile(relativeFileInfo); var result = razorService.Compile(relativeFileInfo);
@ -136,7 +136,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
var razorService = new RazorCompilationService( var razorService = new RazorCompilationService(
Mock.Of<ICompilationService>(), Mock.Of<ICompilationService>(),
Mock.Of<IMvcRazorHost>(), Mock.Of<IMvcRazorHost>(),
GetOptions(fileProvider)); GetFileProviderAccessor(fileProvider));
var errors = new[] var errors = new[]
{ {
new RazorError("message-1", new SourceLocation(1, 2, 17), length: 1), new RazorError("message-1", new SourceLocation(1, 2, 17), length: 1),
@ -211,15 +211,11 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
new ChunkTree()); new ChunkTree());
} }
private static IOptions<RazorViewEngineOptions> GetOptions(IFileProvider fileProvider = null) private static IRazorViewEngineFileProviderAccessor GetFileProviderAccessor(IFileProvider fileProvider = null)
{ {
var razorViewEngineOptions = new RazorViewEngineOptions var options = new Mock<IRazorViewEngineFileProviderAccessor>();
{ options.SetupGet(o => o.FileProvider)
FileProvider = fileProvider ?? new TestFileProvider() .Returns(fileProvider ?? new TestFileProvider());
};
var options = new Mock<IOptions<RazorViewEngineOptions>>();
options.SetupGet(o => o.Value)
.Returns(razorViewEngineOptions);
return options.Object; return options.Object;
} }

View File

@ -2,11 +2,9 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Runtime.Versioning;
using Microsoft.AspNet.FileProviders; using Microsoft.AspNet.FileProviders;
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text;
using Microsoft.Dnx.Runtime;
using Microsoft.Extensions.CompilationAbstractions; using Microsoft.Extensions.CompilationAbstractions;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.Extensions.PlatformAbstractions; using Microsoft.Extensions.PlatformAbstractions;
@ -35,7 +33,8 @@ public class MyTestType {}";
applicationEnvironment, applicationEnvironment,
libraryExporter, libraryExporter,
mvcRazorHost.Object, mvcRazorHost.Object,
GetOptions()); GetOptions(),
GetFileProviderAccessor());
var relativeFileInfo = new RelativeFileInfo( var relativeFileInfo = new RelativeFileInfo(
new TestFileInfo { PhysicalPath = "SomePath" }, new TestFileInfo { PhysicalPath = "SomePath" },
"some-relative-path"); "some-relative-path");
@ -66,7 +65,8 @@ this should fail";
applicationEnvironment, applicationEnvironment,
libraryExporter, libraryExporter,
mvcRazorHost, mvcRazorHost,
GetOptions(fileProvider)); GetOptions(),
GetFileProviderAccessor(fileProvider));
var relativeFileInfo = new RelativeFileInfo(fileInfo, "some-relative-path"); var relativeFileInfo = new RelativeFileInfo(fileInfo, "some-relative-path");
// Act // Act
@ -94,7 +94,8 @@ this should fail";
applicationEnvironment, applicationEnvironment,
libraryExporter, libraryExporter,
mvcRazorHost, mvcRazorHost,
GetOptions()); GetOptions(),
GetFileProviderAccessor());
var relativeFileInfo = new RelativeFileInfo( var relativeFileInfo = new RelativeFileInfo(
new TestFileInfo { Content = fileContent }, new TestFileInfo { Content = fileContent },
"some-relative-path"); "some-relative-path");
@ -125,7 +126,7 @@ this should fail";
var mockFileInfo = new Mock<IFileInfo>(); var mockFileInfo = new Mock<IFileInfo>();
mockFileInfo.Setup(f => f.CreateReadStream()) mockFileInfo.Setup(f => f.CreateReadStream())
.Throws(new Exception()); .Throws(new Exception());
var fileProvider = new TestFileProvider(); var fileProvider = new TestFileProvider();
fileProvider.AddFile(path, mockFileInfo.Object); fileProvider.AddFile(path, mockFileInfo.Object);
@ -133,7 +134,8 @@ this should fail";
applicationEnvironment, applicationEnvironment,
libraryExporter, libraryExporter,
mvcRazorHost, mvcRazorHost,
GetOptions(fileProvider)); GetOptions(),
GetFileProviderAccessor(fileProvider));
var relativeFileInfo = new RelativeFileInfo(mockFileInfo.Object, path); var relativeFileInfo = new RelativeFileInfo(mockFileInfo.Object, path);
@ -163,7 +165,7 @@ public class MyNonCustomDefinedClass {}
var libraryExporter = CompilationServices.Default.LibraryExporter; var libraryExporter = CompilationServices.Default.LibraryExporter;
var mvcRazorHost = new Mock<IMvcRazorHost>(); var mvcRazorHost = new Mock<IMvcRazorHost>();
mvcRazorHost.SetupGet(m => m.MainClassNamePrefix) mvcRazorHost.SetupGet(m => m.MainClassNamePrefix)
.Returns("My"); .Returns("My");
var options = GetOptions(); var options = GetOptions();
options.Value.ParseOptions = options.Value.ParseOptions.WithPreprocessorSymbols("MY_CUSTOM_DEFINE"); options.Value.ParseOptions = options.Value.ParseOptions.WithPreprocessorSymbols("MY_CUSTOM_DEFINE");
@ -172,7 +174,8 @@ public class MyNonCustomDefinedClass {}
applicationEnvironment, applicationEnvironment,
libraryExporter, libraryExporter,
mvcRazorHost.Object, mvcRazorHost.Object,
options); options,
GetFileProviderAccessor());
var relativeFileInfo = new RelativeFileInfo( var relativeFileInfo = new RelativeFileInfo(
new TestFileInfo { PhysicalPath = "SomePath" }, new TestFileInfo { PhysicalPath = "SomePath" },
"some-relative-path"); "some-relative-path");
@ -202,7 +205,8 @@ public class NotRazorPrefixType {}";
applicationEnvironment, applicationEnvironment,
libraryExporter, libraryExporter,
mvcRazorHost.Object, mvcRazorHost.Object,
GetOptions()); GetOptions(),
GetFileProviderAccessor());
var relativeFileInfo = new RelativeFileInfo( var relativeFileInfo = new RelativeFileInfo(
new TestFileInfo { PhysicalPath = "SomePath" }, new TestFileInfo { PhysicalPath = "SomePath" },
@ -224,17 +228,17 @@ public class NotRazorPrefixType {}";
var generatedCodeFileName = "Generated Code"; var generatedCodeFileName = "Generated Code";
var fileProvider = new TestFileProvider(); var fileProvider = new TestFileProvider();
fileProvider.AddFile(viewPath, "view-content"); fileProvider.AddFile(viewPath, "view-content");
var options = new Mock<IOptions<RazorViewEngineOptions>>(); var options = new RazorViewEngineOptions();
options.SetupGet(o => o.Value) options.FileProviders.Add(fileProvider);
.Returns(new RazorViewEngineOptions var optionsAccessor = new Mock<IOptions<RazorViewEngineOptions>>();
{ optionsAccessor.SetupGet(o => o.Value)
FileProvider = fileProvider .Returns(options);
});
var compilationService = new RoslynCompilationService( var compilationService = new RoslynCompilationService(
PlatformServices.Default.Application, PlatformServices.Default.Application,
CompilationServices.Default.LibraryExporter, CompilationServices.Default.LibraryExporter,
Mock.Of<IMvcRazorHost>(), Mock.Of<IMvcRazorHost>(),
options.Object); optionsAccessor.Object,
GetFileProviderAccessor(fileProvider));
var assemblyName = "random-assembly-name"; var assemblyName = "random-assembly-name";
@ -325,7 +329,8 @@ public class NotRazorPrefixType {}";
applicationEnvironment, applicationEnvironment,
libraryExporter, libraryExporter,
mvcRazorHost.Object, mvcRazorHost.Object,
GetOptions(callback: c => usedCompilation = c)); GetOptions(callback: c => usedCompilation = c),
GetFileProviderAccessor());
var relativeFileInfo = new RelativeFileInfo( var relativeFileInfo = new RelativeFileInfo(
new TestFileInfo { PhysicalPath = "SomePath" }, new TestFileInfo { PhysicalPath = "SomePath" },
@ -350,13 +355,11 @@ public class NotRazorPrefixType {}";
isEnabledByDefault: true); isEnabledByDefault: true);
} }
private static IOptions<RazorViewEngineOptions> GetOptions(IFileProvider fileProvider = null, private static IOptions<RazorViewEngineOptions> GetOptions(Action<RoslynCompilationContext> callback = null)
Action<RoslynCompilationContext> callback = null)
{ {
var razorViewEngineOptions = new RazorViewEngineOptions var razorViewEngineOptions = new RazorViewEngineOptions
{ {
FileProvider = fileProvider ?? new TestFileProvider(), CompilationCallback = callback ?? (c => { }),
CompilationCallback = callback ?? (c => { })
}; };
var options = new Mock<IOptions<RazorViewEngineOptions>>(); var options = new Mock<IOptions<RazorViewEngineOptions>>();
options options
@ -365,5 +368,14 @@ public class NotRazorPrefixType {}";
return options.Object; return options.Object;
} }
private IRazorViewEngineFileProviderAccessor GetFileProviderAccessor(IFileProvider fileProvider = null)
{
var options = new Mock<IRazorViewEngineFileProviderAccessor>();
options.SetupGet(o => o.FileProvider)
.Returns(fileProvider ?? new TestFileProvider());
return options.Object;
}
} }
} }

View File

@ -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<IOptions<RazorViewEngineOptions>>();
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<IOptions<RazorViewEngineOptions>>();
optionsAccessor.SetupGet(o => o.Value).Returns(options);
var fileProviderAccessor = new DefaultRazorViewEngineFileProviderAccessor(optionsAccessor.Object);
// Act
var actual = fileProviderAccessor.FileProvider;
// Assert
Assert.IsType<CompositeFileProvider>(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<IOptions<RazorViewEngineOptions>>();
optionsAccessor.SetupGet(o => o.Value).Returns(options);
var fileProviderAccessor = new DefaultRazorViewEngineFileProviderAccessor(optionsAccessor.Object);
// Act
var actual = fileProviderAccessor.FileProvider;
// Assert
Assert.IsType<CompositeFileProvider>(actual);
}
}
}

View File

@ -1,7 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // 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.AspNet.Mvc.Internal;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@ -12,18 +11,7 @@ namespace Microsoft.AspNet.Mvc.Razor
public class RazorViewEngineOptionsTest public class RazorViewEngineOptionsTest
{ {
[Fact] [Fact]
public void FileProviderThrows_IfNullIsAssigned() public void AddRazorOptions_ConfiguresOptionsAsExpected()
{
// Arrange
var options = new RazorViewEngineOptions();
// Act and Assert
var ex = Assert.Throws<ArgumentNullException>(() => options.FileProvider = null);
Assert.Equal("value", ex.ParamName);
}
[Fact]
public void AddRazorOptions_ConfiguresOptionsProperly()
{ {
// Arrange // Arrange
var services = new ServiceCollection().AddOptions(); var services = new ServiceCollection().AddOptions();
@ -33,13 +21,13 @@ namespace Microsoft.AspNet.Mvc.Razor
var builder = new MvcBuilder(services); var builder = new MvcBuilder(services);
builder.AddRazorOptions(options => builder.AddRazorOptions(options =>
{ {
options.FileProvider = fileProvider; options.FileProviders.Add(fileProvider);
}); });
var serviceProvider = services.BuildServiceProvider(); var serviceProvider = services.BuildServiceProvider();
// Assert // Assert
var accessor = serviceProvider.GetRequiredService<IOptions<RazorViewEngineOptions>>(); var accessor = serviceProvider.GetRequiredService<IOptions<RazorViewEngineOptions>>();
Assert.Same(fileProvider, accessor.Value.FileProvider); Assert.Same(fileProvider, accessor.Value.FileProviders[0]);
} }
} }
} }

View File

@ -21,18 +21,18 @@ namespace Microsoft.AspNet.Mvc
var options = new RazorViewEngineOptions(); var options = new RazorViewEngineOptions();
var appEnv = new Mock<IApplicationEnvironment>(); var appEnv = new Mock<IApplicationEnvironment>();
appEnv.SetupGet(e => e.ApplicationBasePath) appEnv.SetupGet(e => e.ApplicationBasePath)
.Returns(Directory.GetCurrentDirectory()); .Returns(Directory.GetCurrentDirectory());
var hostingEnv = new Mock<IHostingEnvironment>(); var hostingEnv = new Mock<IHostingEnvironment>();
hostingEnv.SetupGet(e => e.EnvironmentName) hostingEnv.SetupGet(e => e.EnvironmentName)
.Returns("Development"); .Returns("Development");
var optionsSetup = new RazorViewEngineOptionsSetup(appEnv.Object, hostingEnv.Object); var optionsSetup = new RazorViewEngineOptionsSetup(appEnv.Object, hostingEnv.Object);
// Act // Act
optionsSetup.Configure(options); optionsSetup.Configure(options);
// Assert // Assert
Assert.NotNull(options.FileProvider); var fileProvider = Assert.Single(options.FileProviders);
Assert.IsType<PhysicalFileProvider>(options.FileProvider); Assert.IsType<PhysicalFileProvider>(fileProvider);
} }
[Theory] [Theory]
@ -62,7 +62,9 @@ namespace Microsoft.AspNet.Mvc
[InlineData("Development", OptimizationLevel.Debug)] [InlineData("Development", OptimizationLevel.Debug)]
[InlineData("Staging", OptimizationLevel.Release)] [InlineData("Staging", OptimizationLevel.Release)]
[InlineData("Production", OptimizationLevel.Release)] [InlineData("Production", OptimizationLevel.Release)]
public void RazorViewEngineOptionsSetup_SetsOptimizationLevel(string environment, OptimizationLevel expectedOptimizationLevel) public void RazorViewEngineOptionsSetup_SetsOptimizationLevel(
string environment,
OptimizationLevel expectedOptimizationLevel)
{ {
// Arrange // Arrange
var options = new RazorViewEngineOptions(); var options = new RazorViewEngineOptions();

View File

@ -6,7 +6,6 @@ using System.Text;
using Microsoft.AspNet.Mvc.Razor; using Microsoft.AspNet.Mvc.Razor;
using Microsoft.AspNet.Mvc.Razor.Compilation; using Microsoft.AspNet.Mvc.Razor.Compilation;
using Microsoft.AspNet.Razor.CodeGenerators; using Microsoft.AspNet.Razor.CodeGenerators;
using Microsoft.Extensions.Options;
namespace RazorPageExecutionInstrumentationWebSite namespace RazorPageExecutionInstrumentationWebSite
{ {
@ -15,8 +14,8 @@ namespace RazorPageExecutionInstrumentationWebSite
public TestRazorCompilationService( public TestRazorCompilationService(
ICompilationService compilationService, ICompilationService compilationService,
IMvcRazorHost razorHost, IMvcRazorHost razorHost,
IOptions<RazorViewEngineOptions> viewEngineOptions) IRazorViewEngineFileProviderAccessor fileProviderAccessor)
: base(compilationService, razorHost, viewEngineOptions) : base(compilationService, razorHost, fileProviderAccessor)
{ {
} }