private Assembly LoadAssemblyWithReferences(string assemblyPath, ManagedAssemblyLoadContext loadContext) { var depsFilePath = Path.ChangeExtension(assemblyPath, ".deps.json"); if (!File.Exists(depsFilePath)) { throw new ModuleInitializeException($"Cannot find \".deps.json\" file for \"{assemblyPath}\"."); } var mainAssemblyName = Path.GetFileNameWithoutExtension(assemblyPath); Assembly mainAssembly = null; // Load all assembly referencies which we could get through .deps.json file foreach (var dependency in depsFilePath.ExtractDependenciesFromPath()) { try { var loadedAssembly = LoadAssemblyCached(dependency, loadContext) ?? throw GenerateAssemblyLoadException(dependency.Name.Name, assemblyPath); if (mainAssemblyName.EqualsInvariant(loadedAssembly.GetName().Name)) { mainAssembly = loadedAssembly; } } catch (Exception ex) when(!(ex is ModuleInitializeException)) { throw GenerateAssemblyLoadException(dependency.Name.Name, assemblyPath, ex); } } return(mainAssembly); }
/// <summary> /// Loads assembly to AssemblyLoadContext.Default or gets it from own assembly cache. /// <para> /// Note that only one version of assembly would be loaded and cached by AssemblyName.Name, for all other versions returns cached assembly. /// </para> /// </summary> /// <param name="managedLibrary">ManagedLibrary object containing library name and paths.</param> /// <param name="loadContext">ManagedAssemblyLoadContext object.</param> /// <returns>Retures loaded assembly (could be cached).</returns> private Assembly LoadAssemblyCached(ManagedLibrary managedLibrary, ManagedAssemblyLoadContext loadContext) { var assemblyName = managedLibrary.Name; if (_loadedAssemblies.ContainsKey(assemblyName.Name)) { return(_loadedAssemblies[assemblyName.Name]); } var loadedAssembly = LoadAssemblyInternal(managedLibrary, loadContext); if (loadedAssembly != null) { _loadedAssemblies.Add(assemblyName.Name, loadedAssembly); } return(loadedAssembly); }
/// <summary> /// Performs loading into AssemblyLoadContext.Default using LoadFromAssemblyName for TPA assemblies and LoadFromAssemblyPath for other dependecies. /// <para> /// Based on https://github.com/natemcmaster/DotNetCorePlugins/blob/8f5c28fa70f0869a1af2e2904536268f184e71de/src/Plugins/Loader/ManagedLoadContext.cs Load method, /// but avoided FileNotFoundException from LoadFromAssemblyName trying only load TPA assemblies that way. /// </para> /// </summary> /// <param name="managedLibrary">ManagedLibrary object containing assembly name and paths.</param> /// <param name="loadContext">ManagedAssemblyLoadContext object.</param> /// <returns>Returns loaded assembly.</returns> private Assembly LoadAssemblyInternal(ManagedLibrary managedLibrary, ManagedAssemblyLoadContext loadContext) { // To avoid FileNotFoundException for assemblies that are included in TPA - we load them using AssemblyLoadContext.Default.LoadFromAssemblyName. var assemblyFileName = Path.GetFileName(managedLibrary.AppLocalPath); if (TPA.ContainsAssembly(assemblyFileName)) { var defaultAssembly = AssemblyLoadContext.Default.LoadFromAssemblyName(managedLibrary.Name); if (defaultAssembly != null) { return(defaultAssembly); } } if (SearchForLibrary(managedLibrary, loadContext, out var path)) { return(AssemblyLoadContext.Default.LoadFromAssemblyPath(path)); } return(null); }
private bool SearchForLibrary(ManagedLibrary library, ManagedAssemblyLoadContext loadContext, out string path) { // 1. Check for in _basePath + app local path var localFile = Path.Combine(loadContext.BasePath, library.AppLocalPath); if (File.Exists(localFile)) { path = localFile; return(true); } // 2. Search additional probing paths foreach (var searchPath in loadContext.AdditionalProdingPath) { var candidate = Path.Combine(searchPath, library.AdditionalProbingPath); if (File.Exists(candidate)) { path = candidate; return(true); } } // 3. Search in base path foreach (var ext in PlatformInformation.ManagedAssemblyExtensions) { var local = Path.Combine(loadContext.BasePath, library.Name.Name + ext); if (File.Exists(local)) { path = local; return(true); } } path = null; return(false); }