private async Task <Assembly?> LoadAssemblyByNameAsync( AssemblyName assemblyName, AssemblyLoaderContext?context) { if (_assemblyLoadContext == null) { return(null); } IAssemblyComparer comparer = GetAssemblyNameComparer(assemblyName); if (TryGetAlreadyLoadedAssembly(assemblyName, comparer, out var alreadyLoadedAssembly)) { return(alreadyLoadedAssembly); } if (TryGetAlreadyLoadingAssembly(assemblyName, comparer, out var assemblyLoadingTask)) { Debug.WriteLine($"Waiting for Loading Assembly '{assemblyName}'"); return(await assemblyLoadingTask !.ConfigureAwait(false)); } AssemblyLoaderContext contextScope = context == null ? new AssemblyLoaderContext(assemblyName) : context.NewScope(assemblyName); Assembly?assembly = await PerformAssemblyLoad(assemblyName, comparer, contextScope).ConfigureAwait(false); return(assembly); }
public async Task <AssemblyData?> GetAssemblyDataAsync( AssemblyName assemblyName, AssemblyLoaderContext context) { if (_assemblyDataCache.TryGetValue(assemblyName, out AssemblyData? data)) { return(data); } var paths = _assemblyDataLocator.GetFindPaths(assemblyName, context); foreach (var path in paths) { data = await GetAssemblyDataAsync(path).ConfigureAwait(false); if (data != null) { _assemblyDataCache.TryAdd(assemblyName, data); return(data); } } return(null); }
private async Task <Assembly?> ResolveAssembly( AssemblyName assemblyName, IAssemblyComparer comparer, AssemblyLoaderContext context) { if (_assemblyLoadContext == null) { return(null); } // Try loading the assembly by name (this works when the assembly is part of the bootloader, but never used explicitly) Assembly?assembly = _assemblyLoadContext.Load(assemblyName); if (assembly != null) { return(assembly); } AssemblyData?data = await _assemblyDataProvider.GetAssemblyDataAsync(assemblyName, context).ConfigureAwait(false); if (data == null) { Debug.WriteLine($"Failed to resolve Assembly: '{assemblyName}'"); return(null); } var dependencies = await ResolveDependencies(assemblyName, data, context).ConfigureAwait(false); if (dependencies == null) { return(null); } return(_assemblyLoadContext.Load(data)); }
/// <inheritdoc/> public IEnumerable <AssemblyLocation> GetFindPaths( AssemblyName assemblyName, AssemblyLoaderContext context) { foreach (var module in _lazyModuleNamesProvider.ModuleNameHints) { yield return(CreateAssemblyLocation($"_content/{module}/_lazy", assemblyName)); } yield return(CreateAssemblyLocation($"_content/{assemblyName}/_lazy", assemblyName)); yield return(CreateAssemblyLocation($"_framework/_bin", assemblyName)); }
private ICollection <AssemblyName> GetAssemblyDependencies( AssemblyData assemblyData, AssemblyLoaderContext context) { if (_assemblyLoadContext == null || assemblyData.DllBytes == null) { return(Array.Empty <AssemblyName>()); } using MemoryStream dllStream = new MemoryStream(assemblyData.DllBytes); using PEReader peReader = new PEReader(dllStream); MetadataReader mdReader = peReader.GetMetadataReader(MetadataReaderOptions.None); // TODO: Throw error if the loaded assembly doesn't match the version requested return(mdReader.AssemblyReferences .Select(x => mdReader.GetAssemblyReference(x).GetAssemblyName()) .Except(_assemblyLoadContext.AllAssemblies.Select(a => a.GetName()), AssemblyByNameAndVersionComparer.Default) .ToList()); }
private async Task <Assembly?> PerformAssemblyLoad( AssemblyName assemblyName, IAssemblyComparer comparer, AssemblyLoaderContext context) { var assemblyLoadingTaskSource = new TaskCompletionSource <Assembly?>(); if (!TryActionRepeteadly(() => _loadingAssemblies.TryAdd(assemblyName, assemblyLoadingTaskSource.Task), 5)) { throw new InvalidOperationException($"Unable to Load Assembly '{assemblyName}': Concurrency error (adding)"); } Debug.WriteLine($"Loading Assembly: '{assemblyName}'"); Assembly?assembly = await ResolveAssembly(assemblyName, comparer, context).ConfigureAwait(false); if (assembly != null) { Debug.WriteLine($"Loaded Assembly: '{assemblyName}'"); foreach (var assemblyLoadCallback in _onAssemblyLoad) { await assemblyLoadCallback.Invoke(assembly).ConfigureAwait(false); } } else { Debug.WriteLine($"Assembly '{assemblyName}' failed to load"); } assemblyLoadingTaskSource.SetResult(assembly); if (!TryActionRepeteadly(() => _loadingAssemblies.TryRemove(assemblyName, out var _), 5)) { throw new InvalidOperationException($"Unable to Load Assembly '{assemblyName}': Concurrency error (removing)"); } return(assembly); }
private async Task <ICollection <Assembly>?> ResolveDependencies( AssemblyName assemblyName, AssemblyData data, AssemblyLoaderContext context) { var dependencies = GetAssemblyDependencies(data, context); var loadDependenciesTasks = dependencies .Select(async n => new { Name = n, Assembly = await LoadAssemblyByNameAsync(n, context).ConfigureAwait(false), }) .ToList(); await Task.WhenAll(loadDependenciesTasks).ConfigureAwait(false); var resolvedAssemblies = loadDependenciesTasks .Select(t => t.Result) .ToList(); var erroredAssemblies = resolvedAssemblies .Where(a => a.Assembly == null) .ToList(); foreach (var missingDependency in erroredAssemblies) { Debug.WriteLine($"Dependency load failed: '{missingDependency.Name}' required by '{assemblyName}'"); } if (erroredAssemblies.Any()) { return(null); } return(resolvedAssemblies .Select(a => a.Assembly !) .ToList()); }