parent
1dc4b28bbe
commit
304000095a
|
|
@ -59,7 +59,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
|
||||
foreach (var item in views)
|
||||
{
|
||||
var cacheEntry = new CompilerCacheResult(item.Key, new CompilationResult(item.Value));
|
||||
var cacheEntry = new CompilerCacheResult(item.Key, new CompilationResult(item.Value), isPrecompiled: true);
|
||||
_cache.Set(GetNormalizedPath(item.Key), Task.FromResult(cacheEntry));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,19 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="CompilerCacheResult"/> with the specified
|
||||
/// <see cref="Compilation.CompilationResult"/>.
|
||||
/// </summary>
|
||||
/// <param name="relativePath">Path of the view file relative to the application base.</param>
|
||||
/// <param name="compilationResult">The <see cref="Compilation.CompilationResult"/>.</param>
|
||||
/// <param name="isPrecompiled"><c>true</c> if the view is precompiled, <c>false</c> otherwise.</param>
|
||||
public CompilerCacheResult(string relativePath, CompilationResult compilationResult, bool isPrecompiled)
|
||||
: this(relativePath, compilationResult, EmptyArray<IChangeToken>.Instance)
|
||||
{
|
||||
IsPrecompiled = isPrecompiled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="CompilerCacheResult"/> with the specified
|
||||
/// <see cref="Compilation.CompilationResult"/>.
|
||||
|
|
@ -51,9 +64,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
|
||||
var propertyBindExpression = Expression.Bind(pathProperty, Expression.Constant(relativePath));
|
||||
var objectInitializeExpression = Expression.MemberInit(newExpression, propertyBindExpression);
|
||||
PageFactory = Expression
|
||||
PageFactory = Expression
|
||||
.Lambda<Func<IRazorPage>>(objectInitializeExpression)
|
||||
.Compile();
|
||||
IsPrecompiled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -71,6 +85,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
|
||||
ExpirationTokens = expirationTokens;
|
||||
PageFactory = null;
|
||||
IsPrecompiled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -87,5 +102,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
/// Gets a delegate that creates an instance of the <see cref="IRazorPage"/>.
|
||||
/// </summary>
|
||||
public Func<IRazorPage> PageFactory { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value that determines if the view is precompiled.
|
||||
/// </summary>
|
||||
public bool IsPrecompiled { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -62,7 +62,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
var result = CompilerCache.GetOrAdd(relativePath, _compileDelegate);
|
||||
if (result.Success)
|
||||
{
|
||||
return new RazorPageFactoryResult(result.PageFactory, result.ExpirationTokens);
|
||||
return new RazorPageFactoryResult(result.PageFactory, result.ExpirationTokens, result.IsPrecompiled);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
|
||||
private static readonly Action<ILogger, string, string, Exception> _viewLookupCacheMiss;
|
||||
private static readonly Action<ILogger, string, string, Exception> _viewLookupCacheHit;
|
||||
private static readonly Action<ILogger, string, Exception> _precompiledViewFound;
|
||||
|
||||
static MvcRazorLoggerExtensions()
|
||||
{
|
||||
|
|
@ -42,6 +43,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
2,
|
||||
"View lookup cache hit for view '{ViewName}' in controller '{ControllerName}'.");
|
||||
|
||||
_precompiledViewFound = LoggerMessage.Define<string>(
|
||||
LogLevel.Debug,
|
||||
3,
|
||||
"Using precompiled view for '{RelativePath}'.");
|
||||
|
||||
_generatedCodeToAssemblyCompilationStart = LoggerMessage.Define<string>(
|
||||
LogLevel.Debug,
|
||||
1,
|
||||
|
|
@ -79,6 +85,11 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
_viewLookupCacheHit(logger, viewName, controllerName, null);
|
||||
}
|
||||
|
||||
public static void PrecompiledViewFound(this ILogger logger, string relativePath)
|
||||
{
|
||||
_precompiledViewFound(logger, relativePath, null);
|
||||
}
|
||||
|
||||
public static void GeneratedCodeToAssemblyCompilationStart(this ILogger logger, string filePath)
|
||||
{
|
||||
_generatedCodeToAssemblyCompilationStart(logger, filePath, null);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
|||
|
||||
ExpirationTokens = expirationTokens;
|
||||
RazorPageFactory = null;
|
||||
IsPrecompiled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -37,6 +38,21 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
|||
public RazorPageFactoryResult(
|
||||
Func<IRazorPage> razorPageFactory,
|
||||
IList<IChangeToken> expirationTokens)
|
||||
: this(razorPageFactory, expirationTokens, isPrecompiled: false)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="RazorPageFactoryResult"/> with the
|
||||
/// specified <see cref="IRazorPage"/> factory.
|
||||
/// </summary>
|
||||
/// <param name="razorPageFactory">The <see cref="IRazorPage"/> factory.</param>
|
||||
/// <param name="expirationTokens">One or more <see cref="IChangeToken"/> instances.</param>
|
||||
/// <param name="isPrecompiled"><c>true</c> if the view is precompiled, <c>false</c> otherwise.</param>
|
||||
public RazorPageFactoryResult(
|
||||
Func<IRazorPage> razorPageFactory,
|
||||
IList<IChangeToken> expirationTokens,
|
||||
bool isPrecompiled)
|
||||
{
|
||||
if (razorPageFactory == null)
|
||||
{
|
||||
|
|
@ -50,6 +66,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
|||
|
||||
RazorPageFactory = razorPageFactory;
|
||||
ExpirationTokens = expirationTokens;
|
||||
IsPrecompiled = isPrecompiled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -68,5 +85,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
|||
/// Gets a value that determines if the page was successfully located.
|
||||
/// </summary>
|
||||
public bool Success => RazorPageFactory != null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value that determines if the view is precompiled.
|
||||
/// </summary>
|
||||
public bool IsPrecompiled { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -395,7 +395,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
|||
return ViewLookupCache.Set<ViewLocationCacheResult>(cacheKey, cacheResult, cacheEntryOptions);
|
||||
}
|
||||
|
||||
private ViewLocationCacheResult CreateCacheResult(
|
||||
// Internal for unit testing
|
||||
internal ViewLocationCacheResult CreateCacheResult(
|
||||
HashSet<IChangeToken> expirationTokens,
|
||||
string relativePath,
|
||||
bool isMainPage)
|
||||
|
|
@ -415,6 +416,10 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
|||
var viewStartPages = isMainPage ?
|
||||
GetViewStartPages(relativePath, expirationTokens) :
|
||||
EmptyArray<ViewLocationCacheItem>.Instance;
|
||||
if (factoryResult.IsPrecompiled)
|
||||
{
|
||||
_logger.PrecompiledViewFound(relativePath);
|
||||
}
|
||||
|
||||
return new ViewLocationCacheResult(
|
||||
new ViewLocationCacheItem(factoryResult.RazorPageFactory, relativePath),
|
||||
|
|
|
|||
|
|
@ -241,6 +241,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Internal
|
|||
|
||||
// Assert
|
||||
Assert.True(result.Success);
|
||||
Assert.True(result.IsPrecompiled);
|
||||
Assert.IsType<PreCompile>(result.PageFactory());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1283,6 +1283,35 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Test
|
|||
Assert.Equal(expected, result.SearchedLocations);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateCacheResult_LogsPrecompiledViewFound()
|
||||
{
|
||||
// Arrange
|
||||
var sink = new TestSink();
|
||||
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
||||
|
||||
var relativePath = "/Views/Foo/details.cshtml";
|
||||
var pageFactory = new Mock<IRazorPageFactoryProvider>();
|
||||
pageFactory
|
||||
.Setup(p => p.CreateFactory(relativePath))
|
||||
.Returns(new RazorPageFactoryResult(() => Mock.Of<IRazorPage>(), new IChangeToken[0], isPrecompiled: true))
|
||||
.Verifiable();
|
||||
|
||||
var viewEngine = new RazorViewEngine(
|
||||
pageFactory.Object,
|
||||
Mock.Of<IRazorPageActivator>(),
|
||||
new HtmlTestEncoder(),
|
||||
GetOptionsAccessor(expanders: null),
|
||||
loggerFactory);
|
||||
|
||||
// Act
|
||||
var result = viewEngine.CreateCacheResult(null, relativePath, false);
|
||||
|
||||
// Assert
|
||||
var logMessage = Assert.Single(sink.Writes);
|
||||
Assert.Equal($"Using precompiled view for '{relativePath}'.", logMessage.State.ToString());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("/Test-View.cshtml")]
|
||||
[InlineData("~/Test-View.CSHTML")]
|
||||
|
|
|
|||
Loading…
Reference in New Issue