* Avoid lazyily evaluating IRazorCompilationService in

VirtualPathRazorPageFactory
* Cleanup comments on the lifetime of Razor services.
This commit is contained in:
Pranav K 2015-08-20 11:39:57 -07:00
parent ddc74e5396
commit c0d4981452
3 changed files with 20 additions and 40 deletions

View File

@ -96,28 +96,22 @@ namespace Microsoft.Framework.DependencyInjection
return new DefaultChunkTreeCache(cachedFileProvider.Options.FileProvider);
}));
// The host is designed to be discarded after consumption and is very inexpensive to initialize.
services.TryAddTransient<IMvcRazorHost, MvcRazorHost>();
// Caches compilation artifacts across the lifetime of the application.
services.TryAddSingleton<ICompilerCacheProvider, DefaultCompilerCacheProvider>();
// This caches compilation related details that are valid across the lifetime of the application
// and is required to be a singleton.
// This caches compilation related details that are valid across the lifetime of the application.
services.TryAddSingleton<ICompilationService, RoslynCompilationService>();
// Both the compiler cache and roslyn compilation service hold on the compilation related
// caches. RazorCompilation service is just an adapter service, and it is transient to ensure
// the IMvcRazorHost dependency does not maintain state.
services.TryAddTransient<IRazorCompilationService, RazorCompilationService>();
// The ViewStartProvider needs to be able to consume scoped instances of IRazorPageFactory
services.TryAddScoped<IViewStartProvider, ViewStartProvider>();
// In the default scenario the following services are singleton by virtue of being initialized as part of
// creating the singleton RazorViewEngine instance.
services.TryAddTransient<IRazorViewFactory, RazorViewFactory>();
services.TryAddSingleton<IRazorPageActivator, RazorPageActivator>();
services.TryAddTransient<IRazorPageFactory, VirtualPathRazorPageFactory>();
services.TryAddTransient<IRazorCompilationService, RazorCompilationService>();
services.TryAddTransient<IViewStartProvider, ViewStartProvider>();
services.TryAddTransient<IMvcRazorHost, MvcRazorHost>();
// Virtual path view factory needs to stay scoped so views can get get scoped services.
services.TryAddScoped<IRazorPageFactory, VirtualPathRazorPageFactory>();
// This caches Razor page activation details that are valid for the lifetime of the application.
services.TryAddSingleton<IRazorPageActivator, RazorPageActivator>();
// Only want one ITagHelperActivator so it can cache Type activation information. Types won't conflict.
services.TryAddSingleton<ITagHelperActivator, DefaultTagHelperActivator>();

View File

@ -3,7 +3,6 @@
using System;
using Microsoft.AspNet.Mvc.Razor.Compilation;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc.Razor
@ -14,40 +13,26 @@ namespace Microsoft.AspNet.Mvc.Razor
/// </summary>
public class VirtualPathRazorPageFactory : IRazorPageFactory
{
private readonly IServiceProvider _serviceProvider;
/// <remarks>
/// This delegate holds on to an instance of <see cref="IRazorCompilationService"/>.
/// </remarks>
private readonly Func<RelativeFileInfo, CompilationResult> _compileDelegate;
private readonly ICompilerCacheProvider _compilerCacheProvider;
private IRazorCompilationService _razorcompilationService;
private ICompilerCache _compilerCache;
/// <summary>
/// Initializes a new instance of <see cref="VirtualPathRazorPageFactory"/>.
/// </summary>
/// <param name="serviceProvider">The request specific <see cref="IServiceProvider"/>.</param>
/// <param name="razorCompilationService">The <see cref="IRazorCompilationService"/>.</param>
/// <param name="compilerCacheProvider">The <see cref="ICompilerCacheProvider"/>.</param>
public VirtualPathRazorPageFactory(
IServiceProvider serviceProvider,
IRazorCompilationService razorCompilationService,
ICompilerCacheProvider compilerCacheProvider)
{
_serviceProvider = serviceProvider;
_compileDelegate = razorCompilationService.Compile;
_compilerCacheProvider = compilerCacheProvider;
}
private IRazorCompilationService RazorCompilationService
{
get
{
if (_razorcompilationService == null)
{
// it is ok to use the cached service provider because both this, and the
// resolved service are in a lifetime of Scoped.
// We don't want to get it upfront because it will force Roslyn to load.
_razorcompilationService = _serviceProvider.GetRequiredService<IRazorCompilationService>();
}
return _razorcompilationService;
}
}
private ICompilerCache CompilerCache
{
get
@ -70,9 +55,7 @@ namespace Microsoft.AspNet.Mvc.Razor
relativePath = relativePath.Substring(1);
}
var result = CompilerCache.GetOrAdd(
relativePath,
RazorCompilationService.Compile);
var result = CompilerCache.GetOrAdd(relativePath, _compileDelegate);
if (result == CompilerCacheResult.FileNotFound)
{

View File

@ -9,6 +9,7 @@ using Microsoft.AspNet.Mvc.Internal;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
using Microsoft.AspNet.Mvc.Razor;
using Microsoft.Dnx.Compilation;
using Microsoft.Dnx.Runtime;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.OptionsModel;
@ -232,6 +233,8 @@ namespace Microsoft.AspNet.Mvc
private static void AddDnxServices(IServiceCollection serviceCollection)
{
serviceCollection.AddInstance(Mock.Of<ILibraryManager>());
serviceCollection.AddInstance(Mock.Of<ILibraryExporter>());
serviceCollection.AddInstance(Mock.Of<ICompilerOptionsProvider>());
serviceCollection.AddInstance(Mock.Of<IAssemblyLoadContextAccessor>());
var applicationEnvironment = new Mock<IApplicationEnvironment>();