diff --git a/src/Components/Authorization/src/AttributeAuthorizeDataCache.cs b/src/Components/Authorization/src/AttributeAuthorizeDataCache.cs
index 6f7f4bd06539..e37d2aed57d7 100644
--- a/src/Components/Authorization/src/AttributeAuthorizeDataCache.cs
+++ b/src/Components/Authorization/src/AttributeAuthorizeDataCache.cs
@@ -11,7 +11,7 @@ internal static class AttributeAuthorizeDataCache
{
static AttributeAuthorizeDataCache()
{
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied += ClearCache;
}
diff --git a/src/Components/Authorization/src/Microsoft.AspNetCore.Components.Authorization.csproj b/src/Components/Authorization/src/Microsoft.AspNetCore.Components.Authorization.csproj
index cef47c8d844d..5d715cb928ba 100644
--- a/src/Components/Authorization/src/Microsoft.AspNetCore.Components.Authorization.csproj
+++ b/src/Components/Authorization/src/Microsoft.AspNetCore.Components.Authorization.csproj
@@ -18,4 +18,8 @@
+
+
+
+
diff --git a/src/Components/Authorization/src/Properties/ILLink.Substitutions.xml b/src/Components/Authorization/src/Properties/ILLink.Substitutions.xml
new file mode 100644
index 000000000000..cf09080ae79b
--- /dev/null
+++ b/src/Components/Authorization/src/Properties/ILLink.Substitutions.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/src/Components/Components/src/BindConverter.cs b/src/Components/Components/src/BindConverter.cs
index a3e68de026a5..d4971de515d3 100644
--- a/src/Components/Components/src/BindConverter.cs
+++ b/src/Components/Components/src/BindConverter.cs
@@ -1670,7 +1670,7 @@ private static class FormatterDelegateCache
static FormatterDelegateCache()
{
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied += _cache.Clear;
}
@@ -1867,7 +1867,7 @@ internal static class ParserDelegateCache
static ParserDelegateCache()
{
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied += _cache.Clear;
}
diff --git a/src/Components/Components/src/ChangeDetection.cs b/src/Components/Components/src/ChangeDetection.cs
index 952debeb8f90..9fef8303d826 100644
--- a/src/Components/Components/src/ChangeDetection.cs
+++ b/src/Components/Components/src/ChangeDetection.cs
@@ -12,7 +12,7 @@ internal sealed class ChangeDetection
static ChangeDetection()
{
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied += _immutableObjectTypesCache.Clear;
}
diff --git a/src/Components/Components/src/ComponentFactory.cs b/src/Components/Components/src/ComponentFactory.cs
index a4b5aaa3224e..0b3d84796196 100644
--- a/src/Components/Components/src/ComponentFactory.cs
+++ b/src/Components/Components/src/ComponentFactory.cs
@@ -21,7 +21,7 @@ internal sealed class ComponentFactory
static ComponentFactory()
{
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied += ClearCache;
}
diff --git a/src/Components/Components/src/DefaultComponentActivator.cs b/src/Components/Components/src/DefaultComponentActivator.cs
index 24b92dcb1056..4e868cfcc4e6 100644
--- a/src/Components/Components/src/DefaultComponentActivator.cs
+++ b/src/Components/Components/src/DefaultComponentActivator.cs
@@ -14,7 +14,7 @@ internal sealed class DefaultComponentActivator(IServiceProvider serviceProvider
static DefaultComponentActivator()
{
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied += ClearCache;
}
diff --git a/src/Components/Components/src/DefaultComponentPropertyActivator.cs b/src/Components/Components/src/DefaultComponentPropertyActivator.cs
index 3fa29d33903c..396bba438a10 100644
--- a/src/Components/Components/src/DefaultComponentPropertyActivator.cs
+++ b/src/Components/Components/src/DefaultComponentPropertyActivator.cs
@@ -20,7 +20,7 @@ private const BindingFlags InjectablePropertyBindingFlags
static DefaultComponentPropertyActivator()
{
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied += ClearCache;
}
diff --git a/src/Components/Components/src/PersistentState/PersistentServicesRegistry.cs b/src/Components/Components/src/PersistentState/PersistentServicesRegistry.cs
index e27e5c2560b0..79d7be17618d 100644
--- a/src/Components/Components/src/PersistentState/PersistentServicesRegistry.cs
+++ b/src/Components/Components/src/PersistentState/PersistentServicesRegistry.cs
@@ -27,7 +27,7 @@ internal sealed class PersistentServicesRegistry
static PersistentServicesRegistry()
{
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied += _cachedAccessorsByType.Clear;
}
diff --git a/src/Components/Components/src/PersistentState/PersistentStateValueProviderKeyResolver.cs b/src/Components/Components/src/PersistentState/PersistentStateValueProviderKeyResolver.cs
index 8de18363342c..c12dbe12533d 100644
--- a/src/Components/Components/src/PersistentState/PersistentStateValueProviderKeyResolver.cs
+++ b/src/Components/Components/src/PersistentState/PersistentStateValueProviderKeyResolver.cs
@@ -18,7 +18,7 @@ internal static class PersistentStateValueProviderKeyResolver
static PersistentStateValueProviderKeyResolver()
{
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied += ClearCaches;
}
diff --git a/src/Components/Components/src/PersistentState/PersistentValueProviderComponentSubscription.cs b/src/Components/Components/src/PersistentState/PersistentValueProviderComponentSubscription.cs
index 35ad18735816..624439c8a592 100644
--- a/src/Components/Components/src/PersistentState/PersistentValueProviderComponentSubscription.cs
+++ b/src/Components/Components/src/PersistentState/PersistentValueProviderComponentSubscription.cs
@@ -21,7 +21,7 @@ internal partial class PersistentValueProviderComponentSubscription : IDisposabl
static PersistentValueProviderComponentSubscription()
{
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied += ClearCaches;
}
diff --git a/src/Components/Components/src/Properties/ILLink.Substitutions.xml b/src/Components/Components/src/Properties/ILLink.Substitutions.xml
index 6f45322d42d0..d069a5a3aa7f 100644
--- a/src/Components/Components/src/Properties/ILLink.Substitutions.xml
+++ b/src/Components/Components/src/Properties/ILLink.Substitutions.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/src/Components/Components/src/Reflection/ComponentProperties.cs b/src/Components/Components/src/Reflection/ComponentProperties.cs
index 353576925963..c5a49dfa3f80 100644
--- a/src/Components/Components/src/Reflection/ComponentProperties.cs
+++ b/src/Components/Components/src/Reflection/ComponentProperties.cs
@@ -14,7 +14,7 @@ internal static class ComponentProperties
{
static ComponentProperties()
{
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied += ClearCache;
}
diff --git a/src/Components/Components/src/RenderHandle.cs b/src/Components/Components/src/RenderHandle.cs
index edcb644bddfb..f6840d8c554a 100644
--- a/src/Components/Components/src/RenderHandle.cs
+++ b/src/Components/Components/src/RenderHandle.cs
@@ -49,7 +49,7 @@ public Dispatcher Dispatcher
///
/// Gets a value that determines if the is triggering a render in response to a metadata update (hot-reload) change.
///
- public bool IsRenderingOnMetadataUpdate => HotReloadManager.Default.MetadataUpdateSupported && (_renderer?.IsRenderingOnMetadataUpdate ?? false);
+ public bool IsRenderingOnMetadataUpdate => HotReloadManager.IsSupported && (_renderer?.IsRenderingOnMetadataUpdate ?? false);
internal bool IsRendererDisposed => _renderer?.Disposed
?? throw new InvalidOperationException("No renderer has been initialized.");
diff --git a/src/Components/Components/src/RenderTree/EventArgsTypeCache.cs b/src/Components/Components/src/RenderTree/EventArgsTypeCache.cs
index 5b9abafb0bed..82b6661b2f93 100644
--- a/src/Components/Components/src/RenderTree/EventArgsTypeCache.cs
+++ b/src/Components/Components/src/RenderTree/EventArgsTypeCache.cs
@@ -13,7 +13,7 @@ internal static class EventArgsTypeCache
static EventArgsTypeCache()
{
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied += Cache.Clear;
}
diff --git a/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs b/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs
index e61fb6d2d932..35ae4707692b 100644
--- a/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs
+++ b/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs
@@ -684,7 +684,7 @@ private static void AppendDiffEntriesForFramesWithSameSequence(
var oldParameters = new ParameterView(ParameterViewLifetime.Unbound, oldTree, oldFrameIndex);
var newParametersLifetime = new ParameterViewLifetime(diffContext.BatchBuilder);
var newParameters = new ParameterView(newParametersLifetime, newTree, newFrameIndex);
- var isHotReload = HotReloadManager.Default.MetadataUpdateSupported && diffContext.Renderer.IsRenderingOnMetadataUpdate;
+ var isHotReload = HotReloadManager.IsSupported && diffContext.Renderer.IsRenderingOnMetadataUpdate;
if (isHotReload && newParameters.HasRemovedDirectParameters(oldParameters))
{
@@ -754,13 +754,13 @@ private static string CreateDiffErrorMessage(ref DiffContext diffContext, int ne
{
var newTree = diffContext.NewTree;
var unsupportedFrameType = newTree[newFrameIndex].FrameTypeField;
-
+
// Build component hierarchy path
var componentPath = BuildComponentPath(diffContext.Renderer, diffContext.ComponentId);
-
+
// Build frame types descriptor
var frameTypesDescriptor = BuildFrameTypeDescriptor(newTree, newFrameIndex);
-
+
return $"Encountered an unsupported frame type during diffing {unsupportedFrameType} for Component Path: '{componentPath}' on tree with length '{newTree.Length}' and contents '{frameTypesDescriptor}'.";
}
@@ -771,7 +771,7 @@ private static string BuildFrameTypeDescriptor(RenderTreeFrame[] renderTree, int
{
frameTypes.Add(renderTree[i].FrameTypeField.ToString());
}
-
+
return string.Join(", ", frameTypes);
}
@@ -779,14 +779,14 @@ private static string BuildComponentPath(Renderer renderer, int componentId)
{
var componentPath = new List();
var currentComponentState = renderer.GetRequiredComponentState(componentId);
-
+
while (currentComponentState is not null)
{
var componentType = currentComponentState.Component.GetType();
componentPath.Insert(0, componentType.Name);
currentComponentState = currentComponentState.ParentComponentState;
}
-
+
return string.Join(" -> ", componentPath);
}
diff --git a/src/Components/Components/src/RenderTree/Renderer.cs b/src/Components/Components/src/RenderTree/Renderer.cs
index 0f5f7f23a24a..ba6f72512ae2 100644
--- a/src/Components/Components/src/RenderTree/Renderer.cs
+++ b/src/Components/Components/src/RenderTree/Renderer.cs
@@ -120,7 +120,7 @@ public Renderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory,
internal ICascadingValueSupplier[] ServiceProviderCascadingValueSuppliers { get; }
- internal HotReloadManager HotReloadManager { get; set; } = HotReloadManager.Default;
+ internal HotReloadManager? HotReloadManager { get; set; } = HotReloadManager.IsSupported ? HotReloadManager.Default : null;
private static IComponentActivator GetComponentActivatorOrDefault(IServiceProvider serviceProvider)
{
@@ -243,7 +243,7 @@ protected internal int AssignRootComponentId(IComponent component)
if (!_hotReloadInitialized)
{
_hotReloadInitialized = true;
- if (HotReloadManager.MetadataUpdateSupported)
+ if (HotReload.HotReloadManager.IsSupported && HotReloadManager != null)
{
// Capture the current ExecutionContext so AsyncLocal values present during initial root component
// registration flow through to hot reload re-renders. Without this, hot reload callbacks execute
@@ -308,7 +308,7 @@ protected internal async Task RenderRootComponentAsync(int componentId, Paramete
_pendingTasks ??= new();
var componentState = GetRequiredRootComponentState(componentId);
- if (HotReloadManager.MetadataUpdateSupported)
+ if (HotReload.HotReloadManager.IsSupported && HotReloadManager != null)
{
// When we're doing hot-reload, stash away the parameters used while rendering root components.
// We'll use this to trigger re-renders on hot reload updates.
@@ -338,7 +338,7 @@ protected internal void RemoveRootComponent(int componentId)
// Currently there's no known scenario where we need to support calling RemoveRootComponentAsync
// during a batch, but if a scenario emerges we can add support.
_batchBuilder.ComponentDisposalQueue.Enqueue(componentId);
- if (HotReloadManager.MetadataUpdateSupported)
+ if (HotReload.HotReloadManager.IsSupported && HotReloadManager != null)
{
_rootComponentsLatestParameters?.Remove(componentId);
}
@@ -1253,7 +1253,7 @@ protected virtual void Dispose(bool disposing)
_rendererIsDisposed = true;
}
- if (_hotReloadInitialized && HotReloadManager.MetadataUpdateSupported && _hotReloadRenderHandler is not null)
+ if (HotReload.HotReloadManager.IsSupported && HotReloadManager != null && _hotReloadInitialized && _hotReloadRenderHandler is not null)
{
HotReloadManager.OnDeltaApplied -= _hotReloadRenderHandler.RerenderOnHotReload;
}
diff --git a/src/Components/Components/src/RouteView.cs b/src/Components/Components/src/RouteView.cs
index 36560a2aa342..ab40bf32f14b 100644
--- a/src/Components/Components/src/RouteView.cs
+++ b/src/Components/Components/src/RouteView.cs
@@ -22,7 +22,7 @@ public class RouteView : IComponent
static RouteView()
{
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied += _layoutAttributeCache.Clear;
}
diff --git a/src/Components/Components/src/Routing/RouteTable.cs b/src/Components/Components/src/Routing/RouteTable.cs
index f56beec826b9..b868d145d9bf 100644
--- a/src/Components/Components/src/Routing/RouteTable.cs
+++ b/src/Components/Components/src/Routing/RouteTable.cs
@@ -16,7 +16,7 @@ internal sealed class RouteTable(TreeRouter treeRouter)
static RouteTable()
{
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied += _routeEntryCache.Clear;
}
diff --git a/src/Components/Components/src/Routing/Router.cs b/src/Components/Components/src/Routing/Router.cs
index c52a818767e3..002a48fa69bf 100644
--- a/src/Components/Components/src/Routing/Router.cs
+++ b/src/Components/Components/src/Routing/Router.cs
@@ -111,7 +111,7 @@ public void Attach(RenderHandle renderHandle)
NavigationManager.OnNotFound += OnNotFound;
RoutingStateProvider = ServiceProvider.GetService();
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied += ClearRouteCaches;
}
@@ -179,7 +179,7 @@ public void Dispose()
{
NavigationManager.LocationChanged -= OnLocationChanged;
NavigationManager.OnNotFound -= OnNotFound;
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied -= ClearRouteCaches;
}
diff --git a/src/Components/Components/test/Microsoft.AspNetCore.Components.Tests.csproj b/src/Components/Components/test/Microsoft.AspNetCore.Components.Tests.csproj
index 012c36a3c274..25a12fa2bdb9 100644
--- a/src/Components/Components/test/Microsoft.AspNetCore.Components.Tests.csproj
+++ b/src/Components/Components/test/Microsoft.AspNetCore.Components.Tests.csproj
@@ -3,6 +3,8 @@
$(DefaultNetCoreTargetFramework)
Microsoft.AspNetCore.Components
+
+ true
diff --git a/src/Components/Components/test/RendererTest.cs b/src/Components/Components/test/RendererTest.cs
index 56fc26840edd..b672dcaf867a 100644
--- a/src/Components/Components/test/RendererTest.cs
+++ b/src/Components/Components/test/RendererTest.cs
@@ -4982,33 +4982,42 @@ public async Task DisposeAsyncCallsComponentDisposeAsyncOnSyncContext()
}
[Fact]
- public async Task NoHotReloadListenersAreRegistered_WhenMetadataUpdatesAreNotSupported()
+ public async Task NoHotReloadListenersAreRegistered_WhenHotReloadIsDisabled()
{
// Arrange
- await using var renderer = new TestRenderer();
- var hotReloadManager = new HotReloadManager { MetadataUpdateSupported = false };
- renderer.HotReloadManager = hotReloadManager;
- var component = new TestComponent(builder =>
+ try
{
- builder.OpenElement(0, "h2");
- builder.AddContent(1, "some text");
- builder.CloseElement();
- });
+ AppContext.SetSwitch("System.Reflection.Metadata.MetadataUpdater.IsSupported", false);
+ await using var renderer = new TestRenderer();
+ var hotReloadManager = new HotReloadManager();
+ renderer.HotReloadManager = hotReloadManager;
+ var component = new TestComponent(builder =>
+ {
+ builder.OpenElement(0, "h2");
+ builder.AddContent(1, "some text");
+ builder.CloseElement();
+ });
- // Act
- var componentId = renderer.AssignRootComponentId(component);
- component.TriggerRender();
- Assert.False(hotReloadManager.IsSubscribedTo);
+ // Act
+ var componentId = renderer.AssignRootComponentId(component);
+ component.TriggerRender();
+ Assert.False(hotReloadManager.IsSubscribedTo);
- await renderer.DisposeAsync();
+ await renderer.DisposeAsync();
+ }
+ finally
+ {
+ AppContext.SetSwitch("System.Reflection.Metadata.MetadataUpdater.IsSupported", true);
+ }
}
[Fact]
public async Task DisposingRenderer_UnsubsribesFromHotReloadManager()
{
// Arrange
+ AppContext.SetSwitch("System.Reflection.Metadata.MetadataUpdater.IsSupported", true);
var renderer = new TestRenderer();
- var hotReloadManager = new HotReloadManager { MetadataUpdateSupported = true };
+ var hotReloadManager = new HotReloadManager();
renderer.HotReloadManager = hotReloadManager;
var component = new TestComponent(builder =>
{
@@ -5031,11 +5040,12 @@ public async Task DisposingRenderer_UnsubsribesFromHotReloadManager()
[Fact]
public async Task HotReload_ReRenderPreservesAsyncLocalValues()
{
+ AppContext.SetSwitch("System.Reflection.Metadata.MetadataUpdater.IsSupported", true);
+
await using var renderer = new TestRenderer();
- var hotReloadManager = new HotReloadManager { MetadataUpdateSupported = true };
+ var hotReloadManager = new HotReloadManager();
renderer.HotReloadManager = hotReloadManager;
- HotReloadManager.Default.MetadataUpdateSupported = true;
var component = new AsyncLocalCaptureComponent();
@@ -5223,7 +5233,7 @@ public void RenderFragmentContravariance_WorksWithInterfaceHierarchy()
{
// C# variance only works with reference types. This test uses interface hierarchy.
// IComparable is contravariant, so we can demonstrate the concept
-
+
// Arrange - Create a fragment that accepts any IComparable
RenderFragment baseFragment = (IComparable value) => builder =>
{
@@ -5244,7 +5254,7 @@ public void RenderFragmentContravariance_WorksWithInterfaceHierarchy()
public void RenderFragmentContravariance_WorksWithObjectToPrimitiveWrapper()
{
// For value types, contravariance only works when going through object (boxing)
-
+
// Arrange - Create a fragment that accepts object
RenderFragment
+
+
+
+
diff --git a/src/Components/Endpoints/src/Properties/ILLink.Substitutions.xml b/src/Components/Endpoints/src/Properties/ILLink.Substitutions.xml
new file mode 100644
index 000000000000..367ba717e59d
--- /dev/null
+++ b/src/Components/Endpoints/src/Properties/ILLink.Substitutions.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/src/Components/Endpoints/src/Rendering/EndpointComponentState.cs b/src/Components/Endpoints/src/Rendering/EndpointComponentState.cs
index 6c03d0585f2f..f76bdc40a236 100644
--- a/src/Components/Endpoints/src/Rendering/EndpointComponentState.cs
+++ b/src/Components/Endpoints/src/Rendering/EndpointComponentState.cs
@@ -19,7 +19,7 @@ internal sealed class EndpointComponentState : ComponentState
static EndpointComponentState()
{
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied += _streamRenderingAttributeByComponentType.Clear;
}
diff --git a/src/Components/Forms/src/FieldIdentifier.cs b/src/Components/Forms/src/FieldIdentifier.cs
index 5764b018e4ce..bd66ae25ae43 100644
--- a/src/Components/Forms/src/FieldIdentifier.cs
+++ b/src/Components/Forms/src/FieldIdentifier.cs
@@ -20,7 +20,7 @@ namespace Microsoft.AspNetCore.Components.Forms;
static FieldIdentifier()
{
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied += ClearCache;
}
diff --git a/src/Components/Forms/src/Microsoft.AspNetCore.Components.Forms.csproj b/src/Components/Forms/src/Microsoft.AspNetCore.Components.Forms.csproj
index c92fe86008f3..5f068882fb38 100644
--- a/src/Components/Forms/src/Microsoft.AspNetCore.Components.Forms.csproj
+++ b/src/Components/Forms/src/Microsoft.AspNetCore.Components.Forms.csproj
@@ -23,4 +23,8 @@
+
+
+
+
diff --git a/src/Components/Forms/src/Properties/ILLink.Substitutions.xml b/src/Components/Forms/src/Properties/ILLink.Substitutions.xml
new file mode 100644
index 000000000000..367ba717e59d
--- /dev/null
+++ b/src/Components/Forms/src/Properties/ILLink.Substitutions.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj b/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj
index 3efe5346b208..72809b5d3b3c 100644
--- a/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj
+++ b/src/Components/Server/src/Microsoft.AspNetCore.Components.Server.csproj
@@ -114,4 +114,8 @@
+
+
+
+
diff --git a/src/Components/Server/src/Properties/ILLink.Substitutions.xml b/src/Components/Server/src/Properties/ILLink.Substitutions.xml
new file mode 100644
index 000000000000..ec8951251310
--- /dev/null
+++ b/src/Components/Server/src/Properties/ILLink.Substitutions.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/src/Components/Shared/src/ExpressionFormatting/ExpressionFormatter.cs b/src/Components/Shared/src/ExpressionFormatting/ExpressionFormatter.cs
index fa2febd3754e..8682810448fe 100644
--- a/src/Components/Shared/src/ExpressionFormatting/ExpressionFormatter.cs
+++ b/src/Components/Shared/src/ExpressionFormatting/ExpressionFormatter.cs
@@ -14,7 +14,7 @@ internal static class ExpressionFormatter
{
static ExpressionFormatter()
{
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied += ClearCache;
}
@@ -77,7 +77,7 @@ public static string FormatLambda(LambdaExpression expression, string? prefix =
builder.InsertFront("]");
FormatIndexArgument(methodCallExpression.Arguments[0], ref builder);
builder.InsertFront("[");
-
+
break;
case ExpressionType.ArrayIndex:
diff --git a/src/Components/Shared/src/HotReloadManager.cs b/src/Components/Shared/src/HotReloadManager.cs
index f3ca59cf2651..ab01a8f04f39 100644
--- a/src/Components/Shared/src/HotReloadManager.cs
+++ b/src/Components/Shared/src/HotReloadManager.cs
@@ -1,6 +1,7 @@
// 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.CodeAnalysis;
using System.Reflection.Metadata;
using Microsoft.AspNetCore.Components.HotReload;
@@ -12,7 +13,9 @@ internal sealed class HotReloadManager
{
public static readonly HotReloadManager Default = new();
- public bool MetadataUpdateSupported { get; set; } = MetadataUpdater.IsSupported;
+ [FeatureSwitchDefinition("System.Reflection.Metadata.MetadataUpdater.IsSupported")]
+ internal static bool IsSupported =>
+ AppContext.TryGetSwitch("System.Reflection.Metadata.MetadataUpdater.IsSupported", out bool isSupported) ? isSupported : true;
///
/// Gets a value that determines if OnDeltaApplied is subscribed to.
diff --git a/src/Components/Shared/src/RootTypeCache.cs b/src/Components/Shared/src/RootTypeCache.cs
index 016ab5acd814..e9ef1bad55ca 100644
--- a/src/Components/Shared/src/RootTypeCache.cs
+++ b/src/Components/Shared/src/RootTypeCache.cs
@@ -19,7 +19,7 @@ internal sealed class RootTypeCache : IDisposable
public RootTypeCache()
{
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied += ClearCache;
}
@@ -29,7 +29,7 @@ public RootTypeCache()
public void Dispose()
{
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied -= ClearCache;
}
diff --git a/src/Components/Web/src/Forms/ExpressionMemberAccessor.cs b/src/Components/Web/src/Forms/ExpressionMemberAccessor.cs
index e1a81d4f0062..f6b971081225 100644
--- a/src/Components/Web/src/Forms/ExpressionMemberAccessor.cs
+++ b/src/Components/Web/src/Forms/ExpressionMemberAccessor.cs
@@ -17,7 +17,7 @@ internal static class ExpressionMemberAccessor
static ExpressionMemberAccessor()
{
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied += ClearCache;
}
diff --git a/src/Components/Web/src/JSComponents/JSComponentInterop.cs b/src/Components/Web/src/JSComponents/JSComponentInterop.cs
index 9df1c3288f71..8fdf4785152a 100644
--- a/src/Components/Web/src/JSComponents/JSComponentInterop.cs
+++ b/src/Components/Web/src/JSComponents/JSComponentInterop.cs
@@ -27,7 +27,7 @@ public class JSComponentInterop
static JSComponentInterop()
{
- if (HotReloadManager.Default.MetadataUpdateSupported)
+ if (HotReloadManager.IsSupported)
{
HotReloadManager.Default.OnDeltaApplied += ParameterTypeCaches.Clear;
}
diff --git a/src/Components/WebAssembly/WebAssembly/src/Properties/ILLink.Substitutions.xml b/src/Components/WebAssembly/WebAssembly/src/Properties/ILLink.Substitutions.xml
index 867efb0dfbd9..ec4d41761279 100644
--- a/src/Components/WebAssembly/WebAssembly/src/Properties/ILLink.Substitutions.xml
+++ b/src/Components/WebAssembly/WebAssembly/src/Properties/ILLink.Substitutions.xml
@@ -1,5 +1,8 @@
+
+
+
diff --git a/src/Components/test/E2ETest/Infrastructure/ServerFixtures/BasicTestAppServerSiteFixture.cs b/src/Components/test/E2ETest/Infrastructure/ServerFixtures/BasicTestAppServerSiteFixture.cs
index 20bb845423b8..61a5e6790d40 100644
--- a/src/Components/test/E2ETest/Infrastructure/ServerFixtures/BasicTestAppServerSiteFixture.cs
+++ b/src/Components/test/E2ETest/Infrastructure/ServerFixtures/BasicTestAppServerSiteFixture.cs
@@ -1,10 +1,17 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Reflection;
+
namespace Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
public class BasicTestAppServerSiteFixture : AspNetSiteServerFixture where TStartup : class
{
+ public readonly bool TestTrimmedOrMultithreadingApps = typeof(BasicTestAppServerSiteFixture<>).Assembly
+ .GetCustomAttributes()
+ .First(m => m.Key == "Microsoft.AspNetCore.E2ETesting.TestTrimmedOrMultithreadingApps")
+ .Value == "true";
+
public BasicTestAppServerSiteFixture()
{
ApplicationAssembly = typeof(TStartup).Assembly;
diff --git a/src/Components/test/E2ETest/ServerExecutionTests/HotReloadTest.cs b/src/Components/test/E2ETest/ServerExecutionTests/HotReloadTest.cs
index e17c426583b9..5993d0e823de 100644
--- a/src/Components/test/E2ETest/ServerExecutionTests/HotReloadTest.cs
+++ b/src/Components/test/E2ETest/ServerExecutionTests/HotReloadTest.cs
@@ -36,6 +36,12 @@ protected override void InitializeAsyncCore()
[Fact]
public async Task InvokingRender_CausesComponentToRender()
{
+ if (_serverFixture.TestTrimmedOrMultithreadingApps)
+ {
+ // In published app, metrics are trimmed
+ return;
+ }
+
Browser.Equal("This component was rendered 1 time(s).", () => Browser.Exists(By.TagName("h2")).Text);
Browser.Equal("Initial title", () => Browser.Exists(By.TagName("h3")).Text);
Browser.Equal("Component with ShouldRender=false was rendered 1 time(s).", () => Browser.Exists(By.TagName("h4")).Text);
diff --git a/src/Components/test/E2ETest/Tests/WebAssemblyTrimmingTest.cs b/src/Components/test/E2ETest/Tests/WebAssemblyTrimmingTest.cs
index 49587e420985..cf11b68b1790 100644
--- a/src/Components/test/E2ETest/Tests/WebAssemblyTrimmingTest.cs
+++ b/src/Components/test/E2ETest/Tests/WebAssemblyTrimmingTest.cs
@@ -27,6 +27,24 @@ protected override void InitializeAsyncCore()
Navigate(ServerPathBase);
}
+ [Fact]
+ public void HotReloadTypesAreTrimmed_WhenPublishedWithTrimming()
+ {
+ if (!_serverFixture.TestTrimmedOrMultithreadingApps)
+ {
+ // In dev mode, hot reload types are expected to be present
+ return;
+ }
+
+ var appElement = Browser.MountTestComponent();
+
+ // Hot reload manager type is present, but shallow type
+ Browser.Equal("true", () => appElement.FindElement(By.Id("hot-reload-manager-found")).Text);
+
+ // Verify that UpdateApplication method has been trimmed away
+ Browser.Equal("false", () => appElement.FindElement(By.Id("update-application-found")).Text);
+ }
+
[Fact]
public void MetricsTypesAreTrimmed_WhenPublishedWithTrimming()
{
diff --git a/src/Components/test/testassets/BasicTestApp/BasicTestApp.csproj b/src/Components/test/testassets/BasicTestApp/BasicTestApp.csproj
index cc5d77b5a3d9..35dea697a6a8 100644
--- a/src/Components/test/testassets/BasicTestApp/BasicTestApp.csproj
+++ b/src/Components/test/testassets/BasicTestApp/BasicTestApp.csproj
@@ -20,6 +20,11 @@
<_BlazorBrotliCompressionLevel>NoCompression
+
+
+ true
+
+
+ true
true
diff --git a/src/Components/test/testassets/Components.TestServer/HotReloadStartup.cs b/src/Components/test/testassets/Components.TestServer/HotReloadStartup.cs
index 51269338ae33..219c242ef3f8 100644
--- a/src/Components/test/testassets/Components.TestServer/HotReloadStartup.cs
+++ b/src/Components/test/testassets/Components.TestServer/HotReloadStartup.cs
@@ -12,7 +12,7 @@ public class HotReloadStartup
{
public HotReloadStartup()
{
- HotReloadManager.Default.MetadataUpdateSupported = true;
+ AppContext.SetSwitch("System.Reflection.Metadata.MetadataUpdater.IsSupported", true);
}
public void ConfigureServices(IServiceCollection services)