diff --git a/src/Components/Components/src/Microsoft.AspNetCore.Components.csproj b/src/Components/Components/src/Microsoft.AspNetCore.Components.csproj
index 490ee213ed6b..9a75de9cca0d 100644
--- a/src/Components/Components/src/Microsoft.AspNetCore.Components.csproj
+++ b/src/Components/Components/src/Microsoft.AspNetCore.Components.csproj
@@ -12,7 +12,7 @@
-
+
diff --git a/src/Components/Components/src/Properties/ILLink.Substitutions.xml b/src/Components/Components/src/Properties/ILLink.Substitutions.xml
index 724381711cb7..90abb328b06f 100644
--- a/src/Components/Components/src/Properties/ILLink.Substitutions.xml
+++ b/src/Components/Components/src/Properties/ILLink.Substitutions.xml
@@ -1,17 +1,11 @@
-
-
-
-
-
-
-
-
-
-
+
+
+
+
diff --git a/src/Components/Components/src/RenderHandle.cs b/src/Components/Components/src/RenderHandle.cs
index 3b6cf7de5290..d7789e18cec8 100644
--- a/src/Components/Components/src/RenderHandle.cs
+++ b/src/Components/Components/src/RenderHandle.cs
@@ -3,6 +3,7 @@
using System;
using System.Diagnostics.CodeAnalysis;
+using Microsoft.AspNetCore.Components.HotReload;
using Microsoft.AspNetCore.Components.RenderTree;
namespace Microsoft.AspNetCore.Components
@@ -46,7 +47,7 @@ public Dispatcher Dispatcher
///
/// Gets a value that determines if the is triggering a render in response to a hot-reload change.
///
- public bool IsHotReloading => _renderer?.IsHotReloading ?? false;
+ public bool IsHotReloading => HotReloadFeature.IsSupported && (_renderer?.IsHotReloading ?? false);
///
/// Notifies the renderer that the component should be rendered.
diff --git a/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs b/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs
index 5669fdad80fb..6ba718884410 100644
--- a/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs
+++ b/src/Components/Components/src/RenderTree/RenderTreeDiffBuilder.cs
@@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
+using Microsoft.AspNetCore.Components.HotReload;
using Microsoft.AspNetCore.Components.Rendering;
namespace Microsoft.AspNetCore.Components.RenderTree
@@ -541,7 +542,7 @@ private static void UpdateRetainedChildComponent(
var oldParameters = new ParameterView(ParameterViewLifetime.Unbound, oldTree, oldComponentIndex);
var newParametersLifetime = new ParameterViewLifetime(diffContext.BatchBuilder);
var newParameters = new ParameterView(newParametersLifetime, newTree, newComponentIndex);
- if (!newParameters.DefinitelyEquals(oldParameters) || diffContext.Renderer.IsHotReloading)
+ if (!newParameters.DefinitelyEquals(oldParameters) || (HotReloadFeature.IsSupported && diffContext.Renderer.IsHotReloading))
{
componentState.SetDirectParameters(newParameters);
}
diff --git a/src/Components/Components/src/RenderTree/Renderer.cs b/src/Components/Components/src/RenderTree/Renderer.cs
index 06e1724b7b5c..b059b1998f20 100644
--- a/src/Components/Components/src/RenderTree/Renderer.cs
+++ b/src/Components/Components/src/RenderTree/Renderer.cs
@@ -7,7 +7,6 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
-using System.Runtime.ExceptionServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.HotReload;
@@ -35,10 +34,9 @@ public abstract partial class Renderer : IDisposable, IAsyncDisposable
private readonly Dictionary _eventHandlerIdReplacements = new Dictionary();
private readonly ILogger _logger;
private readonly ComponentFactory _componentFactory;
- private HotReloadEnvironment? _hotReloadEnvironment;
private List<(ComponentState, ParameterView)>? _rootComponents;
- private int _nextComponentId = 0; // TODO: change to 'long' when Mono .NET->JS interop supports it
+ private int _nextComponentId = 0;
private bool _isBatchInProgress;
private ulong _lastEventHandlerId;
private List? _pendingTasks;
@@ -98,16 +96,7 @@ public Renderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory,
_logger = loggerFactory.CreateLogger();
_componentFactory = new ComponentFactory(componentActivator);
- InitializeHotReload(serviceProvider);
- }
-
- private void InitializeHotReload(IServiceProvider serviceProvider)
- {
- // HotReloadEnvironment is a test-specific feature and may not be available in a running app. We'll fallback to the default instance
- // if the test fixture does not provide one.
- _hotReloadEnvironment = serviceProvider.GetService() ?? HotReloadEnvironment.Instance;
-
- if (_hotReloadEnvironment.IsHotReloadEnabled)
+ if (HotReloadFeature.IsSupported)
{
HotReloadManager.OnDeltaApplied += RenderRootComponentsOnHotReload;
}
@@ -232,7 +221,13 @@ protected async Task RenderRootComponentAsync(int componentId, ParameterView ini
// During the asynchronous rendering process we want to wait up until all components have
// finished rendering so that we can produce the complete output.
var componentState = GetRequiredComponentState(componentId);
- CaptureRootComponentForHotReload(initialParameters, componentState);
+ if (HotReloadFeature.IsSupported)
+ {
+ // 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.
+ _rootComponents ??= new();
+ _rootComponents.Add((componentState, initialParameters.Clone()));
+ }
componentState.SetDirectParameters(initialParameters);
@@ -247,20 +242,6 @@ protected async Task RenderRootComponentAsync(int componentId, ParameterView ini
}
}
- ///
- /// Intentionally authored as a separate method call so we can trim this code.
- ///
- private void CaptureRootComponentForHotReload(ParameterView initialParameters, ComponentState componentState)
- {
- if (_hotReloadEnvironment?.IsHotReloadEnabled ?? false)
- {
- // 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.
- _rootComponents ??= new();
- _rootComponents.Add((componentState, initialParameters.Clone()));
- }
- }
-
///
/// Allows derived types to handle exceptions during rendering. Defaults to rethrowing the original exception.
///
@@ -1011,7 +992,10 @@ public void Dispose()
///
public async ValueTask DisposeAsync()
{
- DisposeForHotReload();
+ if (HotReloadFeature.IsSupported)
+ {
+ HotReloadManager.OnDeltaApplied -= RenderRootComponentsOnHotReload;
+ }
if (_disposed)
{
@@ -1035,16 +1019,5 @@ public async ValueTask DisposeAsync()
}
}
}
-
- ///
- /// Intentionally authored as a separate method call so we can trim this code.
- ///
- private void DisposeForHotReload()
- {
- if (_hotReloadEnvironment?.IsHotReloadEnabled ?? false)
- {
- HotReloadManager.OnDeltaApplied -= RenderRootComponentsOnHotReload;
- }
- }
}
}
diff --git a/src/Components/Shared/src/HotReloadEnvironment.cs b/src/Components/Shared/src/HotReloadEnvironment.cs
deleted file mode 100644
index fef2cd9255cd..000000000000
--- a/src/Components/Shared/src/HotReloadEnvironment.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-
-namespace Microsoft.AspNetCore.Components.HotReload
-{
- internal class HotReloadEnvironment
- {
- public static readonly HotReloadEnvironment Instance = new(Environment.GetEnvironmentVariable("DOTNET_MODIFIABLE_ASSEMBLIES") == "debug");
-
- public HotReloadEnvironment(bool isHotReloadEnabled)
- {
- IsHotReloadEnabled = isHotReloadEnabled;
- }
-
- ///
- /// Gets a value that determines if HotReload is configured for this application.
- ///
- public bool IsHotReloadEnabled { get; }
- }
-}
diff --git a/src/Components/Shared/src/HotReloadFeature.cs b/src/Components/Shared/src/HotReloadFeature.cs
new file mode 100644
index 000000000000..7a5ef6baa6b2
--- /dev/null
+++ b/src/Components/Shared/src/HotReloadFeature.cs
@@ -0,0 +1,15 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+
+namespace Microsoft.AspNetCore.Components.HotReload
+{
+ internal static class HotReloadFeature
+ {
+ ///
+ /// Gets a value that determines if hot reload is supported. Currently, the Debugger.IsSupported feature switch is used as a proxy for this.
+ ///
+ public static bool IsSupported { get; } = AppContext.TryGetSwitch("System.Diagnostics.Debugger.IsSupported", out var isSupported) ? isSupported : true;
+ }
+}
diff --git a/src/Components/WebAssembly/WebAssembly/src/Hosting/WebAssemblyHost.cs b/src/Components/WebAssembly/WebAssembly/src/Hosting/WebAssemblyHost.cs
index a2c7f8c0777c..70bfa2456cfd 100644
--- a/src/Components/WebAssembly/WebAssembly/src/Hosting/WebAssemblyHost.cs
+++ b/src/Components/WebAssembly/WebAssembly/src/Hosting/WebAssemblyHost.cs
@@ -4,6 +4,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.AspNetCore.Components.HotReload;
using Microsoft.AspNetCore.Components.Lifetime;
using Microsoft.AspNetCore.Components.WebAssembly.HotReload;
using Microsoft.AspNetCore.Components.WebAssembly.Infrastructure;
@@ -144,11 +145,9 @@ internal async Task RunAsyncCore(CancellationToken cancellationToken, WebAssembl
await manager.RestoreStateAsync(store);
- var initializeTask = InitializeHotReloadAsync();
- if (initializeTask is not null)
+ if (HotReloadFeature.IsSupported)
{
- // The returned value will be "null" in a trimmed app
- await initializeTask;
+ await WebAssemblyHotReload.InitializeAsync();
}
var tcs = new TaskCompletionSource();
@@ -184,11 +183,5 @@ internal async Task RunAsyncCore(CancellationToken cancellationToken, WebAssembl
await tcs.Task;
}
}
-
- private Task? InitializeHotReloadAsync()
- {
- // In Development scenarios, wait for hot reload to apply deltas before initiating rendering.
- return WebAssemblyHotReload.InitializeAsync();
- }
}
}
diff --git a/src/Components/WebAssembly/WebAssembly/src/HotReload/WebAssemblyHotReload.cs b/src/Components/WebAssembly/WebAssembly/src/HotReload/WebAssemblyHotReload.cs
index ba672d4c8d3d..c79182917fbc 100644
--- a/src/Components/WebAssembly/WebAssembly/src/HotReload/WebAssemblyHotReload.cs
+++ b/src/Components/WebAssembly/WebAssembly/src/HotReload/WebAssemblyHotReload.cs
@@ -5,7 +5,6 @@
using System.ComponentModel;
using System.Diagnostics;
using System.Threading.Tasks;
-using Microsoft.AspNetCore.Components.HotReload;
using Microsoft.AspNetCore.Components.WebAssembly.Services;
using Microsoft.Extensions.HotReload;
using Microsoft.JSInterop;
@@ -27,7 +26,10 @@ public static class WebAssemblyHotReload
internal static async Task InitializeAsync()
{
- if (!HotReloadEnvironment.Instance.IsHotReloadEnabled)
+ // Determine if we're running under a hot reload environment (e.g. dotnet-watch).
+ // It's insufficient to know it the app can be hot reloaded (HotReloadEnvironment.IsEnabled),
+ // since the hot-reload agent might be unavilable.
+ if (Environment.GetEnvironmentVariable("DOTNET_MODIFIABLE_ASSEMBLIES") != "debug")
{
return;
}
@@ -45,7 +47,6 @@ internal static async Task InitializeAsync()
public static void ApplyHotReloadDelta(string moduleIdString, byte[] metadataDelta, byte[] ilDeta)
{
var moduleId = Guid.Parse(moduleIdString);
- Debug.Assert(HotReloadEnvironment.Instance.IsHotReloadEnabled);
_updateDeltas[0].ModuleId = moduleId;
_updateDeltas[0].MetadataDelta = metadataDelta;
diff --git a/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj b/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj
index 46238a9a4c0d..f80c2e225fa5 100644
--- a/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj
+++ b/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj
@@ -1,4 +1,4 @@
-
+
$(DefaultNetCoreTargetFramework)
@@ -32,7 +32,7 @@
-
+
diff --git a/src/Components/WebAssembly/WebAssembly/src/Properties/ILLink.Substitutions.xml b/src/Components/WebAssembly/WebAssembly/src/Properties/ILLink.Substitutions.xml
index 95ac01acc9ac..2b8260e080d5 100644
--- a/src/Components/WebAssembly/WebAssembly/src/Properties/ILLink.Substitutions.xml
+++ b/src/Components/WebAssembly/WebAssembly/src/Properties/ILLink.Substitutions.xml
@@ -1,8 +1,7 @@
-
-
-
+
+
diff --git a/src/Components/test/testassets/TestServer/HotReloadStartup.cs b/src/Components/test/testassets/TestServer/HotReloadStartup.cs
index f9b0061c9d41..aeb99355c4f1 100644
--- a/src/Components/test/testassets/TestServer/HotReloadStartup.cs
+++ b/src/Components/test/testassets/TestServer/HotReloadStartup.cs
@@ -3,7 +3,6 @@
using System.Globalization;
using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Components.HotReload;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
@@ -14,7 +13,6 @@ public class HotReloadStartup
{
public void ConfigureServices(IServiceCollection services)
{
- services.AddSingleton(new HotReloadEnvironment(isHotReloadEnabled: true));
services.AddControllers();
services.AddRazorPages();
services.AddServerSideBlazor();