From 275f63e91f242575744de77263477e0a729ae0fe Mon Sep 17 00:00:00 2001 From: YishaiGalatzer Date: Thu, 9 Oct 2014 23:34:02 -0700 Subject: [PATCH] Prevent Roslyn from loading prematurely on cold start --- .../Compilation/CompilerCache.cs | 15 ++++++++--- .../Razor/RazorCompilationService.cs | 26 ++++++++++++++++--- .../RazorViewEngine.cs | 4 ++- .../VirtualPathRazorPageFactory.cs | 21 +++++++++++---- .../RazorCompilationServiceTest.cs | 18 ++++++++++--- 5 files changed, 67 insertions(+), 17 deletions(-) diff --git a/src/Microsoft.AspNet.Mvc.Razor/Compilation/CompilerCache.cs b/src/Microsoft.AspNet.Mvc.Razor/Compilation/CompilerCache.cs index 2a99db122a..0e8bccc48f 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/Compilation/CompilerCache.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/Compilation/CompilerCache.cs @@ -31,7 +31,7 @@ namespace Microsoft.AspNet.Mvc.Razor // There shouldn't be any duplicates and if there are any the first will win. // If the result doesn't match the one on disk its going to recompile anyways. - _cache.TryAdd(fileInfo.RelativePath, cacheEntry); + _cache.TryAdd(NormalizePath(fileInfo.RelativePath), cacheEntry); } } } @@ -68,8 +68,9 @@ namespace Microsoft.AspNet.Mvc.Razor bool enableInstrumentation, [NotNull] Func compile) { + CompilerCacheEntry cacheEntry; - if (!_cache.TryGetValue(fileInfo.RelativePath, out cacheEntry)) + if (!_cache.TryGetValue(NormalizePath(fileInfo.RelativePath), out cacheEntry)) { return OnCacheMiss(fileInfo, enableInstrumentation, compile); } @@ -114,9 +115,17 @@ namespace Microsoft.AspNet.Mvc.Razor var result = compile(); var cacheEntry = new CompilerCacheEntry(file, result.CompiledType, isInstrumented); - _cache[file.RelativePath] = cacheEntry; + _cache[NormalizePath(file.RelativePath)] = cacheEntry; return result; } + + private string NormalizePath(string path) + { + path = path.Replace('/', '\\'); + path = path.TrimStart('\\'); + + return path; + } } } diff --git a/src/Microsoft.AspNet.Mvc.Razor/Razor/RazorCompilationService.cs b/src/Microsoft.AspNet.Mvc.Razor/Razor/RazorCompilationService.cs index e8b463f205..223c35cbc9 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/Razor/RazorCompilationService.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/Razor/RazorCompilationService.cs @@ -1,8 +1,10 @@ // Copyright (c) Microsoft Open Technologies, Inc. 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.Linq; using Microsoft.AspNet.Razor; +using Microsoft.Framework.DependencyInjection; namespace Microsoft.AspNet.Mvc.Razor { @@ -14,15 +16,31 @@ namespace Microsoft.AspNet.Mvc.Razor /// public class RazorCompilationService : IRazorCompilationService { + private readonly IServiceProvider _serviceProvider; + private readonly CompilerCache _cache; - private readonly ICompilationService _baseCompilationService; + private ICompilationService _compilationService; + + private ICompilationService CompilationService + { + get + { + if (_compilationService == null) + { + _compilationService = _serviceProvider.GetService(); + } + + return _compilationService; + } + } + private readonly IMvcRazorHost _razorHost; - public RazorCompilationService(ICompilationService compilationService, + public RazorCompilationService(IServiceProvider serviceProvider, IControllerAssemblyProvider _controllerAssemblyProvider, IMvcRazorHost razorHost) { - _baseCompilationService = compilationService; + _serviceProvider = serviceProvider; _razorHost = razorHost; _cache = new CompilerCache(_controllerAssemblyProvider.CandidateAssemblies); } @@ -50,7 +68,7 @@ namespace Microsoft.AspNet.Mvc.Razor return CompilationResult.Failed(file.FileInfo, results.GeneratedCode, messages); } - return _baseCompilationService.Compile(file.FileInfo, results.GeneratedCode); + return CompilationService.Compile(file.FileInfo, results.GeneratedCode); } } } diff --git a/src/Microsoft.AspNet.Mvc.Razor/RazorViewEngine.cs b/src/Microsoft.AspNet.Mvc.Razor/RazorViewEngine.cs index b8d4034b28..b91790bbea 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/RazorViewEngine.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/RazorViewEngine.cs @@ -163,7 +163,9 @@ namespace Microsoft.AspNet.Mvc.Razor viewName, controllerName, areaName); - var page = _pageFactory.CreateInstance(transformedPath, IsInstrumentationEnabled(context)); + + var isInstrumentated = IsInstrumentationEnabled(context); + var page = _pageFactory.CreateInstance(transformedPath, isInstrumentated); if (page != null) { // 3a. We found a page. Cache the set of values that produced it and return a found result. diff --git a/src/Microsoft.AspNet.Mvc.Razor/VirtualPathRazorPageFactory.cs b/src/Microsoft.AspNet.Mvc.Razor/VirtualPathRazorPageFactory.cs index ee28806b5d..4b7fb7ae93 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/VirtualPathRazorPageFactory.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/VirtualPathRazorPageFactory.cs @@ -12,17 +12,28 @@ namespace Microsoft.AspNet.Mvc.Razor /// public class VirtualPathRazorPageFactory : IRazorPageFactory { - private readonly IRazorCompilationService _compilationService; + private IRazorCompilationService _compilationService; + private IRazorCompilationService CompilationService + { + get + { + if (_compilationService == null) + { + _compilationService = _serviceProvider.GetService(); + } + + return _compilationService; + } + } + private readonly ITypeActivator _activator; private readonly IServiceProvider _serviceProvider; private readonly IFileInfoCache _fileInfoCache; - public VirtualPathRazorPageFactory(IRazorCompilationService compilationService, - ITypeActivator typeActivator, + public VirtualPathRazorPageFactory(ITypeActivator typeActivator, IServiceProvider serviceProvider, IFileInfoCache fileInfoCache) { - _compilationService = compilationService; _activator = typeActivator; _serviceProvider = serviceProvider; _fileInfoCache = fileInfoCache; @@ -47,7 +58,7 @@ namespace Microsoft.AspNet.Mvc.Razor RelativePath = relativePath, }; - var result = _compilationService.Compile(relativeFileInfo, enableInstrumentation); + var result = CompilationService.Compile(relativeFileInfo, enableInstrumentation); var page = (IRazorPage)_activator.CreateInstance(_serviceProvider, result.CompiledType); page.Path = relativePath; diff --git a/test/Microsoft.AspNet.Mvc.Razor.Test/RazorCompilationServiceTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Test/RazorCompilationServiceTest.cs index d1fb1d71f5..ab3100ea7c 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Test/RazorCompilationServiceTest.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Test/RazorCompilationServiceTest.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Open Technologies, Inc. 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.IO; using System.Linq; using System.Reflection; @@ -34,10 +35,16 @@ namespace Microsoft.AspNet.Mvc.Razor.Test var fileInfo = new Mock(); fileInfo.Setup(f => f.PhysicalPath).Returns(viewPath); fileInfo.Setup(f => f.CreateReadStream()).Returns(Stream.Null); + var compiler = new Mock(); compiler.Setup(c => c.Compile(fileInfo.Object, It.IsAny())) .Returns(CompilationResult.Successful(typeof(RazorCompilationServiceTest))); - var razorService = new RazorCompilationService(compiler.Object, ap.Object, host.Object); + + var serviceProvider = new Mock(); + serviceProvider.Setup(sp => sp.GetService(It.Is(t => t == typeof(ICompilationService)))) + .Returns(compiler.Object); + + var razorService = new RazorCompilationService(serviceProvider.Object, ap.Object, host.Object); var relativeFileInfo = new RelativeFileInfo() { @@ -61,8 +68,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test var host = new Mock(); host.SetupAllProperties(); host.Setup(h => h.GenerateCode(It.IsAny(), It.IsAny())) - .Returns(GetGeneratorResult()); - var assemblyProvider = new Mock(); + .Returns(GetGeneratorResult()); var assemblyProvider = new Mock(); assemblyProvider.SetupGet(e => e.CandidateAssemblies) .Returns(Enumerable.Empty()); @@ -70,7 +76,11 @@ namespace Microsoft.AspNet.Mvc.Razor.Test compiler.Setup(c => c.Compile(It.IsAny(), It.IsAny())) .Returns(CompilationResult.Successful(GetType())); - var razorService = new RazorCompilationService(compiler.Object, assemblyProvider.Object, host.Object); + var serviceProvider = new Mock(); + serviceProvider.Setup(sp => sp.GetService(It.Is(t => t == typeof(ICompilationService)))) + .Returns(compiler.Object); + + var razorService = new RazorCompilationService(serviceProvider.Object, assemblyProvider.Object, host.Object); var relativeFileInfo = new RelativeFileInfo() { FileInfo = Mock.Of(),