Refactor ICompilerCache to be instantiated via ICompilerCacheProvider
Fixes #2933
This commit is contained in:
parent
e61ebca116
commit
05226a4a55
17
Mvc.sln
17
Mvc.sln
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 14
|
# Visual Studio 14
|
||||||
VisualStudioVersion = 14.0.23017.0
|
VisualStudioVersion = 14.0.23107.0
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}"
|
||||||
EndProject
|
EndProject
|
||||||
|
|
@ -122,8 +122,6 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ControllersFromServicesWebS
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ControllersFromServicesClassLibrary", "test\WebSites\ControllersFromServicesClassLibrary\ControllersFromServicesClassLibrary.xproj", "{551DC89E-2A13-4CF2-83D7-1ADD802443D5}"
|
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ControllersFromServicesClassLibrary", "test\WebSites\ControllersFromServicesClassLibrary\ControllersFromServicesClassLibrary.xproj", "{551DC89E-2A13-4CF2-83D7-1ADD802443D5}"
|
||||||
EndProject
|
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}"
|
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
|
EndProject
|
||||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "UserClassLibrary", "test\WebSites\UserClassLibrary\UserClassLibrary.xproj", "{C651F432-4EBE-41A6-BAD2-3E07CCBA209C}"
|
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|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.ActiveCfg = Release|Any CPU
|
||||||
{551DC89E-2A13-4CF2-83D7-1ADD802443D5}.Release|x86.Build.0 = 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.ActiveCfg = Debug|Any CPU
|
||||||
{4DA2D7C1-A7B6-4C01-B57D-89E6EA4609DE}.Debug|Any CPU.Build.0 = 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
|
{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}
|
{AC9BE567-540E-4C70-90C2-AAF021307A80} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||||
{983741B2-4424-4ED1-9B03-7675A67230C8} = {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}
|
{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}
|
{4DA2D7C1-A7B6-4C01-B57D-89E6EA4609DE} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||||
{C651F432-4EBE-41A6-BAD2-3E07CCBA209C} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
{C651F432-4EBE-41A6-BAD2-3E07CCBA209C} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||||
{A19022EF-9BA3-4349-94E4-F48E13E1C8AE} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
{A19022EF-9BA3-4349-94E4-F48E13E1C8AE} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"description": "Features that enable globalization & localization of MVC applications.",
|
"description": "Features that enable globalization & localization of MVC applications.",
|
||||||
"version": "6.0.0-*",
|
"version": "6.0.0-*",
|
||||||
"compilationOptions": {
|
"compilationOptions": {
|
||||||
"warningsAsErrors": false
|
"warningsAsErrors": true
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.AspNet.Localization": "1.0.0-*",
|
"Microsoft.AspNet.Localization": "1.0.0-*",
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,9 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
|
||||||
using Microsoft.AspNet.FileProviders;
|
using Microsoft.AspNet.FileProviders;
|
||||||
using Microsoft.AspNet.Mvc.Razor.Precompilation;
|
|
||||||
using Microsoft.Dnx.Runtime;
|
|
||||||
using Microsoft.Framework.Caching.Memory;
|
using Microsoft.Framework.Caching.Memory;
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
using Microsoft.Framework.OptionsModel;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
||||||
{
|
{
|
||||||
|
|
@ -18,46 +14,36 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CompilerCache : ICompilerCache
|
public class CompilerCache : ICompilerCache
|
||||||
{
|
{
|
||||||
private static readonly Assembly RazorHostAssembly = typeof(CompilerCache).GetTypeInfo().Assembly;
|
|
||||||
private readonly IFileProvider _fileProvider;
|
private readonly IFileProvider _fileProvider;
|
||||||
private readonly IMemoryCache _cache;
|
private readonly IMemoryCache _cache;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of <see cref="CompilerCache"/> populated with precompiled views
|
/// Initializes a new instance of <see cref="CompilerCache"/>.
|
||||||
/// discovered using <paramref name="provider"/>.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="razorFileInfoCollections">The sequence of <see cref="RazorFileInfoCollection"/> that provides
|
/// <param name="fileProvider"><see cref="IFileProvider"/> used to locate Razor views.</param>
|
||||||
/// information for precompiled view discovery.</param>
|
public CompilerCache([NotNull] IFileProvider fileProvider)
|
||||||
/// <param name="loaderContextAccessor">The <see cref="IAssemblyLoadContextAccessor"/>.</param>
|
|
||||||
/// <param name="optionsAccessor">An accessor to the <see cref="RazorViewEngineOptions"/>.</param>
|
|
||||||
public CompilerCache(
|
|
||||||
IEnumerable<RazorFileInfoCollection> razorFileInfoCollections,
|
|
||||||
IAssemblyLoadContextAccessor loadContextAccessor,
|
|
||||||
IOptions<RazorViewEngineOptions> optionsAccessor)
|
|
||||||
: this(razorFileInfoCollections,
|
|
||||||
loadContextAccessor.GetLoadContext(RazorHostAssembly),
|
|
||||||
optionsAccessor.Options.FileProvider)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
internal CompilerCache(
|
|
||||||
IEnumerable<RazorFileInfoCollection> razorFileInfoCollections,
|
|
||||||
IAssemblyLoadContext loadContext,
|
|
||||||
IFileProvider fileProvider)
|
|
||||||
{
|
{
|
||||||
_fileProvider = fileProvider;
|
_fileProvider = fileProvider;
|
||||||
_cache = new MemoryCache(new MemoryCacheOptions { CompactOnMemoryPressure = false });
|
_cache = new MemoryCache(new MemoryCacheOptions { CompactOnMemoryPressure = false });
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var viewCollection in razorFileInfoCollections)
|
/// <summary>
|
||||||
|
/// Initializes a new instance of <see cref="CompilerCache"/> populated with precompiled views
|
||||||
|
/// specified by <paramref name="precompiledViews"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fileProvider"><see cref="IFileProvider"/> used to locate Razor views.</param>
|
||||||
|
/// <param name="precompiledViews">A mapping of application relative paths of view to the precompiled view
|
||||||
|
/// <see cref="Type"/>s.</param>
|
||||||
|
public CompilerCache(
|
||||||
|
[NotNull] IFileProvider fileProvider,
|
||||||
|
[NotNull] IDictionary<string, Type> precompiledViews)
|
||||||
|
: this(fileProvider)
|
||||||
|
{
|
||||||
|
foreach (var item in precompiledViews)
|
||||||
{
|
{
|
||||||
var containingAssembly = viewCollection.LoadAssembly(loadContext);
|
var cacheEntry = new CompilerCacheResult(CompilationResult.Successful(item.Value));
|
||||||
foreach (var fileInfo in viewCollection.FileInfos)
|
var normalizedPath = NormalizePath(item.Key);
|
||||||
{
|
_cache.Set(normalizedPath, cacheEntry);
|
||||||
var viewType = containingAssembly.GetType(fileInfo.FullTypeName);
|
|
||||||
var cacheEntry = new CompilerCacheResult(CompilationResult.Successful(viewType));
|
|
||||||
var normalizedPath = NormalizePath(fileInfo.RelativePath);
|
|
||||||
_cache.Set(normalizedPath, cacheEntry);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Default implementation for <see cref="ICompilerCacheProvider"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class DefaultCompilerCacheProvider : ICompilerCacheProvider
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of <see cref="DefaultCompilerCacheProvider"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="optionsAccessor">An accessor to the <see cref="RazorViewEngineOptions"/>.</param>
|
||||||
|
public DefaultCompilerCacheProvider(IOptions<RazorViewEngineOptions> mvcViewOptions)
|
||||||
|
{
|
||||||
|
var fileProvider = mvcViewOptions.Options.FileProvider;
|
||||||
|
Cache = new CompilerCache(fileProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ICompilerCache Cache { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides access to a cached <see cref="ICompilerCache"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
public interface ICompilerCacheProvider
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The cached <see cref="ICompilerCache"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
ICompilerCache Cache { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An <see cref="ICompilerCacheProvider"/> that provides a <see cref="CompilerCache"/> instance
|
||||||
|
/// populated with precompiled views.
|
||||||
|
/// </summary>
|
||||||
|
public class PrecompiledViewsCompilerCacheProvider : ICompilerCacheProvider
|
||||||
|
{
|
||||||
|
private static readonly Assembly RazorAssembly = typeof(DefaultCompilerCacheProvider).GetTypeInfo().Assembly;
|
||||||
|
private static readonly Type RazorFileInfoCollectionType = typeof(RazorFileInfoCollection);
|
||||||
|
private readonly Func<ICompilerCache> _createCache;
|
||||||
|
private readonly IAssemblyLoadContextAccessor _loadContextAccessor;
|
||||||
|
private readonly IFileProvider _fileProvider;
|
||||||
|
private readonly Assembly[] _assemblies;
|
||||||
|
|
||||||
|
private object _cacheLock = new object();
|
||||||
|
private bool _cacheInitialized;
|
||||||
|
private ICompilerCache _compilerCache;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of <see cref="DefaultCompilerCacheProvider"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="loaderContextAccessor">The <see cref="IAssemblyLoadContextAccessor"/>.</param>
|
||||||
|
/// <param name="optionsAccessor">An accessor to the <see cref="RazorViewEngineOptions"/>.</param>
|
||||||
|
/// <param name="assemblies"><see cref="Assembly"/> instances to scan for precompiled views.</param>
|
||||||
|
public PrecompiledViewsCompilerCacheProvider(
|
||||||
|
IAssemblyLoadContextAccessor loadContextAccessor,
|
||||||
|
IOptions<RazorViewEngineOptions> mvcViewOptions,
|
||||||
|
IEnumerable<Assembly> assemblies)
|
||||||
|
{
|
||||||
|
_loadContextAccessor = loadContextAccessor;
|
||||||
|
_fileProvider = mvcViewOptions.Options.FileProvider;
|
||||||
|
_createCache = CreateCache;
|
||||||
|
_assemblies = assemblies.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
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<string, Type> GetPrecompiledViews(
|
||||||
|
IEnumerable<RazorFileInfoCollection> razorFileInfoCollections,
|
||||||
|
IAssemblyLoadContext loadContext)
|
||||||
|
{
|
||||||
|
var precompiledViews = new Dictionary<string, Type>(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<RazorFileInfoCollection> GetFileInfoCollections(IEnumerable<Assembly> assemblies)
|
||||||
|
{
|
||||||
|
return assemblies
|
||||||
|
.SelectMany(assembly => assembly.ExportedTypes)
|
||||||
|
.Where(IsValidRazorFileInfoCollection)
|
||||||
|
.Select(Activator.CreateInstance)
|
||||||
|
.Cast<RazorFileInfoCollection>();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool IsValidRazorFileInfoCollection(Type type)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
RazorFileInfoCollectionType.IsAssignableFrom(type) &&
|
||||||
|
!type.GetTypeInfo().IsAbstract &&
|
||||||
|
!type.GetTypeInfo().ContainsGenericParameters;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,10 +2,11 @@
|
||||||
// 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.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Microsoft.AspNet.Mvc;
|
using Microsoft.AspNet.Mvc;
|
||||||
using Microsoft.AspNet.Mvc.Razor;
|
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.AspNet.Razor.Runtime.TagHelpers;
|
||||||
using Microsoft.Framework.DependencyInjection.Extensions;
|
using Microsoft.Framework.DependencyInjection.Extensions;
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
|
|
@ -53,13 +54,17 @@ namespace Microsoft.Framework.DependencyInjection
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IMvcBuilder AddPrecompiledRazorViews(
|
public static IMvcBuilder AddPrecompiledRazorViews(
|
||||||
[NotNull] this IMvcBuilder builder,
|
[NotNull] this IMvcBuilder builder,
|
||||||
[NotNull] params Assembly[] assemblies)
|
[NotNull] params Assembly[] assemblies)
|
||||||
{
|
{
|
||||||
var razorFileInfos = RazorFileInfoCollections.GetFileInfoCollections(assemblies);
|
builder.Services.Replace(
|
||||||
builder.Services.TryAddEnumerable(ServiceDescriptor.Instance(razorFileInfos));
|
ServiceDescriptor.Singleton<ICompilerCacheProvider>(serviceProvider =>
|
||||||
|
ActivatorUtilities.CreateInstance<PrecompiledViewsCompilerCacheProvider>(
|
||||||
|
serviceProvider,
|
||||||
|
assemblies.AsEnumerable())));
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
// 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.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Microsoft.AspNet.Mvc;
|
using Microsoft.AspNet.Mvc;
|
||||||
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.Mvc.Razor.Directives;
|
using Microsoft.AspNet.Mvc.Razor.Directives;
|
||||||
using Microsoft.AspNet.Mvc.Razor.Internal;
|
|
||||||
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
|
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
|
||||||
using Microsoft.Framework.Caching.Memory;
|
using Microsoft.Framework.Caching.Memory;
|
||||||
using Microsoft.Framework.DependencyInjection.Extensions;
|
using Microsoft.Framework.DependencyInjection.Extensions;
|
||||||
|
|
@ -46,8 +46,11 @@ namespace Microsoft.Framework.DependencyInjection
|
||||||
{
|
{
|
||||||
AddRazorViewEngine(builder);
|
AddRazorViewEngine(builder);
|
||||||
|
|
||||||
var razorFileInfos = RazorFileInfoCollections.GetFileInfoCollections(assemblies);
|
builder.Services.Replace(
|
||||||
builder.Services.TryAddEnumerable(ServiceDescriptor.Instance(razorFileInfos));
|
ServiceDescriptor.Singleton<ICompilerCacheProvider>(serviceProvider =>
|
||||||
|
ActivatorUtilities.CreateInstance<PrecompiledViewsCompilerCacheProvider>(
|
||||||
|
serviceProvider,
|
||||||
|
assemblies.AsEnumerable())));
|
||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
@ -97,7 +100,7 @@ namespace Microsoft.Framework.DependencyInjection
|
||||||
services.TryAddTransient<IMvcRazorHost, MvcRazorHost>();
|
services.TryAddTransient<IMvcRazorHost, MvcRazorHost>();
|
||||||
|
|
||||||
// Caches compilation artifacts across the lifetime of the application.
|
// Caches compilation artifacts across the lifetime of the application.
|
||||||
services.TryAddSingleton<ICompilerCache, CompilerCache>();
|
services.TryAddSingleton<ICompilerCacheProvider, DefaultCompilerCacheProvider>();
|
||||||
|
|
||||||
// This caches compilation related details that are valid across the lifetime of the application
|
// This caches compilation related details that are valid across the lifetime of the application
|
||||||
// and is required to be a singleton.
|
// and is required to be a singleton.
|
||||||
|
|
|
||||||
|
|
@ -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<RazorFileInfoCollection> GetFileInfoCollections(IEnumerable<Assembly> assemblies)
|
|
||||||
{
|
|
||||||
return assemblies
|
|
||||||
.SelectMany(assembly => assembly.ExportedTypes)
|
|
||||||
.Where(IsValidRazorFileInfoCollection)
|
|
||||||
.Select(Activator.CreateInstance)
|
|
||||||
.Cast<RazorFileInfoCollection>();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static bool IsValidRazorFileInfoCollection(Type type)
|
|
||||||
{
|
|
||||||
return
|
|
||||||
RazorFileInfoCollectionType.IsAssignableFrom(type) &&
|
|
||||||
!type.GetTypeInfo().IsAbstract &&
|
|
||||||
!type.GetTypeInfo().ContainsGenericParameters;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -15,14 +15,21 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
public class VirtualPathRazorPageFactory : IRazorPageFactory
|
public class VirtualPathRazorPageFactory : IRazorPageFactory
|
||||||
{
|
{
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
private readonly ICompilerCache _compilerCache;
|
private readonly ICompilerCacheProvider _compilerCacheProvider;
|
||||||
private IRazorCompilationService _razorcompilationService;
|
private IRazorCompilationService _razorcompilationService;
|
||||||
|
private ICompilerCache _compilerCache;
|
||||||
|
|
||||||
public VirtualPathRazorPageFactory(IServiceProvider serviceProvider,
|
/// <summary>
|
||||||
ICompilerCache compilerCache)
|
/// Initializes a new instance of <see cref="VirtualPathRazorPageFactory"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="serviceProvider">The request specific <see cref="IServiceProvider"/>.</param>
|
||||||
|
/// <param name="compilerCacheProvider">The <see cref="ICompilerCacheProvider"/>.</param>
|
||||||
|
public VirtualPathRazorPageFactory(
|
||||||
|
IServiceProvider serviceProvider,
|
||||||
|
ICompilerCacheProvider compilerCacheProvider)
|
||||||
{
|
{
|
||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
_compilerCache = compilerCache;
|
_compilerCacheProvider = compilerCacheProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IRazorCompilationService RazorCompilationService
|
private IRazorCompilationService RazorCompilationService
|
||||||
|
|
@ -41,6 +48,19 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ICompilerCache CompilerCache
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_compilerCache == null)
|
||||||
|
{
|
||||||
|
_compilerCache = _compilerCacheProvider.Cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _compilerCache;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IRazorPage CreateInstance([NotNull] string relativePath)
|
public IRazorPage CreateInstance([NotNull] string relativePath)
|
||||||
{
|
{
|
||||||
|
|
@ -50,7 +70,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
||||||
relativePath = relativePath.Substring(1);
|
relativePath = relativePath.Substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = _compilerCache.GetOrAdd(
|
var result = CompilerCache.GetOrAdd(
|
||||||
relativePath,
|
relativePath,
|
||||||
RazorCompilationService.Compile);
|
RazorCompilationService.Compile);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
"url": "git://github.com/aspnet/mvc"
|
"url": "git://github.com/aspnet/mvc"
|
||||||
},
|
},
|
||||||
"compilationOptions": {
|
"compilationOptions": {
|
||||||
"warningsAsErrors": false
|
"warningsAsErrors": true
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.AspNet.Mvc.Razor.Host": "6.0.0-*",
|
"Microsoft.AspNet.Mvc.Razor.Host": "6.0.0-*",
|
||||||
|
|
|
||||||
|
|
@ -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<IApplicationBuilder> _app = new Startup().Configure;
|
|
||||||
private readonly Action<IServiceCollection> _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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -49,7 +49,6 @@
|
||||||
"ModelBindingWebSite": "1.0.0",
|
"ModelBindingWebSite": "1.0.0",
|
||||||
"MvcSample.Web": "1.0.0",
|
"MvcSample.Web": "1.0.0",
|
||||||
"PrecompilationWebSite": "1.0.0",
|
"PrecompilationWebSite": "1.0.0",
|
||||||
"RazorCompilerCacheWebSite": "1.0.0",
|
|
||||||
"RazorEmbeddedViewsWebSite": "1.0.0",
|
"RazorEmbeddedViewsWebSite": "1.0.0",
|
||||||
"RazorPageExecutionInstrumentationWebSite": "1.0.0",
|
"RazorPageExecutionInstrumentationWebSite": "1.0.0",
|
||||||
"RazorWebSite": "1.0.0",
|
"RazorWebSite": "1.0.0",
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Microsoft.AspNet.Mvc.Razor.Precompilation;
|
using Microsoft.AspNet.Mvc.Razor.Precompilation;
|
||||||
using Microsoft.Dnx.Runtime;
|
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 ViewPath = "Views/Home/Index.cshtml";
|
||||||
private const string PrecompiledViewsPath = "Views/Home/Precompiled.cshtml";
|
private const string PrecompiledViewsPath = "Views/Home/Precompiled.cshtml";
|
||||||
private readonly IAssemblyLoadContext TestLoadContext = Mock.Of<IAssemblyLoadContext>();
|
private readonly IDictionary<string, Type> _precompiledViews = new Dictionary<string, Type>
|
||||||
|
{
|
||||||
|
{ PrecompiledViewsPath, typeof(PreCompile) }
|
||||||
|
};
|
||||||
|
|
||||||
public static TheoryData ViewImportsPaths =>
|
public static TheoryData ViewImportsPaths =>
|
||||||
new TheoryData<string>
|
new TheoryData<string>
|
||||||
|
|
@ -32,7 +34,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var fileProvider = new TestFileProvider();
|
var fileProvider = new TestFileProvider();
|
||||||
var cache = new CompilerCache(Enumerable.Empty<RazorFileInfoCollection>(), TestLoadContext, fileProvider);
|
var cache = new CompilerCache(fileProvider);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = cache.GetOrAdd("/some/path", ThrowsIfCalled);
|
var result = cache.GetOrAdd("/some/path", ThrowsIfCalled);
|
||||||
|
|
@ -48,7 +50,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
||||||
// Arrange
|
// Arrange
|
||||||
var fileProvider = new TestFileProvider();
|
var fileProvider = new TestFileProvider();
|
||||||
fileProvider.AddFile(ViewPath, "some content");
|
fileProvider.AddFile(ViewPath, "some content");
|
||||||
var cache = new CompilerCache(Enumerable.Empty<RazorFileInfoCollection>(), TestLoadContext, fileProvider);
|
var cache = new CompilerCache(fileProvider);
|
||||||
var type = typeof(TestView);
|
var type = typeof(TestView);
|
||||||
var expected = UncachedCompilationResult.Successful(type, "hello world");
|
var expected = UncachedCompilationResult.Successful(type, "hello world");
|
||||||
|
|
||||||
|
|
@ -70,7 +72,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
||||||
// Arrange
|
// Arrange
|
||||||
var fileProvider = new TestFileProvider();
|
var fileProvider = new TestFileProvider();
|
||||||
fileProvider.AddFile(ViewPath, "some content");
|
fileProvider.AddFile(ViewPath, "some content");
|
||||||
var cache = new CompilerCache(Enumerable.Empty<RazorFileInfoCollection>(), TestLoadContext, fileProvider);
|
var cache = new CompilerCache(fileProvider);
|
||||||
var type = typeof(TestView);
|
var type = typeof(TestView);
|
||||||
var expected = UncachedCompilationResult.Successful(type, "hello world");
|
var expected = UncachedCompilationResult.Successful(type, "hello world");
|
||||||
|
|
||||||
|
|
@ -98,7 +100,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
||||||
// Arrange
|
// Arrange
|
||||||
var fileProvider = new TestFileProvider();
|
var fileProvider = new TestFileProvider();
|
||||||
fileProvider.AddFile(ViewPath, "some content");
|
fileProvider.AddFile(ViewPath, "some content");
|
||||||
var cache = new CompilerCache(Enumerable.Empty<RazorFileInfoCollection>(), TestLoadContext, fileProvider);
|
var cache = new CompilerCache(fileProvider);
|
||||||
var expected1 = UncachedCompilationResult.Successful(typeof(TestView), "hello world");
|
var expected1 = UncachedCompilationResult.Successful(typeof(TestView), "hello world");
|
||||||
var expected2 = UncachedCompilationResult.Successful(typeof(DifferentView), "different content");
|
var expected2 = UncachedCompilationResult.Successful(typeof(DifferentView), "different content");
|
||||||
|
|
||||||
|
|
@ -133,7 +135,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
||||||
// Arrange
|
// Arrange
|
||||||
var fileProvider = new TestFileProvider();
|
var fileProvider = new TestFileProvider();
|
||||||
fileProvider.AddFile(ViewPath, "some content");
|
fileProvider.AddFile(ViewPath, "some content");
|
||||||
var cache = new CompilerCache(Enumerable.Empty<RazorFileInfoCollection>(), TestLoadContext, fileProvider);
|
var cache = new CompilerCache(fileProvider);
|
||||||
var expected1 = UncachedCompilationResult.Successful(typeof(TestView), "hello world");
|
var expected1 = UncachedCompilationResult.Successful(typeof(TestView), "hello world");
|
||||||
var expected2 = UncachedCompilationResult.Successful(typeof(DifferentView), "different content");
|
var expected2 = UncachedCompilationResult.Successful(typeof(DifferentView), "different content");
|
||||||
|
|
||||||
|
|
@ -168,7 +170,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
||||||
var mockFileProvider = new Mock<TestFileProvider> { CallBase = true };
|
var mockFileProvider = new Mock<TestFileProvider> { CallBase = true };
|
||||||
var fileProvider = mockFileProvider.Object;
|
var fileProvider = mockFileProvider.Object;
|
||||||
fileProvider.AddFile(ViewPath, "some content");
|
fileProvider.AddFile(ViewPath, "some content");
|
||||||
var cache = new CompilerCache(Enumerable.Empty<RazorFileInfoCollection>(), TestLoadContext, fileProvider);
|
var cache = new CompilerCache(fileProvider);
|
||||||
var type = typeof(TestView);
|
var type = typeof(TestView);
|
||||||
var expected = UncachedCompilationResult.Successful(type, "hello world");
|
var expected = UncachedCompilationResult.Successful(type, "hello world");
|
||||||
|
|
||||||
|
|
@ -194,7 +196,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var fileProvider = new TestFileProvider();
|
var fileProvider = new TestFileProvider();
|
||||||
var cache = new CompilerCache(new[] { new TestViewCollection() }, TestLoadContext, fileProvider);
|
var cache = new CompilerCache(fileProvider, _precompiledViews);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = cache.GetOrAdd(PrecompiledViewsPath, ThrowsIfCalled);
|
var result = cache.GetOrAdd(PrecompiledViewsPath, ThrowsIfCalled);
|
||||||
|
|
@ -209,7 +211,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var fileProvider = new TestFileProvider();
|
var fileProvider = new TestFileProvider();
|
||||||
var cache = new CompilerCache(new[] { new TestViewCollection() }, TestLoadContext, fileProvider);
|
var cache = new CompilerCache(fileProvider, _precompiledViews);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
fileProvider.Watch(PrecompiledViewsPath);
|
fileProvider.Watch(PrecompiledViewsPath);
|
||||||
|
|
@ -227,7 +229,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var fileProvider = new TestFileProvider();
|
var fileProvider = new TestFileProvider();
|
||||||
var cache = new CompilerCache(new[] { new TestViewCollection() }, TestLoadContext, fileProvider);
|
var cache = new CompilerCache(fileProvider, _precompiledViews);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
fileProvider.Watch(globalImportPath);
|
fileProvider.Watch(globalImportPath);
|
||||||
|
|
@ -245,7 +247,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
||||||
// Arrange
|
// Arrange
|
||||||
var fileProvider = new TestFileProvider();
|
var fileProvider = new TestFileProvider();
|
||||||
fileProvider.AddFile(ViewPath, "some content");
|
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));
|
var expected = CompilationResult.Successful(typeof(TestView));
|
||||||
|
|
||||||
// Act 1
|
// Act 1
|
||||||
|
|
@ -285,25 +287,5 @@ namespace Microsoft.AspNet.Mvc.Razor.Compilation
|
||||||
{
|
{
|
||||||
throw new Exception("Shouldn't be called");
|
throw new Exception("Shouldn't be called");
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestViewCollection : RazorFileInfoCollection
|
|
||||||
{
|
|
||||||
public TestViewCollection()
|
|
||||||
{
|
|
||||||
FileInfos = new List<RazorFileInfo>
|
|
||||||
{
|
|
||||||
new RazorFileInfo
|
|
||||||
{
|
|
||||||
FullTypeName = typeof(PreCompile).FullName,
|
|
||||||
RelativePath = PrecompiledViewsPath,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Assembly LoadAssembly(IAssemblyLoadContext loadContext)
|
|
||||||
{
|
|
||||||
return typeof(TestViewCollection).Assembly;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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<IAssemblyLoadContext>());
|
||||||
|
|
||||||
|
// 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<TVal> : 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
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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<TVal> : RazorFileInfoCollection
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ParameterConstructorRazorFileInfoCollection : RazorFileInfoCollection
|
|
||||||
{
|
|
||||||
public ParameterConstructorRazorFileInfoCollection(string value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class NonSubTypeRazorFileInfoCollection : Controller
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ViewCollection : RazorFileInfoCollection
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Hello from view!
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<PropertyGroup>
|
|
||||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
|
||||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
|
|
||||||
<PropertyGroup Label="Globals">
|
|
||||||
<ProjectGuid>42c5d417-4060-48f4-bb28-e9e179007779</ProjectGuid>
|
|
||||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
|
||||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup>
|
|
||||||
<SchemaVersion>2.0</SchemaVersion>
|
|
||||||
<DevelopmentServerPort>42473</DevelopmentServerPort>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
|
|
||||||
</Project>
|
|
||||||
|
|
@ -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; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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<RazorFileInfoCollection> fileInfoCollection,
|
|
||||||
IAssemblyLoadContextAccessor loadContextAccessor,
|
|
||||||
IOptions<RazorViewEngineOptions> optionsAccessor,
|
|
||||||
CompilerCacheInitialiedService cacheInitializedService)
|
|
||||||
: base(fileInfoCollection, loadContextAccessor, optionsAccessor)
|
|
||||||
{
|
|
||||||
cacheInitializedService.Initialized = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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<ICompilerCache, CustomCompilerCache>();
|
|
||||||
services.AddSingleton<CompilerCacheInitialiedService>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app)
|
|
||||||
{
|
|
||||||
app.UseCultureReplacer();
|
|
||||||
|
|
||||||
app.UseMvc();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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"
|
|
||||||
}
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
A functional test website to verify that the Razor compiler cache gets lazily initialized.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
HelloWorld
|
|
||||||
Loading…
Reference in New Issue