Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/aspnetcore.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPranav K <prkrishn@hotmail.com>2021-10-27 00:29:34 +0300
committerGitHub <noreply@github.com>2021-10-27 00:29:34 +0300
commitae1a6cbe225b99c0bf38b7e31bf60cb653b73a52 (patch)
tree1aab32f6b5306c8fddc95c20b574ece0c0a70979
parent7c57ecbdfee67ad544bd655a757e03145f6122a2 (diff)
Ensure view caches are cleared when RazorHotReload.ClearCache is invoked (#37854)v6.0.0
-rw-r--r--src/Mvc/Mvc.Razor/src/Compilation/DefaultViewCompiler.cs2
-rw-r--r--src/Mvc/Mvc.Razor/src/Compilation/DefaultViewCompilerProvider.cs2
-rw-r--r--src/Mvc/Mvc.Razor/src/RazorHotReload.cs4
-rw-r--r--src/Mvc/Mvc.Razor/src/RazorPageActivator.cs4
-rw-r--r--src/Mvc/Mvc.Razor/src/RazorViewEngine.cs2
-rw-r--r--src/Mvc/Mvc.Razor/test/Compilation/DefaultViewCompilerTest.cs4
-rw-r--r--src/Mvc/Mvc.Razor/test/RazorHotReloadTest.cs86
7 files changed, 96 insertions, 8 deletions
diff --git a/src/Mvc/Mvc.Razor/src/Compilation/DefaultViewCompiler.cs b/src/Mvc/Mvc.Razor/src/Compilation/DefaultViewCompiler.cs
index 872692b11b..932320b784 100644
--- a/src/Mvc/Mvc.Razor/src/Compilation/DefaultViewCompiler.cs
+++ b/src/Mvc/Mvc.Razor/src/Compilation/DefaultViewCompiler.cs
@@ -74,6 +74,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Compilation
_compiledViews = compiledViews;
}
+ internal Dictionary<string, Task<CompiledViewDescriptor>>? CompiledViews => _compiledViews;
+
// Invoked as part of a hot reload event.
internal void ClearCache()
{
diff --git a/src/Mvc/Mvc.Razor/src/Compilation/DefaultViewCompilerProvider.cs b/src/Mvc/Mvc.Razor/src/Compilation/DefaultViewCompilerProvider.cs
index eee0073796..2a16ce1e1b 100644
--- a/src/Mvc/Mvc.Razor/src/Compilation/DefaultViewCompilerProvider.cs
+++ b/src/Mvc/Mvc.Razor/src/Compilation/DefaultViewCompilerProvider.cs
@@ -18,6 +18,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor.Compilation
_compiler = new DefaultViewCompiler(applicationPartManager, loggerFactory.CreateLogger<DefaultViewCompiler>());
}
+ internal DefaultViewCompiler Compiler => _compiler;
+
public IViewCompiler GetCompiler() => _compiler;
}
}
diff --git a/src/Mvc/Mvc.Razor/src/RazorHotReload.cs b/src/Mvc/Mvc.Razor/src/RazorHotReload.cs
index 6efeb0ac5d..d77bbae8eb 100644
--- a/src/Mvc/Mvc.Razor/src/RazorHotReload.cs
+++ b/src/Mvc/Mvc.Razor/src/RazorHotReload.cs
@@ -28,9 +28,9 @@ namespace Microsoft.AspNetCore.Mvc.Razor
// For Razor view services, use the service locator pattern because they views not be registered by default.
_razorCompiledItemFeatureProvider = applicationPartManager.FeatureProviders.OfType<RazorCompiledItemFeatureProvider>().FirstOrDefault();
- if (viewCompilerProvider is DefaultViewCompiler defaultViewCompiler)
+ if (viewCompilerProvider is DefaultViewCompilerProvider defaultViewCompilerProvider)
{
- _defaultViewCompiler = defaultViewCompiler;
+ _defaultViewCompiler = defaultViewCompilerProvider.Compiler;
}
if (razorViewEngine.GetType() == typeof(RazorViewEngine))
diff --git a/src/Mvc/Mvc.Razor/src/RazorPageActivator.cs b/src/Mvc/Mvc.Razor/src/RazorPageActivator.cs
index 064aaf636b..b250d1f43f 100644
--- a/src/Mvc/Mvc.Razor/src/RazorPageActivator.cs
+++ b/src/Mvc/Mvc.Razor/src/RazorPageActivator.cs
@@ -53,6 +53,8 @@ namespace Microsoft.AspNetCore.Mvc.Razor
_activationInfo.Clear();
}
+ internal ConcurrentDictionary<CacheKey, RazorPagePropertyActivator> ActivationInfo => _activationInfo;
+
/// <inheritdoc />
public void Activate(IRazorPage page, ViewContext context)
{
@@ -107,7 +109,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
return propertyActivator;
}
- private readonly struct CacheKey : IEquatable<CacheKey>
+ internal readonly struct CacheKey : IEquatable<CacheKey>
{
public CacheKey(Type pageType, Type? providedModelType)
{
diff --git a/src/Mvc/Mvc.Razor/src/RazorViewEngine.cs b/src/Mvc/Mvc.Razor/src/RazorViewEngine.cs
index 0d225bb9ed..99b3288712 100644
--- a/src/Mvc/Mvc.Razor/src/RazorViewEngine.cs
+++ b/src/Mvc/Mvc.Razor/src/RazorViewEngine.cs
@@ -89,7 +89,7 @@ namespace Microsoft.AspNetCore.Mvc.Razor
/// <summary>
/// A cache for results of view lookups.
/// </summary>
- protected IMemoryCache ViewLookupCache { get; private set; }
+ protected internal IMemoryCache ViewLookupCache { get; private set; }
/// <summary>
/// Gets the case-normalized route value for the specified route <paramref name="key"/>.
diff --git a/src/Mvc/Mvc.Razor/test/Compilation/DefaultViewCompilerTest.cs b/src/Mvc/Mvc.Razor/test/Compilation/DefaultViewCompilerTest.cs
index 9fc7a75199..ea227db36c 100644
--- a/src/Mvc/Mvc.Razor/test/Compilation/DefaultViewCompilerTest.cs
+++ b/src/Mvc/Mvc.Razor/test/Compilation/DefaultViewCompilerTest.cs
@@ -1,12 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
-using System.Collections.Generic;
-using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.Extensions.Logging.Abstractions;
-using Xunit;
namespace Microsoft.AspNetCore.Mvc.Razor.Compilation
{
diff --git a/src/Mvc/Mvc.Razor/test/RazorHotReloadTest.cs b/src/Mvc/Mvc.Razor/test/RazorHotReloadTest.cs
new file mode 100644
index 0000000000..de45a3ce06
--- /dev/null
+++ b/src/Mvc/Mvc.Razor/test/RazorHotReloadTest.cs
@@ -0,0 +1,86 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics;
+using Microsoft.AspNetCore.Mvc.ModelBinding;
+using Microsoft.AspNetCore.Mvc.Razor.Compilation;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+
+namespace Microsoft.AspNetCore.Mvc.Razor;
+
+public class RazorHotReloadTest
+{
+ [Fact]
+ public void ClearCache_CanClearViewCompiler()
+ {
+ // Regression test for https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1425693
+ // Arrange
+ var serviceProvider = GetServiceProvider();
+
+ var compilerProvider = Assert.IsType<DefaultViewCompilerProvider>(serviceProvider.GetRequiredService<IViewCompilerProvider>());
+ var hotReload = serviceProvider.GetRequiredService<RazorHotReload>();
+
+ // Act
+ hotReload.ClearCache(Type.EmptyTypes);
+
+ // Assert
+ Assert.Null(compilerProvider.Compiler.CompiledViews);
+ }
+
+ [Fact]
+ public void ClearCache_ResetsViewEngineLookupCache()
+ {
+ // Arrange
+ var serviceProvider = GetServiceProvider();
+
+ var viewEngine = Assert.IsType<RazorViewEngine>(serviceProvider.GetRequiredService<IRazorViewEngine>());
+ var hotReload = serviceProvider.GetRequiredService<RazorHotReload>();
+ var lookup = viewEngine.ViewLookupCache;
+
+ // Act
+ hotReload.ClearCache(Type.EmptyTypes);
+
+ // Assert
+ Assert.NotSame(lookup, viewEngine.ViewLookupCache);
+ }
+
+ [Fact]
+ public void ClearCache_ResetsRazorPageActivator()
+ {
+ // Arrange
+ var serviceProvider = GetServiceProvider();
+
+ var pageActivator = Assert.IsType<RazorPageActivator>(serviceProvider.GetRequiredService<IRazorPageActivator>());
+ var hotReload = serviceProvider.GetRequiredService<RazorHotReload>();
+ var cache = pageActivator.ActivationInfo;
+ cache[new RazorPageActivator.CacheKey()] = new RazorPagePropertyActivator(
+ typeof(string), typeof(object),
+ new EmptyModelMetadataProvider(),
+ new RazorPagePropertyActivator.PropertyValueAccessors());
+
+ // Act
+ Assert.Single(pageActivator.ActivationInfo);
+ hotReload.ClearCache(Type.EmptyTypes);
+
+ // Assert
+ Assert.Empty(pageActivator.ActivationInfo);
+ }
+
+ private static ServiceProvider GetServiceProvider()
+ {
+ var diagnosticListener = new DiagnosticListener("Microsoft.AspNetCore");
+
+ var serviceProvider = new ServiceCollection()
+ .AddControllersWithViews()
+ .Services
+ // Manually add RazorHotReload because it's only added if MetadataUpdateHandler.IsSupported = true
+ .AddSingleton<RazorHotReload>()
+ .AddSingleton<ILoggerFactory>(NullLoggerFactory.Instance)
+ .AddSingleton<DiagnosticSource>(diagnosticListener)
+ .AddSingleton(diagnosticListener)
+ .BuildServiceProvider();
+ return serviceProvider;
+ }
+}