Remove enableInstrumentation from CompilerCache and IMvcRazorHost

This commit is contained in:
Pranav K 2014-10-28 15:34:09 -07:00
parent 4720381d78
commit 74da350086
14 changed files with 47 additions and 123 deletions

View File

@ -11,11 +11,6 @@ namespace Microsoft.AspNet.Mvc.Razor
/// </summary> /// </summary>
public interface IMvcRazorHost public interface IMvcRazorHost
{ {
/// <summary>
/// Flag that indicates if page execution instrumentation code should be injected into the output.
/// </summary>
bool EnableInstrumentation { get; set; }
/// <summary> /// <summary>
/// Parses and generates the contents of a Razor file represented by <paramref name="inputStream"/>. /// Parses and generates the contents of a Razor file represented by <paramref name="inputStream"/>.
/// </summary> /// </summary>

View File

@ -62,6 +62,8 @@ namespace Microsoft.AspNet.Mvc.Razor
TagHelperDescriptorResolver = new TagHelperDescriptorResolver(); TagHelperDescriptorResolver = new TagHelperDescriptorResolver();
DefaultBaseClass = BaseType + '<' + DefaultModel + '>'; DefaultBaseClass = BaseType + '<' + DefaultModel + '>';
DefaultNamespace = "Asp"; DefaultNamespace = "Asp";
// Enable instrumentation by default to allow precompiled views to work with BrowserLink.
EnableInstrumentation = true;
GeneratedClassContext = new GeneratedClassContext( GeneratedClassContext = new GeneratedClassContext(
executeMethodName: "ExecuteAsync", executeMethodName: "ExecuteAsync",
writeMethodName: "Write", writeMethodName: "Write",

View File

@ -74,24 +74,19 @@ namespace Microsoft.AspNet.Mvc.Razor
/// <inheritdoc /> /// <inheritdoc />
public CompilationResult GetOrAdd([NotNull] RelativeFileInfo fileInfo, public CompilationResult GetOrAdd([NotNull] RelativeFileInfo fileInfo,
bool enableInstrumentation,
[NotNull] Func<CompilationResult> compile) [NotNull] Func<CompilationResult> compile)
{ {
CompilerCacheEntry cacheEntry; CompilerCacheEntry cacheEntry;
if (!_cache.TryGetValue(NormalizePath(fileInfo.RelativePath), out cacheEntry)) if (!_cache.TryGetValue(NormalizePath(fileInfo.RelativePath), out cacheEntry))
{ {
return OnCacheMiss(fileInfo, enableInstrumentation, compile); return OnCacheMiss(fileInfo, compile);
} }
else else
{ {
if ((cacheEntry.Length != fileInfo.FileInfo.Length) || if (cacheEntry.Length != fileInfo.FileInfo.Length)
(enableInstrumentation && !cacheEntry.IsInstrumented))
{ {
// Recompile if // Recompile if the file lengths differ
// (a) If the file lengths differ return OnCacheMiss(fileInfo, compile);
// (b) If the compiled type is not instrumented but we require it to be instrumented.
return OnCacheMiss(fileInfo, enableInstrumentation, compile);
} }
if (cacheEntry.LastModified == fileInfo.FileInfo.LastModified) if (cacheEntry.LastModified == fileInfo.FileInfo.LastModified)
@ -108,22 +103,20 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
// Cache hit, but we need to update the entry // Cache hit, but we need to update the entry
return OnCacheMiss(fileInfo, return OnCacheMiss(fileInfo,
enableInstrumentation,
() => CompilationResult.Successful(cacheEntry.CompiledType)); () => CompilationResult.Successful(cacheEntry.CompiledType));
} }
// it's not a match, recompile // it's not a match, recompile
return OnCacheMiss(fileInfo, enableInstrumentation, compile); return OnCacheMiss(fileInfo, compile);
} }
} }
private CompilationResult OnCacheMiss(RelativeFileInfo file, private CompilationResult OnCacheMiss(RelativeFileInfo file,
bool isInstrumented,
Func<CompilationResult> compile) Func<CompilationResult> compile)
{ {
var result = compile(); var result = compile();
var cacheEntry = new CompilerCacheEntry(file, result.CompiledType, isInstrumented); var cacheEntry = new CompilerCacheEntry(file, result.CompiledType);
_cache[NormalizePath(file.RelativePath)] = cacheEntry; _cache[NormalizePath(file.RelativePath)] = cacheEntry;
return result; return result;

View File

@ -22,8 +22,6 @@ namespace Microsoft.AspNet.Mvc.Razor
Length = info.Length; Length = info.Length;
LastModified = info.LastModified; LastModified = info.LastModified;
Hash = info.Hash; Hash = info.Hash;
// Precompiled views are always instrumented.
IsInstrumented = true;
} }
/// <summary> /// <summary>
@ -31,15 +29,12 @@ namespace Microsoft.AspNet.Mvc.Razor
/// </summary> /// </summary>
/// <param name="info">Metadata about the file that was compiled.</param> /// <param name="info">Metadata about the file that was compiled.</param>
/// <param name="compiledType">The compiled <see cref="Type"/>.</param> /// <param name="compiledType">The compiled <see cref="Type"/>.</param>
/// <param name="isInstrumented">Flag that indicates that the file was generated with instrumentation public CompilerCacheEntry([NotNull] RelativeFileInfo info, [NotNull] Type compiledType)
/// enabled.</param>
public CompilerCacheEntry([NotNull] RelativeFileInfo info, [NotNull] Type compiledType, bool isInstrumented)
{ {
CompiledType = compiledType; CompiledType = compiledType;
RelativePath = info.RelativePath; RelativePath = info.RelativePath;
Length = info.FileInfo.Length; Length = info.FileInfo.Length;
LastModified = info.FileInfo.LastModified; LastModified = info.FileInfo.LastModified;
IsInstrumented = isInstrumented;
} }
/// <summary> /// <summary>
@ -71,10 +66,5 @@ namespace Microsoft.AspNet.Mvc.Razor
/// Gets a flag that indicates if the file is precompiled. /// Gets a flag that indicates if the file is precompiled.
/// </summary> /// </summary>
public bool IsPreCompiled { get { return Hash != null; } } public bool IsPreCompiled { get { return Hash != null; } }
/// <summary>
/// Gets a flag that indiciates if the page execution in <see cref="CompiledType"/> is instrumeted.
/// </summary>
public bool IsInstrumented { get; private set; }
} }
} }

View File

@ -15,11 +15,9 @@ namespace Microsoft.AspNet.Mvc.Razor
/// not available in the cache. /// not available in the cache.
/// </summary> /// </summary>
/// <param name="fileInfo">A <see cref="RelativeFileInfo"/> representing the file.</param> /// <param name="fileInfo">A <see cref="RelativeFileInfo"/> representing the file.</param>
/// <param name="enableInstrumentation"><see langword="true"/> to generate instrumentation.</param>
/// <param name="compile">An delegate that will generate a compilation result.</param> /// <param name="compile">An delegate that will generate a compilation result.</param>
/// <returns>A cached <see cref="CompilationResult"/>.</returns> /// <returns>A cached <see cref="CompilationResult"/>.</returns>
CompilationResult GetOrAdd([NotNull] RelativeFileInfo fileInfo, CompilationResult GetOrAdd([NotNull] RelativeFileInfo fileInfo,
bool enableInstrumentation,
[NotNull] Func<CompilationResult> compile); [NotNull] Func<CompilationResult> compile);
} }
} }

View File

@ -13,10 +13,9 @@ namespace Microsoft.AspNet.Mvc.Razor
/// </summary> /// </summary>
/// <param name="fileInfo">A <see cref="RelativeFileInfo"/> instance that represents the file to compile. /// <param name="fileInfo">A <see cref="RelativeFileInfo"/> instance that represents the file to compile.
/// </param> /// </param>
/// <param name="isInstrumented">Indicates that the page should be instrumented.</param>
/// <returns> /// <returns>
/// A <see cref="CompilationResult"/> that represents the results of parsing and compiling the file. /// A <see cref="CompilationResult"/> that represents the results of parsing and compiling the file.
/// </returns> /// </returns>
CompilationResult Compile(RelativeFileInfo fileInfo, bool isInstrumented); CompilationResult Compile(RelativeFileInfo fileInfo);
} }
} }

View File

@ -32,7 +32,6 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
_serviceProvider = designTimeServiceProvider; _serviceProvider = designTimeServiceProvider;
_host = host; _host = host;
_host.EnableInstrumentation = true;
var appEnv = _serviceProvider.GetRequiredService<IApplicationEnvironment>(); var appEnv = _serviceProvider.GetRequiredService<IApplicationEnvironment>();
_fileSystem = optionsAccessor.Options.FileSystem; _fileSystem = optionsAccessor.Options.FileSystem;

View File

@ -22,10 +22,8 @@ namespace Microsoft.AspNet.Mvc.Razor
} }
/// <inheritdoc /> /// <inheritdoc />
public CompilationResult Compile([NotNull] RelativeFileInfo file, bool isInstrumented) public CompilationResult Compile([NotNull] RelativeFileInfo file)
{ {
_razorHost.EnableInstrumentation = isInstrumented;
GeneratorResults results; GeneratorResults results;
using (var inputStream = file.FileInfo.CreateReadStream()) using (var inputStream = file.FileInfo.CreateReadStream())
{ {

View File

@ -18,20 +18,17 @@ namespace Microsoft.AspNet.Mvc.Razor
private readonly IServiceProvider _serviceProvider; private readonly IServiceProvider _serviceProvider;
private readonly IFileInfoCache _fileInfoCache; private readonly IFileInfoCache _fileInfoCache;
private readonly ICompilerCache _compilerCache; private readonly ICompilerCache _compilerCache;
private readonly bool _isInstrumentationEnabled;
private IRazorCompilationService _razorcompilationService; private IRazorCompilationService _razorcompilationService;
public VirtualPathRazorPageFactory(ITypeActivator typeActivator, public VirtualPathRazorPageFactory(ITypeActivator typeActivator,
IServiceProvider serviceProvider, IServiceProvider serviceProvider,
ICompilerCache compilerCache, ICompilerCache compilerCache,
IFileInfoCache fileInfoCache, IFileInfoCache fileInfoCache)
IContextAccessor<HttpContext> contextAccessor)
{ {
_activator = typeActivator; _activator = typeActivator;
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
_compilerCache = compilerCache; _compilerCache = compilerCache;
_fileInfoCache = fileInfoCache; _fileInfoCache = fileInfoCache;
_isInstrumentationEnabled = IsInstrumentationEnabled(contextAccessor.Value);
} }
private IRazorCompilationService RazorCompilationService private IRazorCompilationService RazorCompilationService
@ -71,8 +68,7 @@ namespace Microsoft.AspNet.Mvc.Razor
var result = _compilerCache.GetOrAdd( var result = _compilerCache.GetOrAdd(
relativeFileInfo, relativeFileInfo,
_isInstrumentationEnabled, () => RazorCompilationService.Compile(relativeFileInfo));
() => RazorCompilationService.Compile(relativeFileInfo, _isInstrumentationEnabled));
var page = (IRazorPage)_activator.CreateInstance(_serviceProvider, result.CompiledType); var page = (IRazorPage)_activator.CreateInstance(_serviceProvider, result.CompiledType);
page.Path = relativePath; page.Path = relativePath;

View File

@ -12,6 +12,19 @@ namespace Microsoft.AspNet.Mvc.Razor
{ {
public class MvcRazorHostTest public class MvcRazorHostTest
{ {
[Fact]
public void MvcRazorHost_EnablesInstrumentationByDefault()
{
// Arrange
var host = new MvcRazorHost(new TestFileSystem());
// Act
var instrumented = host.EnableInstrumentation;
// Assert
Assert.True(instrumented);
}
[Fact] [Fact]
public void MvcRazorHost_GeneratesTagHelperModelExpressionCode_DesignTime() public void MvcRazorHost_GeneratesTagHelperModelExpressionCode_DesignTime()
{ {
@ -22,12 +35,12 @@ namespace Microsoft.AspNet.Mvc.Razor
}; };
var expectedLineMappings = new List<LineMapping> var expectedLineMappings = new List<LineMapping>
{ {
BuildLineMapping(documentAbsoluteIndex: 7, BuildLineMapping(documentAbsoluteIndex: 7,
documentLineIndex: 0, documentLineIndex: 0,
documentCharacterIndex: 7, documentCharacterIndex: 7,
generatedAbsoluteIndex: 444, generatedAbsoluteIndex: 444,
generatedLineIndex: 12, generatedLineIndex: 12,
generatedCharacterIndex: 7, generatedCharacterIndex: 7,
contentLength: 8), contentLength: 8),
BuildLineMapping(documentAbsoluteIndex: 33, BuildLineMapping(documentAbsoluteIndex: 33,
documentLineIndex: 2, documentLineIndex: 2,
@ -39,8 +52,8 @@ namespace Microsoft.AspNet.Mvc.Razor
}; };
// Act and Assert // Act and Assert
RunDesignTimeTest(host, RunDesignTimeTest(host,
testName: "ModelExpressionTagHelper", testName: "ModelExpressionTagHelper",
expectedLineMappings: expectedLineMappings); expectedLineMappings: expectedLineMappings);
} }

View File

@ -27,16 +27,24 @@ namespace Asp
#pragma warning disable 1998 #pragma warning disable 1998
public override async Task ExecuteAsync() public override async Task ExecuteAsync()
{ {
BeginContext(0, 4, true);
WriteLiteral("<div"); WriteLiteral("<div");
EndContext();
WriteAttribute("class", Tuple.Create(" class=\"", 4), Tuple.Create("\"", 17), WriteAttribute("class", Tuple.Create(" class=\"", 4), Tuple.Create("\"", 17),
Tuple.Create(Tuple.Create("", 12), Tuple.Create<System.Object, System.Int32>(logo, 12), false)); Tuple.Create(Tuple.Create("", 12), Tuple.Create<System.Object, System.Int32>(logo, 12), false));
BeginContext(18, 24, true);
WriteLiteral(">\r\n Hello world\r\n "); WriteLiteral(">\r\n Hello world\r\n ");
EndContext();
BeginContext(43, 21, false);
#line 3 "TestFiles/Input/Basic.cshtml" #line 3 "TestFiles/Input/Basic.cshtml"
Write(Html.Input("SomeKey")); Write(Html.Input("SomeKey"));
#line default #line default
#line hidden #line hidden
EndContext();
BeginContext(64, 8, true);
WriteLiteral("\r\n</div>"); WriteLiteral("\r\n</div>");
EndContext();
} }
#pragma warning restore 1998 #pragma warning restore 1998
} }

View File

@ -40,7 +40,9 @@ namespace Asp
#pragma warning disable 1998 #pragma warning disable 1998
public override async Task ExecuteAsync() public override async Task ExecuteAsync()
{ {
BeginContext(120, 2, true);
WriteLiteral("\r\n"); WriteLiteral("\r\n");
EndContext();
__tagHelperExecutionContext = __tagHelperScopeManager.Begin("inputTest"); __tagHelperExecutionContext = __tagHelperScopeManager.Begin("inputTest");
__Microsoft_AspNet_Mvc_Razor_InputTestTagHelper = CreateTagHelper<Microsoft.AspNet.Mvc.Razor.InputTestTagHelper>(); __Microsoft_AspNet_Mvc_Razor_InputTestTagHelper = CreateTagHelper<Microsoft.AspNet.Mvc.Razor.InputTestTagHelper>();
__tagHelperExecutionContext.Add(__Microsoft_AspNet_Mvc_Razor_InputTestTagHelper); __tagHelperExecutionContext.Add(__Microsoft_AspNet_Mvc_Razor_InputTestTagHelper);

View File

@ -34,7 +34,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
}; };
// Act // Act
var actual = cache.GetOrAdd(runtimeFileInfo, false, () => expected); var actual = cache.GetOrAdd(runtimeFileInfo, () => expected);
// Assert // Assert
Assert.Same(expected, actual); Assert.Same(expected, actual);
@ -140,8 +140,7 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
// Act // Act
var actual = cache.GetOrAdd(runtimeFileInfo, var actual = cache.GetOrAdd(runtimeFileInfo,
enableInstrumentation: false, compile: () => CompilationResult.Successful(resultViewType));
compile: () => CompilationResult.Successful(resultViewType));
// Assert // Assert
if (swapsPreCompile) if (swapsPreCompile)
@ -175,9 +174,9 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
}; };
// Act // Act
cache.GetOrAdd(runtimeFileInfo, false, () => uncachedResult); cache.GetOrAdd(runtimeFileInfo, () => uncachedResult);
var actual1 = cache.GetOrAdd(runtimeFileInfo, false, () => uncachedResult); var actual1 = cache.GetOrAdd(runtimeFileInfo, () => uncachedResult);
var actual2 = cache.GetOrAdd(runtimeFileInfo, false, () => uncachedResult); var actual2 = cache.GetOrAdd(runtimeFileInfo, () => uncachedResult);
// Assert // Assert
Assert.NotSame(uncachedResult, actual1); Assert.NotSame(uncachedResult, actual1);
@ -190,40 +189,5 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
Assert.Null(actual2.CompiledContent); Assert.Null(actual2.CompiledContent);
Assert.Same(type, actual2.CompiledType); Assert.Same(type, actual2.CompiledType);
} }
[Fact]
public void GetOrAdd_IgnoresCache_IfCachedItemIsNotInstrumentedAndEnableInstrumentationIsTrue()
{
// Arrange
var lastModified = DateTime.UtcNow;
var cache = new CompilerCache();
var fileInfo = new Mock<IFileInfo>();
fileInfo.SetupGet(f => f.PhysicalPath)
.Returns("test");
fileInfo.SetupGet(f => f.LastModified)
.Returns(lastModified);
var type = GetType();
var uncachedResult1 = UncachedCompilationResult.Successful(type, "hello world");
var uncachedResult2 = UncachedCompilationResult.Successful(typeof(object), "hello world");
var uncachedResult3 = UncachedCompilationResult.Successful(typeof(Guid), "hello world");
var runtimeFileInfo = new RelativeFileInfo()
{
FileInfo = fileInfo.Object,
RelativePath = "test",
};
// Act
cache.GetOrAdd(runtimeFileInfo, false, () => uncachedResult1);
var actual1 = cache.GetOrAdd(runtimeFileInfo, true, () => uncachedResult2);
var actual2 = cache.GetOrAdd(runtimeFileInfo, false, () => uncachedResult3);
// Assert
Assert.Same(uncachedResult2, actual1);
Assert.Same(typeof(object), actual1.CompiledType);
Assert.NotSame(actual2, uncachedResult3);
Assert.Same(typeof(object), actual2.CompiledType);
}
} }
} }

View File

@ -1,10 +1,7 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // 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. // 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.IO;
using System.Linq;
using System.Reflection;
using Microsoft.AspNet.FileSystems; using Microsoft.AspNet.FileSystems;
using Microsoft.AspNet.Razor; using Microsoft.AspNet.Razor;
using Microsoft.AspNet.Razor.Generator.Compiler; using Microsoft.AspNet.Razor.Generator.Compiler;
@ -44,42 +41,12 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
}; };
// Act // Act
razorService.Compile(relativeFileInfo, isInstrumented: false); razorService.Compile(relativeFileInfo);
// Assert // Assert
host.Verify(); host.Verify();
} }
[Theory]
[InlineData(false)]
[InlineData(true)]
public void CompileSetsEnableInstrumentationOnHost(bool enableInstrumentation)
{
// Arrange
var host = new Mock<IMvcRazorHost>();
host.SetupAllProperties();
host.Setup(h => h.GenerateCode(It.IsAny<string>(), It.IsAny<Stream>()))
.Returns(GetGeneratorResult());
var compiler = new Mock<ICompilationService>();
compiler.Setup(c => c.Compile(It.IsAny<IFileInfo>(), It.IsAny<string>()))
.Returns(CompilationResult.Successful(GetType()));
var razorService = new RazorCompilationService(compiler.Object, host.Object);
var relativeFileInfo = new RelativeFileInfo()
{
FileInfo = Mock.Of<IFileInfo>(),
RelativePath = @"views\index\home.cshtml",
};
// Act
razorService.Compile(relativeFileInfo, isInstrumented: enableInstrumentation);
// Assert
Assert.Equal(enableInstrumentation, host.Object.EnableInstrumentation);
}
private static GeneratorResults GetGeneratorResult() private static GeneratorResults GetGeneratorResult()
{ {
return new GeneratorResults( return new GeneratorResults(