diff --git a/.editorconfig b/.editorconfig
index 536c212ea709..45ead881a43c 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -464,6 +464,13 @@ dotnet_diagnostic.IDE0161.severity = silent
# IDE0005: Remove unused usings. Ignore for shared src files since imports for those depend on the projects in which they are included.
dotnet_diagnostic.IDE0005.severity = silent
+[{**/microsoft.dotnet.hotreload.agent*/**.cs}]
+# IDE0005: Remove unused usings. Ignore for shared src files coming from nuget package.
+dotnet_diagnostic.IDE0005.severity = silent
+# IDE0073: A source file is missing a required header. Ignore for shared src files coming from nuget package.
+dotnet_diagnostic.IDE0073.severity = silent
+
+
# Verify settings
[*.{received,verified}.{txt,xml,json}]
charset = "utf-8-bom"
diff --git a/eng/Dependencies.props b/eng/Dependencies.props
index 94bd8109c0c7..cc03487fc95b 100644
--- a/eng/Dependencies.props
+++ b/eng/Dependencies.props
@@ -25,6 +25,8 @@ and are generated based on the last package release.
+
+
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 19c9aad572b1..86a6c11af22f 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -361,6 +361,14 @@
https://github.com/dotnet/dotnet
85778473549347b3e4bad3ea009e9438df7b11bb
+
+ https://github.com/dotnet/dotnet
+ 5e6dacd4d3debda3266224b2a434811c6fa94987
+
+
+ https://github.com/dotnet/dotnet
+ 5e6dacd4d3debda3266224b2a434811c6fa94987
+
diff --git a/eng/Versions.props b/eng/Versions.props
index 81a225c53d77..3136d18a802b 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -155,6 +155,9 @@
10.0.0-preview.4.25260.104
10.0.0-preview.4.25260.104
10.0.0-preview.4.25260.104
+
+ 10.0.100-preview.5.25258.39
+ 10.0.100-preview.5.25258.39
4.13.0-3.24613.7
diff --git a/src/Components/WebAssembly/WebAssembly/src/HotReload/AgentMessageSeverity.cs b/src/Components/WebAssembly/WebAssembly/src/HotReload/AgentMessageSeverity.cs
deleted file mode 100644
index 3ab84cecde97..000000000000
--- a/src/Components/WebAssembly/WebAssembly/src/HotReload/AgentMessageSeverity.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-namespace Microsoft.DotNet.HotReload;
-
-internal enum AgentMessageSeverity : byte
-{
- Verbose = 0,
- Warning = 1,
- Error = 2,
-}
diff --git a/src/Components/WebAssembly/WebAssembly/src/HotReload/AgentReporter.cs b/src/Components/WebAssembly/WebAssembly/src/HotReload/AgentReporter.cs
deleted file mode 100644
index 0950dac4e387..000000000000
--- a/src/Components/WebAssembly/WebAssembly/src/HotReload/AgentReporter.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Linq;
-
-namespace Microsoft.DotNet.HotReload;
-
-internal sealed class AgentReporter
-{
- private readonly List<(string message, AgentMessageSeverity severity)> _log = [];
-
- public void Report(string message, AgentMessageSeverity severity)
- {
- _log.Add((message, severity));
- }
-
- public IReadOnlyCollection<(string message, AgentMessageSeverity severity)> GetAndClearLogEntries(ResponseLoggingLevel level)
- {
- lock (_log)
- {
- var filteredLog = (level != ResponseLoggingLevel.Verbose)
- ? _log.Where(static entry => entry.severity != AgentMessageSeverity.Verbose)
- : _log;
-
- var log = filteredLog.ToArray();
- _log.Clear();
- return log;
- }
- }
-}
diff --git a/src/Components/WebAssembly/WebAssembly/src/HotReload/HotReloadAgent.cs b/src/Components/WebAssembly/WebAssembly/src/HotReload/HotReloadAgent.cs
deleted file mode 100644
index b2c50556be7b..000000000000
--- a/src/Components/WebAssembly/WebAssembly/src/HotReload/HotReloadAgent.cs
+++ /dev/null
@@ -1,203 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System.Collections.Concurrent;
-using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
-using System.Linq;
-using System.Reflection;
-using System.Reflection.Metadata;
-using System.Reflection.Metadata.Ecma335;
-
-namespace Microsoft.DotNet.HotReload;
-
-#if NET
-[System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Hot reload is only expected to work when trimming is disabled.")]
-#endif
-internal sealed class HotReloadAgent : IDisposable
-{
- private const string MetadataUpdaterTypeName = "System.Reflection.Metadata.MetadataUpdater";
- private const string ApplyUpdateMethodName = "ApplyUpdate";
- private const string GetCapabilitiesMethodName = "GetCapabilities";
-
- private delegate void ApplyUpdateDelegate(Assembly assembly, ReadOnlySpan metadataDelta, ReadOnlySpan ilDelta, ReadOnlySpan pdbDelta);
-
- private readonly ConcurrentDictionary> _deltas = new();
- private readonly ConcurrentDictionary _appliedAssemblies = new();
- private readonly ApplyUpdateDelegate _applyUpdate;
- private readonly MetadataUpdateHandlerInvoker _metadataUpdateHandlerInvoker;
-
- public AgentReporter Reporter { get; }
- public string Capabilities { get; }
-
- private HotReloadAgent(AgentReporter reporter, ApplyUpdateDelegate applyUpdate, string capabilities)
- {
- Reporter = reporter;
- _metadataUpdateHandlerInvoker = new(reporter);
- _applyUpdate = applyUpdate;
- Capabilities = capabilities;
-
- AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad;
- }
-
- public static bool TryCreate(AgentReporter reporter, [NotNullWhen(true)] out HotReloadAgent? agent)
- {
- GetUpdaterMethodsAndCapabilities(reporter, out var applyUpdate, out var capabilities);
- if (applyUpdate != null && !string.IsNullOrEmpty(capabilities))
- {
- agent = new HotReloadAgent(reporter, applyUpdate, capabilities);
- return true;
- }
-
- agent = null;
- return false;
- }
-
- public void Dispose()
- {
- AppDomain.CurrentDomain.AssemblyLoad -= OnAssemblyLoad;
- }
-
- private static void GetUpdaterMethodsAndCapabilities(AgentReporter reporter, out ApplyUpdateDelegate? applyUpdate, out string? capabilities)
- {
- applyUpdate = null;
- capabilities = null;
-
- var metadataUpdater = Type.GetType(MetadataUpdaterTypeName + ", System.Runtime.Loader", throwOnError: false);
- if (metadataUpdater == null)
- {
- reporter.Report($"Type not found: {MetadataUpdaterTypeName}", AgentMessageSeverity.Error);
- return;
- }
-
- var applyUpdateMethod = metadataUpdater.GetMethod(ApplyUpdateMethodName, BindingFlags.Public | BindingFlags.Static, binder: null, [typeof(Assembly), typeof(ReadOnlySpan), typeof(ReadOnlySpan), typeof(ReadOnlySpan)], modifiers: null);
- if (applyUpdateMethod == null)
- {
- reporter.Report($"{MetadataUpdaterTypeName}.{ApplyUpdateMethodName} not found.", AgentMessageSeverity.Error);
- return;
- }
-
- applyUpdate = (ApplyUpdateDelegate)applyUpdateMethod.CreateDelegate(typeof(ApplyUpdateDelegate));
-
- var getCapabilities = metadataUpdater.GetMethod(GetCapabilitiesMethodName, BindingFlags.NonPublic | BindingFlags.Static, binder: null, Type.EmptyTypes, modifiers: null);
- if (getCapabilities == null)
- {
- reporter.Report($"{MetadataUpdaterTypeName}.{GetCapabilitiesMethodName} not found.", AgentMessageSeverity.Error);
- return;
- }
-
- try
- {
- capabilities = getCapabilities.Invoke(obj: null, parameters: null) as string;
- }
- catch (Exception e)
- {
- reporter.Report($"Error retrieving capabilities: {e.Message}", AgentMessageSeverity.Error);
- }
- }
-
- private void OnAssemblyLoad(object? _, AssemblyLoadEventArgs eventArgs)
- {
- _metadataUpdateHandlerInvoker.Clear();
-
- var loadedAssembly = eventArgs.LoadedAssembly;
- var moduleId = TryGetModuleId(loadedAssembly);
- if (moduleId is null)
- {
- return;
- }
-
- if (_deltas.TryGetValue(moduleId.Value, out var updateDeltas) && _appliedAssemblies.TryAdd(loadedAssembly, loadedAssembly))
- {
- // A delta for this specific Module exists and we haven't called ApplyUpdate on this instance of Assembly as yet.
- ApplyDeltas(loadedAssembly, updateDeltas);
- }
- }
-
- public void ApplyDeltas(IEnumerable deltas)
- {
- foreach (var delta in deltas)
- {
- Reporter.Report($"Applying delta to module {delta.ModuleId}.", AgentMessageSeverity.Verbose);
-
- foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
- {
- if (TryGetModuleId(assembly) is Guid moduleId && moduleId == delta.ModuleId)
- {
- _applyUpdate(assembly, delta.MetadataDelta, delta.ILDelta, delta.PdbDelta);
- }
- }
-
- // Additionally stash the deltas away so it may be applied to assemblies loaded later.
- var cachedDeltas = _deltas.GetOrAdd(delta.ModuleId, static _ => new());
- cachedDeltas.Add(delta);
- }
-
- _metadataUpdateHandlerInvoker.Invoke(GetMetadataUpdateTypes(deltas));
- }
-
- private Type[] GetMetadataUpdateTypes(IEnumerable deltas)
- {
- List? types = null;
-
- foreach (var delta in deltas)
- {
- var assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(assembly => TryGetModuleId(assembly) is Guid moduleId && moduleId == delta.ModuleId);
- if (assembly is null)
- {
- continue;
- }
-
- foreach (var updatedType in delta.UpdatedTypes)
- {
- // Must be a TypeDef.
- Debug.Assert(MetadataTokens.EntityHandle(updatedType) is { Kind: HandleKind.TypeDefinition, IsNil: false });
-
- // The type has to be in the manifest module since Hot Reload does not support multi-module assemblies:
- try
- {
- var type = assembly.ManifestModule.ResolveType(updatedType);
- types ??= new();
- types.Add(type);
- }
- catch (Exception e)
- {
- Reporter.Report($"Failed to load type 0x{updatedType:X8}: {e.Message}", AgentMessageSeverity.Warning);
- }
- }
- }
-
- return types?.ToArray() ?? Type.EmptyTypes;
- }
-
- private void ApplyDeltas(Assembly assembly, IReadOnlyList deltas)
- {
- try
- {
- foreach (var item in deltas)
- {
- _applyUpdate(assembly, item.MetadataDelta, item.ILDelta, item.PdbDelta);
- }
-
- Reporter.Report("Deltas applied.", AgentMessageSeverity.Verbose);
- }
- catch (Exception ex)
- {
- Reporter.Report(ex.ToString(), AgentMessageSeverity.Warning);
- }
- }
-
- private static Guid? TryGetModuleId(Assembly loadedAssembly)
- {
- try
- {
- return loadedAssembly.Modules.FirstOrDefault()?.ModuleVersionId;
- }
- catch
- {
- // Assembly.Modules might throw. See https://github.com/dotnet/aspnetcore/issues/33152
- }
-
- return default;
- }
-}
diff --git a/src/Components/WebAssembly/WebAssembly/src/HotReload/MetadataUpdateHandlerInvoker.cs b/src/Components/WebAssembly/WebAssembly/src/HotReload/MetadataUpdateHandlerInvoker.cs
deleted file mode 100644
index fab00eb691cd..000000000000
--- a/src/Components/WebAssembly/WebAssembly/src/HotReload/MetadataUpdateHandlerInvoker.cs
+++ /dev/null
@@ -1,244 +0,0 @@
-// 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;
-
-namespace Microsoft.DotNet.HotReload;
-
-///
-/// Finds and invokes metadata update handlers.
-///
-#if NET
-[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Hot reload is only expected to work when trimming is disabled.")]
-[UnconditionalSuppressMessage("Trimming", "IL2070", Justification = "Hot reload is only expected to work when trimming is disabled.")]
-#endif
-internal sealed class MetadataUpdateHandlerInvoker(AgentReporter reporter)
-{
- internal sealed class RegisteredActions(IReadOnlyList> clearCache, IReadOnlyList> updateApplication)
- {
- public void Invoke(Type[] updatedTypes)
- {
- foreach (var action in clearCache)
- {
- action(updatedTypes);
- }
-
- foreach (var action in updateApplication)
- {
- action(updatedTypes);
- }
- }
-
- ///
- /// For testing.
- ///
- internal IEnumerable> ClearCache => clearCache;
-
- ///
- /// For testing.
- ///
- internal IEnumerable> UpdateApplication => updateApplication;
- }
-
- private const string ClearCacheHandlerName = "ClearCache";
- private const string UpdateApplicationHandlerName = "UpdateApplication";
-
- private RegisteredActions? _actions;
-
- ///
- /// Call when a new assembly is loaded.
- ///
- internal void Clear()
- => Interlocked.Exchange(ref _actions, null);
-
- ///
- /// Invokes all registerd handlers.
- ///
- internal void Invoke(Type[] updatedTypes)
- {
- try
- {
- // Defer discovering metadata updata handlers until after hot reload deltas have been applied.
- // This should give enough opportunity for AppDomain.GetAssemblies() to be sufficiently populated.
- var actions = _actions;
- if (actions == null)
- {
- Interlocked.CompareExchange(ref _actions, GetMetadataUpdateHandlerActions(), null);
- actions = _actions;
- }
-
- reporter.Report($"Invoking metadata update handlers. {updatedTypes.Length} type(s) updated.", AgentMessageSeverity.Verbose);
-
- actions.Invoke(updatedTypes);
-
- reporter.Report("Deltas applied.", AgentMessageSeverity.Verbose);
- }
- catch (Exception e)
- {
- reporter.Report(e.ToString(), AgentMessageSeverity.Warning);
- }
- }
-
- private IEnumerable GetHandlerTypes()
- {
- // We need to execute MetadataUpdateHandlers in a well-defined order. For v1, the strategy that is used is to topologically
- // sort assemblies so that handlers in a dependency are executed before the dependent (e.g. the reflection cache action
- // in System.Private.CoreLib is executed before System.Text.Json clears its own cache.)
- // This would ensure that caches and updates more lower in the application stack are up to date
- // before ones higher in the stack are recomputed.
- var sortedAssemblies = TopologicalSort(AppDomain.CurrentDomain.GetAssemblies());
-
- foreach (var assembly in sortedAssemblies)
- {
- foreach (var attr in TryGetCustomAttributesData(assembly))
- {
- // Look up the attribute by name rather than by type. This would allow netstandard targeting libraries to
- // define their own copy without having to cross-compile.
- if (attr.AttributeType.FullName != "System.Reflection.Metadata.MetadataUpdateHandlerAttribute")
- {
- continue;
- }
-
- IList ctorArgs = attr.ConstructorArguments;
- if (ctorArgs.Count != 1 ||
- ctorArgs[0].Value is not Type handlerType)
- {
- reporter.Report($"'{attr}' found with invalid arguments.", AgentMessageSeverity.Warning);
- continue;
- }
-
- yield return handlerType;
- }
- }
- }
-
- public RegisteredActions GetMetadataUpdateHandlerActions()
- => GetMetadataUpdateHandlerActions(GetHandlerTypes());
-
- ///
- /// Internal for testing.
- ///
- internal RegisteredActions GetMetadataUpdateHandlerActions(IEnumerable handlerTypes)
- {
- var clearCacheActions = new List>();
- var updateApplicationActions = new List>();
-
- foreach (var handlerType in handlerTypes)
- {
- bool methodFound = false;
-
- if (GetUpdateMethod(handlerType, ClearCacheHandlerName) is MethodInfo clearCache)
- {
- clearCacheActions.Add(CreateAction(clearCache));
- methodFound = true;
- }
-
- if (GetUpdateMethod(handlerType, UpdateApplicationHandlerName) is MethodInfo updateApplication)
- {
- updateApplicationActions.Add(CreateAction(updateApplication));
- methodFound = true;
- }
-
- if (!methodFound)
- {
- reporter.Report(
- $"Expected to find a static method '{ClearCacheHandlerName}' or '{UpdateApplicationHandlerName}' on type '{handlerType.AssemblyQualifiedName}' but neither exists.",
- AgentMessageSeverity.Warning);
- }
- }
-
- return new RegisteredActions(clearCacheActions, updateApplicationActions);
-
- Action CreateAction(MethodInfo update)
- {
- var action = (Action)update.CreateDelegate(typeof(Action));
- return types =>
- {
- try
- {
- action(types);
- }
- catch (Exception ex)
- {
- reporter.Report($"Exception from '{action}': {ex}", AgentMessageSeverity.Warning);
- }
- };
- }
-
- MethodInfo? GetUpdateMethod(Type handlerType, string name)
- {
- if (handlerType.GetMethod(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, binder: null, [typeof(Type[])], modifiers: null) is MethodInfo updateMethod &&
- updateMethod.ReturnType == typeof(void))
- {
- return updateMethod;
- }
-
- foreach (MethodInfo method in handlerType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance))
- {
- if (method.Name == name)
- {
- reporter.Report($"Type '{handlerType}' has method '{method}' that does not match the required signature.", AgentMessageSeverity.Warning);
- break;
- }
- }
-
- return null;
- }
- }
-
- private IList TryGetCustomAttributesData(Assembly assembly)
- {
- try
- {
- return assembly.GetCustomAttributesData();
- }
- catch (Exception e)
- {
- // In cross-platform scenarios, such as debugging in VS through WSL, Roslyn
- // runs on Windows, and the agent runs on Linux. Assemblies accessible to Windows
- // may not be available or loaded on linux (such as WPF's assemblies).
- // In such case, we can ignore the assemblies and continue enumerating handlers for
- // the rest of the assemblies of current domain.
- reporter.Report($"'{assembly.FullName}' is not loaded ({e.Message})", AgentMessageSeverity.Verbose);
- return [];
- }
- }
-
- ///
- /// Internal for testing.
- ///
- internal static List TopologicalSort(Assembly[] assemblies)
- {
- var sortedAssemblies = new List(assemblies.Length);
-
- var visited = new HashSet(StringComparer.Ordinal);
-
- foreach (var assembly in assemblies)
- {
- Visit(assemblies, assembly, sortedAssemblies, visited);
- }
-
- static void Visit(Assembly[] assemblies, Assembly assembly, List sortedAssemblies, HashSet visited)
- {
- var assemblyIdentifier = assembly.GetName().Name!;
- if (!visited.Add(assemblyIdentifier))
- {
- return;
- }
-
- foreach (var dependencyName in assembly.GetReferencedAssemblies())
- {
- var dependency = Array.Find(assemblies, a => a.GetName().Name == dependencyName.Name);
- if (dependency is not null)
- {
- Visit(assemblies, dependency, sortedAssemblies, visited);
- }
- }
-
- sortedAssemblies.Add(assembly);
- }
-
- return sortedAssemblies;
- }
-}
diff --git a/src/Components/WebAssembly/WebAssembly/src/HotReload/ResponseLoggingLevel.cs b/src/Components/WebAssembly/WebAssembly/src/HotReload/ResponseLoggingLevel.cs
deleted file mode 100644
index dd05c372bf2e..000000000000
--- a/src/Components/WebAssembly/WebAssembly/src/HotReload/ResponseLoggingLevel.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-namespace Microsoft.DotNet.HotReload;
-
-internal enum ResponseLoggingLevel : byte
-{
- WarningsAndErrors = 0,
- Verbose = 1,
-}
diff --git a/src/Components/WebAssembly/WebAssembly/src/HotReload/UpdateDelta.cs b/src/Components/WebAssembly/WebAssembly/src/HotReload/UpdateDelta.cs
deleted file mode 100644
index d02b1c4d46bf..000000000000
--- a/src/Components/WebAssembly/WebAssembly/src/HotReload/UpdateDelta.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-namespace Microsoft.DotNet.HotReload;
-
-internal readonly struct UpdateDelta(Guid moduleId, byte[] metadataDelta, byte[] ilDelta, byte[] pdbDelta, int[] updatedTypes)
-{
- public Guid ModuleId { get; } = moduleId;
- public byte[] MetadataDelta { get; } = metadataDelta;
- public byte[] ILDelta { get; } = ilDelta;
- public byte[] PdbDelta { get; } = pdbDelta;
- public int[] UpdatedTypes { get; } = updatedTypes;
-}
diff --git a/src/Components/WebAssembly/WebAssembly/src/HotReload/WebAssemblyHotReload.cs b/src/Components/WebAssembly/WebAssembly/src/HotReload/WebAssemblyHotReload.cs
index fc8eafc861f1..907e3042aa7f 100644
--- a/src/Components/WebAssembly/WebAssembly/src/HotReload/WebAssemblyHotReload.cs
+++ b/src/Components/WebAssembly/WebAssembly/src/HotReload/WebAssemblyHotReload.cs
@@ -69,10 +69,7 @@ internal static async Task InitializeAsync()
{
s_initialized = true;
- if (!HotReloadAgent.TryCreate(s_reporter, out var agent))
- {
- return;
- }
+ var agent = new HotReloadAgent();
var existingAgent = Interlocked.CompareExchange(ref s_hotReloadAgent, agent, null);
if (existingAgent != null)
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 f0418fd10354..90c9b18180da 100644
--- a/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj
+++ b/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj
@@ -21,6 +21,8 @@
+
+