diff --git a/Mvc.sln b/Mvc.sln index 276f95a909..152c44c231 100644 --- a/Mvc.sln +++ b/Mvc.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.23017.0 +VisualStudioVersion = 14.0.23107.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}" EndProject @@ -122,8 +122,6 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ControllersFromServicesWebS EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ControllersFromServicesClassLibrary", "test\WebSites\ControllersFromServicesClassLibrary\ControllersFromServicesClassLibrary.xproj", "{551DC89E-2A13-4CF2-83D7-1ADD802443D5}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "RazorCompilerCacheWebSite", "test\WebSites\RazorCompilerCacheWebSite\RazorCompilerCacheWebSite.xproj", "{42C5D417-4060-48F4-BB28-E9E179007779}" -EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.PageExecutionInstrumentation.Interfaces", "src\Microsoft.AspNet.PageExecutionInstrumentation.Interfaces\Microsoft.AspNet.PageExecutionInstrumentation.Interfaces.xproj", "{4DA2D7C1-A7B6-4C01-B57D-89E6EA4609DE}" EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "UserClassLibrary", "test\WebSites\UserClassLibrary\UserClassLibrary.xproj", "{C651F432-4EBE-41A6-BAD2-3E07CCBA209C}" @@ -758,18 +756,6 @@ Global {551DC89E-2A13-4CF2-83D7-1ADD802443D5}.Release|Mixed Platforms.Build.0 = Release|Any CPU {551DC89E-2A13-4CF2-83D7-1ADD802443D5}.Release|x86.ActiveCfg = Release|Any CPU {551DC89E-2A13-4CF2-83D7-1ADD802443D5}.Release|x86.Build.0 = Release|Any CPU - {42C5D417-4060-48F4-BB28-E9E179007779}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {42C5D417-4060-48F4-BB28-E9E179007779}.Debug|Any CPU.Build.0 = Debug|Any CPU - {42C5D417-4060-48F4-BB28-E9E179007779}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {42C5D417-4060-48F4-BB28-E9E179007779}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {42C5D417-4060-48F4-BB28-E9E179007779}.Debug|x86.ActiveCfg = Debug|Any CPU - {42C5D417-4060-48F4-BB28-E9E179007779}.Debug|x86.Build.0 = Debug|Any CPU - {42C5D417-4060-48F4-BB28-E9E179007779}.Release|Any CPU.ActiveCfg = Release|Any CPU - {42C5D417-4060-48F4-BB28-E9E179007779}.Release|Any CPU.Build.0 = Release|Any CPU - {42C5D417-4060-48F4-BB28-E9E179007779}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {42C5D417-4060-48F4-BB28-E9E179007779}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {42C5D417-4060-48F4-BB28-E9E179007779}.Release|x86.ActiveCfg = Release|Any CPU - {42C5D417-4060-48F4-BB28-E9E179007779}.Release|x86.Build.0 = Release|Any CPU {4DA2D7C1-A7B6-4C01-B57D-89E6EA4609DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4DA2D7C1-A7B6-4C01-B57D-89E6EA4609DE}.Debug|Any CPU.Build.0 = Debug|Any CPU {4DA2D7C1-A7B6-4C01-B57D-89E6EA4609DE}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU @@ -1213,7 +1199,6 @@ Global {AC9BE567-540E-4C70-90C2-AAF021307A80} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} {983741B2-4424-4ED1-9B03-7675A67230C8} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} {551DC89E-2A13-4CF2-83D7-1ADD802443D5} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} - {42C5D417-4060-48F4-BB28-E9E179007779} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} {4DA2D7C1-A7B6-4C01-B57D-89E6EA4609DE} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} {C651F432-4EBE-41A6-BAD2-3E07CCBA209C} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} {A19022EF-9BA3-4349-94E4-F48E13E1C8AE} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} diff --git a/src/Microsoft.AspNet.Mvc.Localization/project.json b/src/Microsoft.AspNet.Mvc.Localization/project.json index 73383b3511..b8e86d6abb 100644 --- a/src/Microsoft.AspNet.Mvc.Localization/project.json +++ b/src/Microsoft.AspNet.Mvc.Localization/project.json @@ -2,7 +2,7 @@ "description": "Features that enable globalization & localization of MVC applications.", "version": "6.0.0-*", "compilationOptions": { - "warningsAsErrors": false + "warningsAsErrors": true }, "dependencies": { "Microsoft.AspNet.Localization": "1.0.0-*", diff --git a/src/Microsoft.AspNet.Mvc.Razor/Compilation/CompilerCache.cs b/src/Microsoft.AspNet.Mvc.Razor/Compilation/CompilerCache.cs index 2220c1fe58..a403c39b2f 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/Compilation/CompilerCache.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/Compilation/CompilerCache.cs @@ -3,13 +3,9 @@ using System; using System.Collections.Generic; -using System.Reflection; using Microsoft.AspNet.FileProviders; -using Microsoft.AspNet.Mvc.Razor.Precompilation; -using Microsoft.Dnx.Runtime; using Microsoft.Framework.Caching.Memory; using Microsoft.Framework.Internal; -using Microsoft.Framework.OptionsModel; namespace Microsoft.AspNet.Mvc.Razor.Compilation { @@ -18,46 +14,36 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation /// public class CompilerCache : ICompilerCache { - private static readonly Assembly RazorHostAssembly = typeof(CompilerCache).GetTypeInfo().Assembly; private readonly IFileProvider _fileProvider; private readonly IMemoryCache _cache; /// - /// Initializes a new instance of populated with precompiled views - /// discovered using . + /// Initializes a new instance of . /// - /// The sequence of that provides - /// information for precompiled view discovery. - /// The . - /// An accessor to the . - public CompilerCache( - IEnumerable razorFileInfoCollections, - IAssemblyLoadContextAccessor loadContextAccessor, - IOptions optionsAccessor) - : this(razorFileInfoCollections, - loadContextAccessor.GetLoadContext(RazorHostAssembly), - optionsAccessor.Options.FileProvider) - { - } - - internal CompilerCache( - IEnumerable razorFileInfoCollections, - IAssemblyLoadContext loadContext, - IFileProvider fileProvider) + /// used to locate Razor views. + public CompilerCache([NotNull] IFileProvider fileProvider) { _fileProvider = fileProvider; _cache = new MemoryCache(new MemoryCacheOptions { CompactOnMemoryPressure = false }); + } - foreach (var viewCollection in razorFileInfoCollections) + /// + /// Initializes a new instance of populated with precompiled views + /// specified by . + /// + /// used to locate Razor views. + /// A mapping of application relative paths of view to the precompiled view + /// s. + public CompilerCache( + [NotNull] IFileProvider fileProvider, + [NotNull] IDictionary precompiledViews) + : this(fileProvider) + { + foreach (var item in precompiledViews) { - var containingAssembly = viewCollection.LoadAssembly(loadContext); - foreach (var fileInfo in viewCollection.FileInfos) - { - var viewType = containingAssembly.GetType(fileInfo.FullTypeName); - var cacheEntry = new CompilerCacheResult(CompilationResult.Successful(viewType)); - var normalizedPath = NormalizePath(fileInfo.RelativePath); - _cache.Set(normalizedPath, cacheEntry); - } + var cacheEntry = new CompilerCacheResult(CompilationResult.Successful(item.Value)); + var normalizedPath = NormalizePath(item.Key); + _cache.Set(normalizedPath, cacheEntry); } } diff --git a/src/Microsoft.AspNet.Mvc.Razor/Compilation/DefaultCompilerCacheProvider.cs b/src/Microsoft.AspNet.Mvc.Razor/Compilation/DefaultCompilerCacheProvider.cs new file mode 100644 index 0000000000..d915207518 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Razor/Compilation/DefaultCompilerCacheProvider.cs @@ -0,0 +1,26 @@ +// 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.Framework.OptionsModel; + +namespace Microsoft.AspNet.Mvc.Razor.Compilation +{ + /// + /// Default implementation for . + /// + public class DefaultCompilerCacheProvider : ICompilerCacheProvider + { + /// + /// Initializes a new instance of . + /// + /// An accessor to the . + public DefaultCompilerCacheProvider(IOptions mvcViewOptions) + { + var fileProvider = mvcViewOptions.Options.FileProvider; + Cache = new CompilerCache(fileProvider); + } + + /// + public ICompilerCache Cache { get; } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Razor/Compilation/ICompilerCacheProvider.cs b/src/Microsoft.AspNet.Mvc.Razor/Compilation/ICompilerCacheProvider.cs new file mode 100644 index 0000000000..85ef7710ac --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Razor/Compilation/ICompilerCacheProvider.cs @@ -0,0 +1,16 @@ +// 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. + +namespace Microsoft.AspNet.Mvc.Razor.Compilation +{ + /// + /// Provides access to a cached instance. + /// + public interface ICompilerCacheProvider + { + /// + /// The cached instance. + /// + ICompilerCache Cache { get; } + } +} diff --git a/src/Microsoft.AspNet.Mvc.Razor/Compilation/PrecompiledViewsCompilerCacheProvider.cs b/src/Microsoft.AspNet.Mvc.Razor/Compilation/PrecompiledViewsCompilerCacheProvider.cs new file mode 100644 index 0000000000..d9c2e19f89 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Razor/Compilation/PrecompiledViewsCompilerCacheProvider.cs @@ -0,0 +1,109 @@ +// 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 System.Threading; +using Microsoft.AspNet.FileProviders; +using Microsoft.AspNet.Mvc.Razor.Precompilation; +using Microsoft.Dnx.Runtime; +using Microsoft.Framework.OptionsModel; + +namespace Microsoft.AspNet.Mvc.Razor.Compilation +{ + /// + /// An that provides a instance + /// populated with precompiled views. + /// + public class PrecompiledViewsCompilerCacheProvider : ICompilerCacheProvider + { + private static readonly Assembly RazorAssembly = typeof(DefaultCompilerCacheProvider).GetTypeInfo().Assembly; + private static readonly Type RazorFileInfoCollectionType = typeof(RazorFileInfoCollection); + private readonly Func _createCache; + private readonly IAssemblyLoadContextAccessor _loadContextAccessor; + private readonly IFileProvider _fileProvider; + private readonly Assembly[] _assemblies; + + private object _cacheLock = new object(); + private bool _cacheInitialized; + private ICompilerCache _compilerCache; + + /// + /// Initializes a new instance of . + /// + /// The . + /// An accessor to the . + /// instances to scan for precompiled views. + public PrecompiledViewsCompilerCacheProvider( + IAssemblyLoadContextAccessor loadContextAccessor, + IOptions mvcViewOptions, + IEnumerable assemblies) + { + _loadContextAccessor = loadContextAccessor; + _fileProvider = mvcViewOptions.Options.FileProvider; + _createCache = CreateCache; + _assemblies = assemblies.ToArray(); + } + + /// + public ICompilerCache Cache + { + get + { + return LazyInitializer.EnsureInitialized( + ref _compilerCache, + ref _cacheInitialized, + ref _cacheLock, + _createCache); + } + } + + private ICompilerCache CreateCache() + { + var razorFileInfoCollections = GetFileInfoCollections(_assemblies); + var loadContext = _loadContextAccessor.GetLoadContext(RazorAssembly); + var precompiledViews = GetPrecompiledViews(razorFileInfoCollections, loadContext); + + return new CompilerCache(_fileProvider, precompiledViews); + } + + // Internal for unit testing + internal static Dictionary GetPrecompiledViews( + IEnumerable razorFileInfoCollections, + IAssemblyLoadContext loadContext) + { + var precompiledViews = new Dictionary(StringComparer.OrdinalIgnoreCase); + + foreach (var viewCollection in razorFileInfoCollections) + { + var containingAssembly = viewCollection.LoadAssembly(loadContext); + foreach (var fileInfo in viewCollection.FileInfos) + { + var viewType = containingAssembly.GetType(fileInfo.FullTypeName); + precompiledViews[fileInfo.RelativePath] = viewType; + } + } + + return precompiledViews; + } + + private static IEnumerable GetFileInfoCollections(IEnumerable assemblies) + { + return assemblies + .SelectMany(assembly => assembly.ExportedTypes) + .Where(IsValidRazorFileInfoCollection) + .Select(Activator.CreateInstance) + .Cast(); + } + + internal static bool IsValidRazorFileInfoCollection(Type type) + { + return + RazorFileInfoCollectionType.IsAssignableFrom(type) && + !type.GetTypeInfo().IsAbstract && + !type.GetTypeInfo().ContainsGenericParameters; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Razor/DependencyInjection/MvcRazorMvcBuilderExtensions.cs b/src/Microsoft.AspNet.Mvc.Razor/DependencyInjection/MvcRazorMvcBuilderExtensions.cs index 79a7e10250..e1413b5cf2 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/DependencyInjection/MvcRazorMvcBuilderExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/DependencyInjection/MvcRazorMvcBuilderExtensions.cs @@ -2,10 +2,11 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Linq; using System.Reflection; using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc.Razor; -using Microsoft.AspNet.Mvc.Razor.Internal; +using Microsoft.AspNet.Mvc.Razor.Compilation; using Microsoft.AspNet.Razor.Runtime.TagHelpers; using Microsoft.Framework.DependencyInjection.Extensions; using Microsoft.Framework.Internal; @@ -53,13 +54,17 @@ namespace Microsoft.Framework.DependencyInjection return builder; } - + public static IMvcBuilder AddPrecompiledRazorViews( [NotNull] this IMvcBuilder builder, [NotNull] params Assembly[] assemblies) { - var razorFileInfos = RazorFileInfoCollections.GetFileInfoCollections(assemblies); - builder.Services.TryAddEnumerable(ServiceDescriptor.Instance(razorFileInfos)); + builder.Services.Replace( + ServiceDescriptor.Singleton(serviceProvider => + ActivatorUtilities.CreateInstance( + serviceProvider, + assemblies.AsEnumerable()))); + return builder; } } diff --git a/src/Microsoft.AspNet.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs b/src/Microsoft.AspNet.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs index 8bf9a42c91..bd7dfe694d 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/DependencyInjection/MvcRazorMvcCoreBuilderExtensions.cs @@ -2,12 +2,12 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Linq; using System.Reflection; using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc.Razor; using Microsoft.AspNet.Mvc.Razor.Compilation; using Microsoft.AspNet.Mvc.Razor.Directives; -using Microsoft.AspNet.Mvc.Razor.Internal; using Microsoft.AspNet.Razor.Runtime.TagHelpers; using Microsoft.Framework.Caching.Memory; using Microsoft.Framework.DependencyInjection.Extensions; @@ -46,8 +46,11 @@ namespace Microsoft.Framework.DependencyInjection { AddRazorViewEngine(builder); - var razorFileInfos = RazorFileInfoCollections.GetFileInfoCollections(assemblies); - builder.Services.TryAddEnumerable(ServiceDescriptor.Instance(razorFileInfos)); + builder.Services.Replace( + ServiceDescriptor.Singleton(serviceProvider => + ActivatorUtilities.CreateInstance( + serviceProvider, + assemblies.AsEnumerable()))); return builder; } @@ -97,7 +100,7 @@ namespace Microsoft.Framework.DependencyInjection services.TryAddTransient(); // Caches compilation artifacts across the lifetime of the application. - services.TryAddSingleton(); + services.TryAddSingleton(); // This caches compilation related details that are valid across the lifetime of the application // and is required to be a singleton. diff --git a/src/Microsoft.AspNet.Mvc.Razor/Internal/RazorFileInfoCollections.cs b/src/Microsoft.AspNet.Mvc.Razor/Internal/RazorFileInfoCollections.cs deleted file mode 100644 index b7bb454743..0000000000 --- a/src/Microsoft.AspNet.Mvc.Razor/Internal/RazorFileInfoCollections.cs +++ /dev/null @@ -1,34 +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.AspNet.Mvc.Razor.Precompilation; - -namespace Microsoft.AspNet.Mvc.Razor.Internal -{ - public static class RazorFileInfoCollections - { - private static readonly Type RazorFileInfoCollectionType = typeof(RazorFileInfoCollection); - - public static IEnumerable GetFileInfoCollections(IEnumerable assemblies) - { - return assemblies - .SelectMany(assembly => assembly.ExportedTypes) - .Where(IsValidRazorFileInfoCollection) - .Select(Activator.CreateInstance) - .Cast(); - } - - - public static bool IsValidRazorFileInfoCollection(Type type) - { - return - RazorFileInfoCollectionType.IsAssignableFrom(type) && - !type.GetTypeInfo().IsAbstract && - !type.GetTypeInfo().ContainsGenericParameters; - } - } -} diff --git a/src/Microsoft.AspNet.Mvc.Razor/VirtualPathRazorPageFactory.cs b/src/Microsoft.AspNet.Mvc.Razor/VirtualPathRazorPageFactory.cs index 0f663c5a9f..93cc6e578b 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/VirtualPathRazorPageFactory.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/VirtualPathRazorPageFactory.cs @@ -15,14 +15,21 @@ namespace Microsoft.AspNet.Mvc.Razor public class VirtualPathRazorPageFactory : IRazorPageFactory { private readonly IServiceProvider _serviceProvider; - private readonly ICompilerCache _compilerCache; + private readonly ICompilerCacheProvider _compilerCacheProvider; private IRazorCompilationService _razorcompilationService; + private ICompilerCache _compilerCache; - public VirtualPathRazorPageFactory(IServiceProvider serviceProvider, - ICompilerCache compilerCache) + /// + /// Initializes a new instance of . + /// + /// The request specific . + /// The . + public VirtualPathRazorPageFactory( + IServiceProvider serviceProvider, + ICompilerCacheProvider compilerCacheProvider) { _serviceProvider = serviceProvider; - _compilerCache = compilerCache; + _compilerCacheProvider = compilerCacheProvider; } private IRazorCompilationService RazorCompilationService @@ -41,6 +48,19 @@ namespace Microsoft.AspNet.Mvc.Razor } } + private ICompilerCache CompilerCache + { + get + { + if (_compilerCache == null) + { + _compilerCache = _compilerCacheProvider.Cache; + } + + return _compilerCache; + } + } + /// public IRazorPage CreateInstance([NotNull] string relativePath) { @@ -50,7 +70,7 @@ namespace Microsoft.AspNet.Mvc.Razor relativePath = relativePath.Substring(1); } - var result = _compilerCache.GetOrAdd( + var result = CompilerCache.GetOrAdd( relativePath, RazorCompilationService.Compile); diff --git a/src/Microsoft.AspNet.Mvc.Razor/project.json b/src/Microsoft.AspNet.Mvc.Razor/project.json index 1c5589b3ef..e798e0c7ca 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/project.json +++ b/src/Microsoft.AspNet.Mvc.Razor/project.json @@ -6,7 +6,7 @@ "url": "git://github.com/aspnet/mvc" }, "compilationOptions": { - "warningsAsErrors": false + "warningsAsErrors": true }, "dependencies": { "Microsoft.AspNet.Mvc.Razor.Host": "6.0.0-*", diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/RazorCompilerCacheTest.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/RazorCompilerCacheTest.cs deleted file mode 100644 index 3313531cd2..0000000000 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/RazorCompilerCacheTest.cs +++ /dev/null @@ -1,49 +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.Net; -using System.Threading.Tasks; -using Microsoft.AspNet.Builder; -using Microsoft.Framework.DependencyInjection; -using RazorCompilerCacheWebSite; -using Xunit; - -namespace Microsoft.AspNet.Mvc.FunctionalTests -{ - public class RazorCompilerCacheTest - { - private const string SiteName = nameof(RazorCompilerCacheWebSite); - private readonly Action _app = new Startup().Configure; - private readonly Action _configureServices = new Startup().ConfigureServices; - - [Fact] - public async Task CompilerCache_IsNotInitializedUntilFirstViewRequest() - { - // Arrange - var server = TestHelper.CreateServer(_app, SiteName, _configureServices); - var client = server.CreateClient(); - client.BaseAddress = new Uri("http://localhost"); - - // Act - 1 - // Visit a sampling of controller actions that do not produce ViewResult - var result1 = await client.GetAsync("/file"); - var result2 = await client.GetAsync("/statuscode"); - var result3 = await client.GetStringAsync("/cache-status"); - - // Assert - 1 - Assert.Equal(HttpStatusCode.OK, result1.StatusCode); - Assert.Equal(HttpStatusCode.OK, result2.StatusCode); - // Ensure the cache was not initialized. - Assert.Equal(bool.FalseString, result3); - - // Act - 2 - var result4 = await client.GetStringAsync("/view"); - var result5 = await client.GetStringAsync("/cache-status"); - - // Assert - 2 - Assert.Equal("Hello from view!", result4); - Assert.Equal(bool.TrueString, result5); - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json b/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json index 5d685a8250..e1dd8e5ccc 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json @@ -49,7 +49,6 @@ "ModelBindingWebSite": "1.0.0", "MvcSample.Web": "1.0.0", "PrecompilationWebSite": "1.0.0", - "RazorCompilerCacheWebSite": "1.0.0", "RazorEmbeddedViewsWebSite": "1.0.0", "RazorPageExecutionInstrumentationWebSite": "1.0.0", "RazorWebSite": "1.0.0", diff --git a/test/Microsoft.AspNet.Mvc.Razor.Test/Compilation/CompilerCacheTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Test/Compilation/CompilerCacheTest.cs index fc1388ffbd..fa3d74895d 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Test/Compilation/CompilerCacheTest.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Test/Compilation/CompilerCacheTest.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Reflection; using Microsoft.AspNet.Mvc.Razor.Precompilation; using Microsoft.Dnx.Runtime; @@ -17,7 +16,10 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation { private const string ViewPath = "Views/Home/Index.cshtml"; private const string PrecompiledViewsPath = "Views/Home/Precompiled.cshtml"; - private readonly IAssemblyLoadContext TestLoadContext = Mock.Of(); + private readonly IDictionary _precompiledViews = new Dictionary + { + { PrecompiledViewsPath, typeof(PreCompile) } + }; public static TheoryData ViewImportsPaths => new TheoryData @@ -32,7 +34,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation { // Arrange var fileProvider = new TestFileProvider(); - var cache = new CompilerCache(Enumerable.Empty(), TestLoadContext, fileProvider); + var cache = new CompilerCache(fileProvider); // Act var result = cache.GetOrAdd("/some/path", ThrowsIfCalled); @@ -48,7 +50,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation // Arrange var fileProvider = new TestFileProvider(); fileProvider.AddFile(ViewPath, "some content"); - var cache = new CompilerCache(Enumerable.Empty(), TestLoadContext, fileProvider); + var cache = new CompilerCache(fileProvider); var type = typeof(TestView); var expected = UncachedCompilationResult.Successful(type, "hello world"); @@ -70,7 +72,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation // Arrange var fileProvider = new TestFileProvider(); fileProvider.AddFile(ViewPath, "some content"); - var cache = new CompilerCache(Enumerable.Empty(), TestLoadContext, fileProvider); + var cache = new CompilerCache(fileProvider); var type = typeof(TestView); var expected = UncachedCompilationResult.Successful(type, "hello world"); @@ -98,7 +100,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation // Arrange var fileProvider = new TestFileProvider(); fileProvider.AddFile(ViewPath, "some content"); - var cache = new CompilerCache(Enumerable.Empty(), TestLoadContext, fileProvider); + var cache = new CompilerCache(fileProvider); var expected1 = UncachedCompilationResult.Successful(typeof(TestView), "hello world"); var expected2 = UncachedCompilationResult.Successful(typeof(DifferentView), "different content"); @@ -133,7 +135,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation // Arrange var fileProvider = new TestFileProvider(); fileProvider.AddFile(ViewPath, "some content"); - var cache = new CompilerCache(Enumerable.Empty(), TestLoadContext, fileProvider); + var cache = new CompilerCache(fileProvider); var expected1 = UncachedCompilationResult.Successful(typeof(TestView), "hello world"); var expected2 = UncachedCompilationResult.Successful(typeof(DifferentView), "different content"); @@ -168,7 +170,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation var mockFileProvider = new Mock { CallBase = true }; var fileProvider = mockFileProvider.Object; fileProvider.AddFile(ViewPath, "some content"); - var cache = new CompilerCache(Enumerable.Empty(), TestLoadContext, fileProvider); + var cache = new CompilerCache(fileProvider); var type = typeof(TestView); var expected = UncachedCompilationResult.Successful(type, "hello world"); @@ -194,7 +196,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation { // Arrange var fileProvider = new TestFileProvider(); - var cache = new CompilerCache(new[] { new TestViewCollection() }, TestLoadContext, fileProvider); + var cache = new CompilerCache(fileProvider, _precompiledViews); // Act var result = cache.GetOrAdd(PrecompiledViewsPath, ThrowsIfCalled); @@ -209,7 +211,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation { // Arrange var fileProvider = new TestFileProvider(); - var cache = new CompilerCache(new[] { new TestViewCollection() }, TestLoadContext, fileProvider); + var cache = new CompilerCache(fileProvider, _precompiledViews); // Act fileProvider.Watch(PrecompiledViewsPath); @@ -227,7 +229,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation { // Arrange var fileProvider = new TestFileProvider(); - var cache = new CompilerCache(new[] { new TestViewCollection() }, TestLoadContext, fileProvider); + var cache = new CompilerCache(fileProvider, _precompiledViews); // Act fileProvider.Watch(globalImportPath); @@ -245,7 +247,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation // Arrange var fileProvider = new TestFileProvider(); fileProvider.AddFile(ViewPath, "some content"); - var cache = new CompilerCache(new[] { new TestViewCollection() }, TestLoadContext, fileProvider); + var cache = new CompilerCache(fileProvider, _precompiledViews); var expected = CompilationResult.Successful(typeof(TestView)); // Act 1 @@ -285,25 +287,5 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation { throw new Exception("Shouldn't be called"); } - - private class TestViewCollection : RazorFileInfoCollection - { - public TestViewCollection() - { - FileInfos = new List - { - new RazorFileInfo - { - FullTypeName = typeof(PreCompile).FullName, - RelativePath = PrecompiledViewsPath, - } - }; - } - - public override Assembly LoadAssembly(IAssemblyLoadContext loadContext) - { - return typeof(TestViewCollection).Assembly; - } - } } } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.Razor.Test/Compilation/PrecompiledViewsCompilerCacheProviderTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Test/Compilation/PrecompiledViewsCompilerCacheProviderTest.cs new file mode 100644 index 0000000000..6acc48a60a --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.Razor.Test/Compilation/PrecompiledViewsCompilerCacheProviderTest.cs @@ -0,0 +1,142 @@ +// 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.Reflection; +using Microsoft.AspNet.Mvc.Razor.Precompilation; +using Microsoft.Dnx.Runtime; +using Moq; +using Xunit; + +namespace Microsoft.AspNet.Mvc.Razor.Compilation +{ + public class PrecompiledViewsCompilerCacheProviderTest + { + [Fact] + public void IsValidRazorFileInfoCollection_ReturnsFalse_IfTypeIsAbstract() + { + // Arrange + var type = typeof(AbstractRazorFileInfoCollection); + + // Act + var result = PrecompiledViewsCompilerCacheProvider.IsValidRazorFileInfoCollection(type); + + // Assert + Assert.False(result); + } + + [Fact] + public void IsValidRazorFileInfoCollection_ReturnsFalse_IfTypeHasGenericParameters() + { + // Arrange + var type = typeof(GenericRazorFileInfoCollection<>); + + // Act + var result = PrecompiledViewsCompilerCacheProvider.IsValidRazorFileInfoCollection(type); + + // Assert + Assert.False(result); + } + + [Fact] + public void IsValidRazorFileInfoCollection_ReturnsFalse_IfTypeDoesNotDeriveFromRazorFileInfoCollection() + { + // Arrange + var type = typeof(NonSubTypeRazorFileInfoCollection); + + // Act + var result = PrecompiledViewsCompilerCacheProvider.IsValidRazorFileInfoCollection(type); + + // Assert + Assert.False(result); + } + + [Theory] + [InlineData(typeof(ParameterConstructorRazorFileInfoCollection))] + [InlineData(typeof(ViewCollection))] + public void IsValidRazorFileInfoCollection_ReturnsTrue_IfTypeDerivesFromRazorFileInfoCollection(Type type) + { + // Act + var result = PrecompiledViewsCompilerCacheProvider.IsValidRazorFileInfoCollection(type); + + // Assert + Assert.True(result); + } + + [Fact] + public void GetPrecompiledViews_ReturnsTypesSpecifiedByRazorFileInfoCollections() + { + // Arrange + var fileInfoCollections = new[] { new ViewCollection() }; + + // Act + var precompiledViews = PrecompiledViewsCompilerCacheProvider.GetPrecompiledViews( + fileInfoCollections, + Mock.Of()); + + // Assert + Assert.Equal(2, precompiledViews.Count); + + Type type; + Assert.True(precompiledViews.TryGetValue("Views/Home/Index.cshtml", out type)); + Assert.Equal(typeof(TestView1), type); + + Assert.True(precompiledViews.TryGetValue("Views/Home/About.cshtml", out type)); + Assert.Equal(typeof(TestView2), type); + } + + + private abstract class AbstractRazorFileInfoCollection : RazorFileInfoCollection + { + } + + private class GenericRazorFileInfoCollection : RazorFileInfoCollection + { + } + + private class ParameterConstructorRazorFileInfoCollection : RazorFileInfoCollection + { + public ParameterConstructorRazorFileInfoCollection(string value) + { + } + } + + private class NonSubTypeRazorFileInfoCollection : Controller + { + } + + private class ViewCollection : RazorFileInfoCollection + { + public ViewCollection() + { + FileInfos = new[] + { + new RazorFileInfo + { + FullTypeName = typeof(TestView1).FullName, + RelativePath = "Views/Home/Index.cshtml" + }, + new RazorFileInfo + { + FullTypeName = typeof(TestView2).FullName, + RelativePath = "Views/Home/About.cshtml" + }, + }; + } + + public override Assembly LoadAssembly(IAssemblyLoadContext loadContext) + { + return GetType().GetTypeInfo().Assembly; + } + } + + + private class TestView1 + { + } + + private class TestView2 + { + } + } +} diff --git a/test/Microsoft.AspNet.Mvc.Razor.Test/Internal/RazorFileInfoCollectionsTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Test/Internal/RazorFileInfoCollectionsTest.cs deleted file mode 100644 index 51d7d7812e..0000000000 --- a/test/Microsoft.AspNet.Mvc.Razor.Test/Internal/RazorFileInfoCollectionsTest.cs +++ /dev/null @@ -1,88 +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 Microsoft.AspNet.Mvc; -using Microsoft.AspNet.Mvc.Razor.Internal; -using Microsoft.AspNet.Mvc.Razor.Precompilation; -using Xunit; - -namespace Microsoft.Framework.DependencyInjection -{ - public class RazorFileInfoCollectionsTest - { - [Fact] - public void IsValidRazorFileInfoCollection_ReturnsFalse_IfTypeIsAbstract() - { - // Arrange - var type = typeof(AbstractRazorFileInfoCollection); - - // Act - var result = RazorFileInfoCollections.IsValidRazorFileInfoCollection(type); - - // Assert - Assert.False(result); - } - - [Fact] - public void IsValidRazorFileInfoCollection_ReturnsFalse_IfTypeHasGenericParameters() - { - // Arrange - var type = typeof(GenericRazorFileInfoCollection<>); - - // Act - var result = RazorFileInfoCollections.IsValidRazorFileInfoCollection(type); - - // Assert - Assert.False(result); - } - - [Fact] - public void IsValidRazorFileInfoCollection_ReturnsFalse_IfTypeDoesNotDeriveFromRazorFileInfoCollection() - { - // Arrange - var type = typeof(NonSubTypeRazorFileInfoCollection); - - // Act - var result = RazorFileInfoCollections.IsValidRazorFileInfoCollection(type); - - // Assert - Assert.False(result); - } - - [Theory] - [InlineData(typeof(ParameterConstructorRazorFileInfoCollection))] - [InlineData(typeof(ViewCollection))] - public void IsValidRazorFileInfoCollection_ReturnsTrue_IfTypeDerivesFromRazorFileInfoCollection(Type type) - { - // Act - var result = RazorFileInfoCollections.IsValidRazorFileInfoCollection(type); - - // Assert - Assert.True(result); - } - - private abstract class AbstractRazorFileInfoCollection : RazorFileInfoCollection - { - } - - private class GenericRazorFileInfoCollection : RazorFileInfoCollection - { - } - - private class ParameterConstructorRazorFileInfoCollection : RazorFileInfoCollection - { - public ParameterConstructorRazorFileInfoCollection(string value) - { - } - } - - private class NonSubTypeRazorFileInfoCollection : Controller - { - } - - private class ViewCollection : RazorFileInfoCollection - { - } - } -} diff --git a/test/WebSites/RazorCompilerCacheWebSite/CompilerCacheController.cs b/test/WebSites/RazorCompilerCacheWebSite/CompilerCacheController.cs deleted file mode 100644 index 72bf53f815..0000000000 --- a/test/WebSites/RazorCompilerCacheWebSite/CompilerCacheController.cs +++ /dev/null @@ -1,36 +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 Microsoft.AspNet.Mvc; - -namespace RazorCompilerCacheWebSite -{ - public class CompilerCacheController : Controller - { - [HttpGet("/cache-status")] - [Produces("text/plain")] - public ContentResult GetCompilerCacheInitializationStatus( - [FromServices] CompilerCacheInitialiedService service) - { - return Content(service.Initialized.ToString()); - } - - [HttpGet("/statuscode")] - public IActionResult StatusCodeAction() - { - return new EmptyResult(); - } - - [HttpGet("/file")] - public IActionResult FileAction() - { - return File("HelloWorld.htm", "application/text"); - } - - [HttpGet("/view")] - public ViewResult Index() - { - return View("~/Index"); - } - } -} diff --git a/test/WebSites/RazorCompilerCacheWebSite/Index.cshtml b/test/WebSites/RazorCompilerCacheWebSite/Index.cshtml deleted file mode 100644 index b83b16fcf7..0000000000 --- a/test/WebSites/RazorCompilerCacheWebSite/Index.cshtml +++ /dev/null @@ -1 +0,0 @@ -Hello from view! \ No newline at end of file diff --git a/test/WebSites/RazorCompilerCacheWebSite/RazorCompilerCacheWebSite.xproj b/test/WebSites/RazorCompilerCacheWebSite/RazorCompilerCacheWebSite.xproj deleted file mode 100644 index c688fd0fb9..0000000000 --- a/test/WebSites/RazorCompilerCacheWebSite/RazorCompilerCacheWebSite.xproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 42c5d417-4060-48f4-bb28-e9e179007779 - ..\..\..\artifacts\obj\$(MSBuildProjectName) - ..\..\..\artifacts\bin\$(MSBuildProjectName)\ - - - 2.0 - 42473 - - - \ No newline at end of file diff --git a/test/WebSites/RazorCompilerCacheWebSite/Services/CompilerCacheInitialiedService.cs b/test/WebSites/RazorCompilerCacheWebSite/Services/CompilerCacheInitialiedService.cs deleted file mode 100644 index ffd83cae94..0000000000 --- a/test/WebSites/RazorCompilerCacheWebSite/Services/CompilerCacheInitialiedService.cs +++ /dev/null @@ -1,10 +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. - -namespace RazorCompilerCacheWebSite -{ - public class CompilerCacheInitialiedService - { - public bool Initialized { get; set; } - } -} \ No newline at end of file diff --git a/test/WebSites/RazorCompilerCacheWebSite/Services/CustomCompilerCache.cs b/test/WebSites/RazorCompilerCacheWebSite/Services/CustomCompilerCache.cs deleted file mode 100644 index 701f418cb6..0000000000 --- a/test/WebSites/RazorCompilerCacheWebSite/Services/CustomCompilerCache.cs +++ /dev/null @@ -1,24 +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.Collections.Generic; -using Microsoft.AspNet.Mvc.Razor; -using Microsoft.AspNet.Mvc.Razor.Compilation; -using Microsoft.AspNet.Mvc.Razor.Precompilation; -using Microsoft.Dnx.Runtime; -using Microsoft.Framework.OptionsModel; - -namespace RazorCompilerCacheWebSite -{ - public class CustomCompilerCache : CompilerCache - { - public CustomCompilerCache(IEnumerable fileInfoCollection, - IAssemblyLoadContextAccessor loadContextAccessor, - IOptions optionsAccessor, - CompilerCacheInitialiedService cacheInitializedService) - : base(fileInfoCollection, loadContextAccessor, optionsAccessor) - { - cacheInitializedService.Initialized = true; - } - } -} \ No newline at end of file diff --git a/test/WebSites/RazorCompilerCacheWebSite/Startup.cs b/test/WebSites/RazorCompilerCacheWebSite/Startup.cs deleted file mode 100644 index eb3f496e4d..0000000000 --- a/test/WebSites/RazorCompilerCacheWebSite/Startup.cs +++ /dev/null @@ -1,28 +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 Microsoft.AspNet.Builder; -using Microsoft.AspNet.Mvc.Razor.Compilation; -using Microsoft.Framework.DependencyInjection; - -namespace RazorCompilerCacheWebSite -{ - public class Startup - { - // Set up application services - public void ConfigureServices(IServiceCollection services) - { - // Add MVC services to the services container - services.AddMvc(); - services.AddSingleton(); - services.AddSingleton(); - } - - public void Configure(IApplicationBuilder app) - { - app.UseCultureReplacer(); - - app.UseMvc(); - } - } -} diff --git a/test/WebSites/RazorCompilerCacheWebSite/project.json b/test/WebSites/RazorCompilerCacheWebSite/project.json deleted file mode 100644 index 11ff594ef0..0000000000 --- a/test/WebSites/RazorCompilerCacheWebSite/project.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "commands": { - "web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001", - "kestrel": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.Kestrel --server.urls http://localhost:5000" - }, - "dependencies": { - "Microsoft.AspNet.Server.Kestrel": "1.0.0-*", - "Microsoft.AspNet.Mvc": "6.0.0-*", - "Microsoft.AspNet.Mvc.TestConfiguration": "1.0.0", - "Microsoft.AspNet.Server.IIS": "1.0.0-*", - "Microsoft.AspNet.Server.WebListener": "1.0.0-*", - "Microsoft.AspNet.StaticFiles": "1.0.0-*" - }, - "frameworks": { - "dnx451": { }, - "dnxcore50": { } - }, - "webroot": "wwwroot" -} diff --git a/test/WebSites/RazorCompilerCacheWebSite/readme.md b/test/WebSites/RazorCompilerCacheWebSite/readme.md deleted file mode 100644 index 4f984b7cc1..0000000000 --- a/test/WebSites/RazorCompilerCacheWebSite/readme.md +++ /dev/null @@ -1 +0,0 @@ -A functional test website to verify that the Razor compiler cache gets lazily initialized. diff --git a/test/WebSites/RazorCompilerCacheWebSite/wwwroot/HelloWorld.htm b/test/WebSites/RazorCompilerCacheWebSite/wwwroot/HelloWorld.htm deleted file mode 100644 index 3da1ec26e9..0000000000 --- a/test/WebSites/RazorCompilerCacheWebSite/wwwroot/HelloWorld.htm +++ /dev/null @@ -1 +0,0 @@ -HelloWorld