Skip to content

Commit 0a5f4de

Browse files
authoredNov 19, 2024··
Hot Reload agent improvements (#58333)
* Hot Reload agent improvements Refactor agent code so that it can be shared with dotnet-watch implementation via a shared project. Add new API applyHotReloadDeltas to apply updates. * Feedback and cleanup

14 files changed

+544
-253
lines changed
 

‎src/Components/Web.JS/dist/Release/blazor.server.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎src/Components/Web.JS/dist/Release/blazor.web.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎src/Components/Web.JS/dist/Release/blazor.webassembly.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎src/Components/Web.JS/src/Boot.WebAssembly.Common.ts

+5
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,15 @@ async function startCore(components: RootComponentManager<WebAssemblyComponentDe
9797
}
9898
});
9999

100+
// obsolete:
100101
Blazor._internal.applyHotReload = (id: string, metadataDelta: string, ilDelta: string, pdbDelta: string | undefined, updatedTypes?: number[]) => {
101102
dispatcher.invokeDotNetStaticMethod('Microsoft.AspNetCore.Components.WebAssembly', 'ApplyHotReloadDelta', id, metadataDelta, ilDelta, pdbDelta, updatedTypes ?? null);
102103
};
103104

105+
Blazor._internal.applyHotReloadDeltas = (deltas: { moduleId: string, metadataDelta: string, ilDelta: string, pdbDelta: string, updatedTypes: number[] }[], loggingLevel: number) => {
106+
return dispatcher.invokeDotNetStaticMethod('Microsoft.AspNetCore.Components.WebAssembly', 'ApplyHotReloadDeltas', deltas, loggingLevel);
107+
};
108+
104109
Blazor._internal.getApplyUpdateCapabilities = () => dispatcher.invokeDotNetStaticMethod('Microsoft.AspNetCore.Components.WebAssembly', 'GetApplyUpdateCapabilities');
105110

106111
// Configure JS interop

‎src/Components/Web.JS/src/GlobalExports.ts

+4
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,11 @@ export interface IBlazor {
8989
}
9090

9191
// APIs invoked by hot reload
92+
93+
// obsolete:
9294
applyHotReload?: (id: string, metadataDelta: string, ilDelta: string, pdbDelta: string | undefined, updatedTypes?: number[]) => void;
95+
96+
applyHotReloadDeltas?: (deltas: { moduleId: string, metadataDelta: string, ilDelta: string, pdbDelta: string, updatedTypes: number[] }[], loggingLevel: number) => {message: string, severity: number}[];
9397
getApplyUpdateCapabilities?: () => string;
9498
hotReloadApplied?: () => void;
9599
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Microsoft.DotNet.HotReload;
5+
6+
internal enum AgentMessageSeverity : byte
7+
{
8+
Verbose = 0,
9+
Warning = 1,
10+
Error = 2,
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Linq;
5+
6+
namespace Microsoft.DotNet.HotReload;
7+
8+
internal sealed class AgentReporter
9+
{
10+
private readonly List<(string message, AgentMessageSeverity severity)> _log = [];
11+
12+
public void Report(string message, AgentMessageSeverity severity)
13+
{
14+
_log.Add((message, severity));
15+
}
16+
17+
public IReadOnlyCollection<(string message, AgentMessageSeverity severity)> GetAndClearLogEntries(ResponseLoggingLevel level)
18+
{
19+
lock (_log)
20+
{
21+
var filteredLog = (level != ResponseLoggingLevel.Verbose)
22+
? _log.Where(static entry => entry.severity != AgentMessageSeverity.Verbose)
23+
: _log;
24+
25+
var log = filteredLog.ToArray();
26+
_log.Clear();
27+
return log;
28+
}
29+
}
30+
}

‎src/Components/WebAssembly/WebAssembly/src/HotReload/HotReloadAgent.cs

+87-174
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Diagnostics.CodeAnalysis;
5+
using System.Reflection;
6+
7+
namespace Microsoft.DotNet.HotReload;
8+
9+
/// <summary>
10+
/// Finds and invokes metadata update handlers.
11+
/// </summary>
12+
#if NET
13+
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = "Hot reload is only expected to work when trimming is disabled.")]
14+
[UnconditionalSuppressMessage("Trimming", "IL2070", Justification = "Hot reload is only expected to work when trimming is disabled.")]
15+
#endif
16+
internal sealed class MetadataUpdateHandlerInvoker(AgentReporter reporter)
17+
{
18+
internal sealed class RegisteredActions(IReadOnlyList<Action<Type[]?>> clearCache, IReadOnlyList<Action<Type[]?>> updateApplication)
19+
{
20+
public void Invoke(Type[] updatedTypes)
21+
{
22+
foreach (var action in clearCache)
23+
{
24+
action(updatedTypes);
25+
}
26+
27+
foreach (var action in updateApplication)
28+
{
29+
action(updatedTypes);
30+
}
31+
}
32+
33+
/// <summary>
34+
/// For testing.
35+
/// </summary>
36+
internal IEnumerable<Action<Type[]?>> ClearCache => clearCache;
37+
38+
/// <summary>
39+
/// For testing.
40+
/// </summary>
41+
internal IEnumerable<Action<Type[]?>> UpdateApplication => updateApplication;
42+
}
43+
44+
private const string ClearCacheHandlerName = "ClearCache";
45+
private const string UpdateApplicationHandlerName = "UpdateApplication";
46+
47+
private RegisteredActions? _actions;
48+
49+
/// <summary>
50+
/// Call when a new assembly is loaded.
51+
/// </summary>
52+
internal void Clear()
53+
=> Interlocked.Exchange(ref _actions, null);
54+
55+
/// <summary>
56+
/// Invokes all registerd handlers.
57+
/// </summary>
58+
internal void Invoke(Type[] updatedTypes)
59+
{
60+
try
61+
{
62+
// Defer discovering metadata updata handlers until after hot reload deltas have been applied.
63+
// This should give enough opportunity for AppDomain.GetAssemblies() to be sufficiently populated.
64+
var actions = _actions;
65+
if (actions == null)
66+
{
67+
Interlocked.CompareExchange(ref _actions, GetMetadataUpdateHandlerActions(), null);
68+
actions = _actions;
69+
}
70+
71+
reporter.Report($"Invoking metadata update handlers. {updatedTypes.Length} type(s) updated.", AgentMessageSeverity.Verbose);
72+
73+
actions.Invoke(updatedTypes);
74+
75+
reporter.Report("Deltas applied.", AgentMessageSeverity.Verbose);
76+
}
77+
catch (Exception e)
78+
{
79+
reporter.Report(e.ToString(), AgentMessageSeverity.Warning);
80+
}
81+
}
82+
83+
private IEnumerable<Type> GetHandlerTypes()
84+
{
85+
// We need to execute MetadataUpdateHandlers in a well-defined order. For v1, the strategy that is used is to topologically
86+
// sort assemblies so that handlers in a dependency are executed before the dependent (e.g. the reflection cache action
87+
// in System.Private.CoreLib is executed before System.Text.Json clears its own cache.)
88+
// This would ensure that caches and updates more lower in the application stack are up to date
89+
// before ones higher in the stack are recomputed.
90+
var sortedAssemblies = TopologicalSort(AppDomain.CurrentDomain.GetAssemblies());
91+
92+
foreach (var assembly in sortedAssemblies)
93+
{
94+
foreach (var attr in TryGetCustomAttributesData(assembly))
95+
{
96+
// Look up the attribute by name rather than by type. This would allow netstandard targeting libraries to
97+
// define their own copy without having to cross-compile.
98+
if (attr.AttributeType.FullName != "System.Reflection.Metadata.MetadataUpdateHandlerAttribute")
99+
{
100+
continue;
101+
}
102+
103+
IList<CustomAttributeTypedArgument> ctorArgs = attr.ConstructorArguments;
104+
if (ctorArgs.Count != 1 ||
105+
ctorArgs[0].Value is not Type handlerType)
106+
{
107+
reporter.Report($"'{attr}' found with invalid arguments.", AgentMessageSeverity.Warning);
108+
continue;
109+
}
110+
111+
yield return handlerType;
112+
}
113+
}
114+
}
115+
116+
public RegisteredActions GetMetadataUpdateHandlerActions()
117+
=> GetMetadataUpdateHandlerActions(GetHandlerTypes());
118+
119+
/// <summary>
120+
/// Internal for testing.
121+
/// </summary>
122+
internal RegisteredActions GetMetadataUpdateHandlerActions(IEnumerable<Type> handlerTypes)
123+
{
124+
var clearCacheActions = new List<Action<Type[]?>>();
125+
var updateApplicationActions = new List<Action<Type[]?>>();
126+
127+
foreach (var handlerType in handlerTypes)
128+
{
129+
bool methodFound = false;
130+
131+
if (GetUpdateMethod(handlerType, ClearCacheHandlerName) is MethodInfo clearCache)
132+
{
133+
clearCacheActions.Add(CreateAction(clearCache));
134+
methodFound = true;
135+
}
136+
137+
if (GetUpdateMethod(handlerType, UpdateApplicationHandlerName) is MethodInfo updateApplication)
138+
{
139+
updateApplicationActions.Add(CreateAction(updateApplication));
140+
methodFound = true;
141+
}
142+
143+
if (!methodFound)
144+
{
145+
reporter.Report(
146+
$"Expected to find a static method '{ClearCacheHandlerName}' or '{UpdateApplicationHandlerName}' on type '{handlerType.AssemblyQualifiedName}' but neither exists.",
147+
AgentMessageSeverity.Warning);
148+
}
149+
}
150+
151+
return new RegisteredActions(clearCacheActions, updateApplicationActions);
152+
153+
Action<Type[]?> CreateAction(MethodInfo update)
154+
{
155+
var action = (Action<Type[]?>)update.CreateDelegate(typeof(Action<Type[]?>));
156+
return types =>
157+
{
158+
try
159+
{
160+
action(types);
161+
}
162+
catch (Exception ex)
163+
{
164+
reporter.Report($"Exception from '{action}': {ex}", AgentMessageSeverity.Warning);
165+
}
166+
};
167+
}
168+
169+
MethodInfo? GetUpdateMethod(Type handlerType, string name)
170+
{
171+
if (handlerType.GetMethod(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, binder: null, [typeof(Type[])], modifiers: null) is MethodInfo updateMethod &&
172+
updateMethod.ReturnType == typeof(void))
173+
{
174+
return updateMethod;
175+
}
176+
177+
foreach (MethodInfo method in handlerType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance))
178+
{
179+
if (method.Name == name)
180+
{
181+
reporter.Report($"Type '{handlerType}' has method '{method}' that does not match the required signature.", AgentMessageSeverity.Warning);
182+
break;
183+
}
184+
}
185+
186+
return null;
187+
}
188+
}
189+
190+
private IList<CustomAttributeData> TryGetCustomAttributesData(Assembly assembly)
191+
{
192+
try
193+
{
194+
return assembly.GetCustomAttributesData();
195+
}
196+
catch (Exception e)
197+
{
198+
// In cross-platform scenarios, such as debugging in VS through WSL, Roslyn
199+
// runs on Windows, and the agent runs on Linux. Assemblies accessible to Windows
200+
// may not be available or loaded on linux (such as WPF's assemblies).
201+
// In such case, we can ignore the assemblies and continue enumerating handlers for
202+
// the rest of the assemblies of current domain.
203+
reporter.Report($"'{assembly.FullName}' is not loaded ({e.Message})", AgentMessageSeverity.Verbose);
204+
return [];
205+
}
206+
}
207+
208+
/// <summary>
209+
/// Internal for testing.
210+
/// </summary>
211+
internal static List<Assembly> TopologicalSort(Assembly[] assemblies)
212+
{
213+
var sortedAssemblies = new List<Assembly>(assemblies.Length);
214+
215+
var visited = new HashSet<string>(StringComparer.Ordinal);
216+
217+
foreach (var assembly in assemblies)
218+
{
219+
Visit(assemblies, assembly, sortedAssemblies, visited);
220+
}
221+
222+
static void Visit(Assembly[] assemblies, Assembly assembly, List<Assembly> sortedAssemblies, HashSet<string> visited)
223+
{
224+
var assemblyIdentifier = assembly.GetName().Name!;
225+
if (!visited.Add(assemblyIdentifier))
226+
{
227+
return;
228+
}
229+
230+
foreach (var dependencyName in assembly.GetReferencedAssemblies())
231+
{
232+
var dependency = Array.Find(assemblies, a => a.GetName().Name == dependencyName.Name);
233+
if (dependency is not null)
234+
{
235+
Visit(assemblies, dependency, sortedAssemblies, visited);
236+
}
237+
}
238+
239+
sortedAssemblies.Add(assembly);
240+
}
241+
242+
return sortedAssemblies;
243+
}
244+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace Microsoft.DotNet.HotReload;
5+
6+
internal enum ResponseLoggingLevel : byte
7+
{
8+
WarningsAndErrors = 0,
9+
Verbose = 1,
10+
}
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
namespace Microsoft.Extensions.HotReload;
4+
namespace Microsoft.DotNet.HotReload;
55

6-
internal sealed class UpdateDelta
6+
internal readonly struct UpdateDelta(Guid moduleId, byte[] metadataDelta, byte[] ilDelta, byte[] pdbDelta, int[] updatedTypes)
77
{
8-
public Guid ModuleId { get; set; }
9-
10-
public byte[] MetadataDelta { get; set; } = default!;
11-
12-
public byte[] ILDelta { get; set; } = default!;
13-
14-
public byte[]? PdbBytes { get; set; }
15-
16-
public int[]? UpdatedTypes { get; set; }
8+
public Guid ModuleId { get; } = moduleId;
9+
public byte[] MetadataDelta { get; } = metadataDelta;
10+
public byte[] ILDelta { get; } = ilDelta;
11+
public byte[] PdbDelta { get; } = pdbDelta;
12+
public int[] UpdatedTypes { get; } = updatedTypes;
1713
}

‎src/Components/WebAssembly/WebAssembly/src/HotReload/WebAssemblyHotReload.cs

+124-36
Original file line numberDiff line numberDiff line change
@@ -2,79 +2,167 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.ComponentModel;
5-
using System.Diagnostics;
5+
using System.Diagnostics.CodeAnalysis;
66
using System.Globalization;
7-
using System.Reflection;
8-
using System.Runtime.InteropServices.JavaScript;
9-
using Microsoft.Extensions.HotReload;
7+
using System.Linq;
8+
using System.Net.Http;
9+
using System.Text.Json;
10+
using Microsoft.AspNetCore.Components.WebAssembly.Services;
11+
using Microsoft.DotNet.HotReload;
1012
using Microsoft.JSInterop;
1113

14+
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
15+
1216
namespace Microsoft.AspNetCore.Components.WebAssembly.HotReload;
1317

1418
/// <summary>
1519
/// Contains methods called by interop. Intended for framework use only, not supported for use in application
1620
/// code.
1721
/// </summary>
1822
[EditorBrowsable(EditorBrowsableState.Never)]
23+
[UnconditionalSuppressMessage(
24+
"Trimming",
25+
"IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code",
26+
Justification = "Hot Reload does not support trimming")]
1927
public static partial class WebAssemblyHotReload
2028
{
21-
private const string BlazorHotReloadModuleName = "blazor-hotreload";
29+
/// <summary>
30+
/// For framework use only.
31+
/// </summary>
32+
public readonly struct LogEntry
33+
{
34+
public string Message { get; init; }
35+
public int Severity { get; init; }
36+
}
37+
38+
/// <summary>
39+
/// For framework use only.
40+
/// </summary>
41+
internal sealed class Update
42+
{
43+
public int Id { get; set; }
44+
public Delta[] Deltas { get; set; } = default!;
45+
}
2246

23-
private static HotReloadAgent? _hotReloadAgent;
24-
private static readonly UpdateDelta[] _updateDeltas = new[]
47+
/// <summary>
48+
/// For framework use only.
49+
/// </summary>
50+
public readonly struct Delta
2551
{
26-
new UpdateDelta(),
27-
};
52+
public string ModuleId { get; init; }
53+
public byte[] MetadataDelta { get; init; }
54+
public byte[] ILDelta { get; init; }
55+
public byte[] PdbDelta { get; init; }
56+
public int[] UpdatedTypes { get; init; }
57+
}
58+
59+
private static readonly AgentReporter s_reporter = new();
60+
private static readonly JsonSerializerOptions s_jsonSerializerOptions = new(JsonSerializerDefaults.Web);
61+
62+
private static bool s_initialized;
63+
private static HotReloadAgent? s_hotReloadAgent;
2864

2965
internal static async Task InitializeAsync()
3066
{
3167
if (Environment.GetEnvironmentVariable("__ASPNETCORE_BROWSER_TOOLS") == "true" &&
3268
OperatingSystem.IsBrowser())
3369
{
34-
// Attempt to read previously applied hot reload deltas if the ASP.NET Core browser tools are available (indicated by the presence of the Environment variable).
35-
// The agent is injected in to the hosted app and can serve this script that can provide results from local-storage.
36-
// See https://github.com/dotnet/aspnetcore/issues/37357#issuecomment-941237000
37-
await JSHost.ImportAsync(BlazorHotReloadModuleName, "/_framework/blazor-hotreload.js");
38-
await ReceiveHotReloadAsync();
70+
s_initialized = true;
71+
72+
if (!HotReloadAgent.TryCreate(s_reporter, out var agent))
73+
{
74+
return;
75+
}
76+
77+
var existingAgent = Interlocked.CompareExchange(ref s_hotReloadAgent, agent, null);
78+
if (existingAgent != null)
79+
{
80+
throw new InvalidOperationException("Hot Reload agent already initialized");
81+
}
82+
83+
await ApplyPreviousDeltasAsync(agent);
84+
}
85+
}
86+
87+
private static async ValueTask ApplyPreviousDeltasAsync(HotReloadAgent agent)
88+
{
89+
string errorMessage;
90+
91+
using var client = new HttpClient()
92+
{
93+
BaseAddress = new Uri(WebAssemblyNavigationManager.Instance.BaseUri, UriKind.Absolute)
94+
};
95+
96+
try
97+
{
98+
var response = await client.GetAsync("/_framework/blazor-hotreload");
99+
if (response.IsSuccessStatusCode)
100+
{
101+
var deltasJson = await response.Content.ReadAsStringAsync();
102+
var updates = deltasJson != "" ? JsonSerializer.Deserialize<Update[]>(deltasJson, s_jsonSerializerOptions) : null;
103+
if (updates == null)
104+
{
105+
s_reporter.Report($"No previous updates to apply.", AgentMessageSeverity.Verbose);
106+
return;
107+
}
108+
109+
var i = 1;
110+
foreach (var update in updates)
111+
{
112+
s_reporter.Report($"Reapplying update {i}/{updates.Length}.", AgentMessageSeverity.Verbose);
113+
114+
agent.ApplyDeltas(
115+
update.Deltas.Select(d => new UpdateDelta(Guid.Parse(d.ModuleId, CultureInfo.InvariantCulture), d.MetadataDelta, d.ILDelta, d.PdbDelta, d.UpdatedTypes)));
116+
117+
i++;
118+
}
119+
120+
return;
121+
}
122+
123+
errorMessage = $"HTTP GET '/_framework/blazor-hotreload' returned {response.StatusCode}";
124+
}
125+
catch (Exception e)
126+
{
127+
errorMessage = e.ToString();
39128
}
129+
130+
s_reporter.Report($"Failed to retrieve and apply previous deltas from the server: ${errorMessage}", AgentMessageSeverity.Error);
40131
}
41132

133+
private static HotReloadAgent? GetAgent()
134+
=> s_hotReloadAgent ?? (s_initialized ? throw new InvalidOperationException("Hot Reload agent not initialized") : null);
135+
42136
/// <summary>
43137
/// For framework use only.
44138
/// </summary>
139+
[Obsolete("Use ApplyHotReloadDeltas instead")]
45140
[JSInvokable(nameof(ApplyHotReloadDelta))]
46141
public static void ApplyHotReloadDelta(string moduleIdString, byte[] metadataDelta, byte[] ilDelta, byte[] pdbBytes, int[]? updatedTypes)
47142
{
48-
// Analyzer has a bug where it doesn't handle ConditionalAttribute: https://github.com/dotnet/roslyn/issues/63464
49-
#pragma warning disable IDE0200 // Remove unnecessary lambda expression
50-
Interlocked.CompareExchange(ref _hotReloadAgent, new HotReloadAgent(m => Debug.WriteLine(m)), null);
51-
#pragma warning restore IDE0200 // Remove unnecessary lambda expression
143+
GetAgent()?.ApplyDeltas(
144+
[new UpdateDelta(Guid.Parse(moduleIdString, CultureInfo.InvariantCulture), metadataDelta, ilDelta, pdbBytes, updatedTypes ?? [])]);
145+
}
52146

53-
var moduleId = Guid.Parse(moduleIdString, CultureInfo.InvariantCulture);
147+
/// <summary>
148+
/// For framework use only.
149+
/// </summary>
150+
[JSInvokable(nameof(ApplyHotReloadDeltas))]
151+
public static LogEntry[] ApplyHotReloadDeltas(Delta[] deltas, int loggingLevel)
152+
{
153+
var agent = GetAgent();
54154

55-
_updateDeltas[0].ModuleId = moduleId;
56-
_updateDeltas[0].MetadataDelta = metadataDelta;
57-
_updateDeltas[0].ILDelta = ilDelta;
58-
_updateDeltas[0].PdbBytes = pdbBytes;
59-
_updateDeltas[0].UpdatedTypes = updatedTypes;
155+
agent?.ApplyDeltas(
156+
deltas.Select(d => new UpdateDelta(Guid.Parse(d.ModuleId, CultureInfo.InvariantCulture), d.MetadataDelta, d.ILDelta, d.PdbDelta, d.UpdatedTypes)));
60157

61-
_hotReloadAgent.ApplyDeltas(_updateDeltas);
158+
return s_reporter.GetAndClearLogEntries((ResponseLoggingLevel)loggingLevel)
159+
.Select(log => new LogEntry() { Message = log.message, Severity = (int)log.severity }).ToArray();
62160
}
63161

64162
/// <summary>
65163
/// For framework use only.
66164
/// </summary>
67165
[JSInvokable(nameof(GetApplyUpdateCapabilities))]
68166
public static string GetApplyUpdateCapabilities()
69-
{
70-
var method = typeof(System.Reflection.Metadata.MetadataUpdater).GetMethod("GetCapabilities", BindingFlags.NonPublic | BindingFlags.Static, Type.EmptyTypes);
71-
if (method is null)
72-
{
73-
return string.Empty;
74-
}
75-
return (string)method.Invoke(obj: null, parameters: null)!;
76-
}
77-
78-
[JSImport("receiveHotReloadAsync", BlazorHotReloadModuleName)]
79-
private static partial Task ReceiveHotReloadAsync();
167+
=> GetAgent()?.Capabilities ?? "";
80168
}

‎src/Components/WebAssembly/WebAssembly/src/PublicAPI.Shipped.txt

+19
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,24 @@ Microsoft.AspNetCore.Components.WebAssembly.Hosting.WebAssemblyHostConfiguration
8181
Microsoft.AspNetCore.Components.WebAssembly.Hosting.WebAssemblyHostConfiguration.WebAssemblyHostConfiguration() -> void
8282
Microsoft.AspNetCore.Components.WebAssembly.Hosting.WebAssemblyHostEnvironmentExtensions
8383
Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload
84+
Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.Delta
85+
Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.Delta.Delta() -> void
86+
Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.Delta.ILDelta.get -> byte[]!
87+
Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.Delta.ILDelta.init -> void
88+
Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.Delta.MetadataDelta.get -> byte[]!
89+
Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.Delta.MetadataDelta.init -> void
90+
Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.Delta.ModuleId.get -> string!
91+
Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.Delta.ModuleId.init -> void
92+
Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.Delta.PdbDelta.get -> byte[]!
93+
Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.Delta.PdbDelta.init -> void
94+
Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.Delta.UpdatedTypes.get -> int[]!
95+
Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.Delta.UpdatedTypes.init -> void
96+
Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.LogEntry
97+
Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.LogEntry.LogEntry() -> void
98+
Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.LogEntry.Message.get -> string!
99+
Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.LogEntry.Message.init -> void
100+
Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.LogEntry.Severity.get -> int
101+
Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.LogEntry.Severity.init -> void
84102
Microsoft.AspNetCore.Components.WebAssembly.Http.BrowserRequestCache
85103
Microsoft.AspNetCore.Components.WebAssembly.Http.BrowserRequestCache.Default = 0 -> Microsoft.AspNetCore.Components.WebAssembly.Http.BrowserRequestCache
86104
Microsoft.AspNetCore.Components.WebAssembly.Http.BrowserRequestCache.ForceCache = 4 -> Microsoft.AspNetCore.Components.WebAssembly.Http.BrowserRequestCache
@@ -108,6 +126,7 @@ static Microsoft.AspNetCore.Components.WebAssembly.Hosting.WebAssemblyHostEnviro
108126
static Microsoft.AspNetCore.Components.WebAssembly.Hosting.WebAssemblyHostEnvironmentExtensions.IsProduction(this Microsoft.AspNetCore.Components.WebAssembly.Hosting.IWebAssemblyHostEnvironment! hostingEnvironment) -> bool
109127
static Microsoft.AspNetCore.Components.WebAssembly.Hosting.WebAssemblyHostEnvironmentExtensions.IsStaging(this Microsoft.AspNetCore.Components.WebAssembly.Hosting.IWebAssemblyHostEnvironment! hostingEnvironment) -> bool
110128
static Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.ApplyHotReloadDelta(string! moduleIdString, byte[]! metadataDelta, byte[]! ilDelta, byte[]! pdbBytes, int[]? updatedTypes) -> void
129+
static Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.ApplyHotReloadDeltas(Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.Delta[]! deltas, int loggingLevel) -> Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.LogEntry[]!
111130
static Microsoft.AspNetCore.Components.WebAssembly.HotReload.WebAssemblyHotReload.GetApplyUpdateCapabilities() -> string!
112131
static Microsoft.AspNetCore.Components.WebAssembly.Http.WebAssemblyHttpRequestMessageExtensions.SetBrowserRequestCache(this System.Net.Http.HttpRequestMessage! requestMessage, Microsoft.AspNetCore.Components.WebAssembly.Http.BrowserRequestCache requestCache) -> System.Net.Http.HttpRequestMessage!
113132
static Microsoft.AspNetCore.Components.WebAssembly.Http.WebAssemblyHttpRequestMessageExtensions.SetBrowserRequestCredentials(this System.Net.Http.HttpRequestMessage! requestMessage, Microsoft.AspNetCore.Components.WebAssembly.Http.BrowserRequestCredentials requestCredentials) -> System.Net.Http.HttpRequestMessage!

‎src/Components/WebAssembly/WebAssembly/test/WebAssemblyHotReloadTest.cs

-29
This file was deleted.

0 commit comments

Comments
 (0)
Please sign in to comment.