Add support for debugging lazy-loaded assemblies (#25943)
* Add support for debugging lazy-loaded assemblies * Address feedback from peer review * Increase wait for output on tests
This commit is contained in:
parent
f66a1daeda
commit
93f73c7764
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -354,19 +354,42 @@ function createEmscriptenModuleInstance(resourceLoader: WebAssemblyResourceLoade
|
|||
throw new Error(`${notMarked.join()} must be marked with 'BlazorWebAssemblyLazyLoad' item group in your project file to allow lazy-loading.`);
|
||||
}
|
||||
|
||||
let pdbPromises: Promise<(ArrayBuffer | null)[]> | undefined;
|
||||
if (hasDebuggingEnabled()) {
|
||||
const pdbs = resourceLoader.bootConfig.resources.pdb;
|
||||
const pdbsToLoad = assembliesMarkedAsLazy.map(a => changeExtension(a, '.pdb'))
|
||||
if (pdbs) {
|
||||
pdbPromises = Promise.all(pdbsToLoad
|
||||
.map(pdb => lazyAssemblies.hasOwnProperty(pdb) ? resourceLoader.loadResource(pdb, `_framework/${pdb}`, lazyAssemblies[pdb], 'pdb') : null)
|
||||
.map(async resource => resource ? (await resource.response).arrayBuffer() : null));
|
||||
}
|
||||
}
|
||||
|
||||
const resourcePromises = Promise.all(assembliesMarkedAsLazy
|
||||
.map(assembly => resourceLoader.loadResource(assembly, `_framework/${assembly}`, lazyAssemblies[assembly], 'assembly'))
|
||||
.map(async resource => (await resource.response).arrayBuffer()));
|
||||
|
||||
return BINDING.js_to_mono_obj(
|
||||
resourcePromises.then(resourcesToLoad => {
|
||||
Promise.all([resourcePromises, pdbPromises]).then(values => {
|
||||
const resourcesToLoad = values[0];
|
||||
const pdbsToLoad = values[1];
|
||||
if (resourcesToLoad.length) {
|
||||
window['Blazor']._internal.readLazyAssemblies = () => {
|
||||
const array = BINDING.mono_obj_array_new(resourcesToLoad.length);
|
||||
for (var i = 0; i < resourcesToLoad.length; i++) {
|
||||
BINDING.mono_obj_array_set(array, i, BINDING.js_typed_array_to_array(new Uint8Array(resourcesToLoad[i])));
|
||||
const assemblyBytes = BINDING.mono_obj_array_new(resourcesToLoad.length);
|
||||
for (let i = 0; i < resourcesToLoad.length; i++) {
|
||||
const assembly = resourcesToLoad[i] as ArrayBuffer;
|
||||
BINDING.mono_obj_array_set(assemblyBytes, i, BINDING.js_typed_array_to_array(new Uint8Array(assembly)));
|
||||
}
|
||||
return array;
|
||||
return assemblyBytes;
|
||||
};
|
||||
|
||||
window['Blazor']._internal.readLazyPdbs = () => {
|
||||
const pdbBytes = BINDING.mono_obj_array_new(resourcesToLoad.length);
|
||||
for (let i = 0; i < resourcesToLoad.length; i++) {
|
||||
const pdb = pdbsToLoad && pdbsToLoad[i] ? new Uint8Array(pdbsToLoad[i] as ArrayBufferLike) : new Uint8Array();
|
||||
BINDING.mono_obj_array_set(pdbBytes, i, BINDING.js_typed_array_to_array(pdb));
|
||||
}
|
||||
return pdbBytes;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -123,7 +123,12 @@ namespace Microsoft.NET.Sdk.BlazorWebAssembly
|
|||
else if (string.Equals(extension, ".pdb", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
resourceData.pdb ??= new ResourceHashesByNameDictionary();
|
||||
resourceList = resourceData.pdb;
|
||||
if (IsLazyLoadedAssembly($"{fileName}.dll"))
|
||||
{
|
||||
resourceList = resourceData.lazyAssembly;
|
||||
} else {
|
||||
resourceList = resourceData.pdb;
|
||||
}
|
||||
}
|
||||
else if (string.Equals(extension, ".dll", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ namespace Microsoft.AspNetCore.Builder
|
|||
var processStartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = muxerPath,
|
||||
Arguments = $"exec \"{executablePath}\" --owner-pid {ownerPid} --DevToolsUrl {devToolsHost}",
|
||||
Arguments = $"exec \"{executablePath}\" --OwnerPid {ownerPid} --DevToolsUrl {devToolsHost}",
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -21,8 +21,9 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Services
|
|||
/// </summary>
|
||||
public sealed class LazyAssemblyLoader
|
||||
{
|
||||
internal const string GetDynamicAssemblies = "window.Blazor._internal.getLazyAssemblies";
|
||||
internal const string ReadDynamicAssemblies = "window.Blazor._internal.readLazyAssemblies";
|
||||
internal const string GetLazyAssemblies = "window.Blazor._internal.getLazyAssemblies";
|
||||
internal const string ReadLazyAssemblies = "window.Blazor._internal.readLazyAssemblies";
|
||||
internal const string ReadLazyPDBs = "window.Blazor._internal.readLazyPdbs";
|
||||
|
||||
private readonly IJSRuntime _jsRuntime;
|
||||
private readonly HashSet<string> _loadedAssemblyCache;
|
||||
|
|
@ -81,7 +82,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Services
|
|||
var loadedAssemblies = new List<Assembly>();
|
||||
|
||||
var count = (int)await ((IJSUnmarshalledRuntime)_jsRuntime).InvokeUnmarshalled<string[], object, object, Task<object>>(
|
||||
GetDynamicAssemblies,
|
||||
GetLazyAssemblies,
|
||||
newAssembliesToLoad.ToArray(),
|
||||
null,
|
||||
null);
|
||||
|
|
@ -91,19 +92,29 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Services
|
|||
return loadedAssemblies;
|
||||
}
|
||||
|
||||
var assemblies = ((IJSUnmarshalledRuntime)_jsRuntime).InvokeUnmarshalled<object, object, object, object[]>(
|
||||
ReadDynamicAssemblies,
|
||||
var assemblies = ((IJSUnmarshalledRuntime)_jsRuntime).InvokeUnmarshalled<object, object, object, byte[][]>(
|
||||
ReadLazyAssemblies,
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
|
||||
foreach (byte[] assembly in assemblies)
|
||||
var pdbs = ((IJSUnmarshalledRuntime)_jsRuntime).InvokeUnmarshalled<object, object, object, byte[][]>(
|
||||
ReadLazyPDBs,
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
|
||||
for (int i = 0; i < assemblies.Length; i++)
|
||||
{
|
||||
// The runtime loads assemblies into an isolated context by default. As a result,
|
||||
// assemblies that are loaded via Assembly.Load aren't available in the app's context
|
||||
// AKA the default context. To work around this, we explicitly load the assemblies
|
||||
// into the default app context.
|
||||
var loadedAssembly = AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(assembly));
|
||||
var assembly = assemblies[i];
|
||||
var pdb = pdbs[i];
|
||||
var loadedAssembly = pdb.Length == 0 ?
|
||||
AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(assembly)) :
|
||||
AssemblyLoadContext.Default.LoadFromStream(new MemoryStream(assembly), new MemoryStream(pdb));
|
||||
loadedAssemblies.Add(loadedAssembly);
|
||||
_loadedAssemblyCache.Add(loadedAssembly.GetName().Name + ".dll");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,15 +90,16 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
|||
SetUrlViaPushState("/");
|
||||
var app = Browser.MountTestComponent<TestRouterWithLazyAssembly>();
|
||||
|
||||
// Ensure that we haven't requested the lazy loaded assembly
|
||||
// Ensure that we haven't requested the lazy loaded assembly or its PDB
|
||||
Assert.False(HasLoadedAssembly("LazyTestContentPackage.dll"));
|
||||
Assert.False(HasLoadedAssembly("LazyTestContentPackage.pdb"));
|
||||
|
||||
// Navigate to the designated route
|
||||
SetUrlViaPushState("/WithLazyLoadedRoutes");
|
||||
|
||||
// Wait for the page to finish loading
|
||||
new WebDriverWait(Browser, TimeSpan.FromSeconds(2)).Until(
|
||||
driver => driver.FindElement(By.Id("lazy-load-msg")) != null);
|
||||
driver => driver.FindElement(By.Id("lazy-load-msg")) != null);
|
||||
|
||||
// Now the assembly has been loaded
|
||||
Assert.True(HasLoadedAssembly("LazyTestContentPackage.dll"));
|
||||
|
|
|
|||
Loading…
Reference in New Issue