/// <summary> /// Search all fallback paths for a suitable .dll ignoring all exceptions. /// Returns the full path to the dll if a suitable assembly was found. /// </summary> private string?ResolveFromFallbackPaths(AssemblyName name) { bool MatchByName(string file) => Path.GetFileNameWithoutExtension(file) .Equals(name.Name, StringComparison.InvariantCultureIgnoreCase); var found = new List <string>(); foreach (var dir in this.fallbackPaths) { try { found.AddRange(Directory.GetFiles(dir, "*.dll", SearchOption.AllDirectories).Where(MatchByName)); } catch { continue; } } if (found.Count <= 1 || name.Version == null) { return(found.FirstOrDefault()); } var tempContext = new LoadContext(this.PathToParentAssembly); var versions = new List <(string, Version?)>(); foreach (var file in found) { try { var asm = tempContext.LoadFromAssemblyPath(file); var asmVersion = asm.GetName()?.Version; versions.Add((file, asmVersion)); if (name.Version.Equals(asmVersion)) { if (tempContext.IsCollectible) { tempContext.Unload(); } return(file); } } catch { continue; } } if (tempContext.IsCollectible) { tempContext.Unload(); } var matchesMajor = versions.Where(asm => name.Version.Major == asm.Item2?.Major); var matchesMinor = matchesMajor.Where(asm => name.Version.Minor == asm.Item2?.Minor); var matchesMajRev = matchesMinor.Where(asm => name.Version.MajorRevision == asm.Item2?.MajorRevision); return(matchesMajRev.Concat(matchesMinor).Concat(matchesMajor).Select(asm => asm.Item1).FirstOrDefault()); }
/// <summary> /// Loads an assembly at the given location into a new context. /// Adds the specified fallback locations, if any, /// to the list of paths where the context will try to look for assemblies that could otherwise not be loaded. /// Throws a FileNotFoundException if no file with the given path exists. /// </summary> public static Assembly LoadAssembly(string path, string[] fallbackPaths = null) { if (!File.Exists(path)) { throw new FileNotFoundException("Failed to create contex for \"path\". No such file exists."); } var context = new LoadContext(path); if (fallbackPaths != null) { context.AddToPath(fallbackPaths); } LoadContext.Loaded.Add(context); var assemblyName = new AssemblyName(Path.GetFileNameWithoutExtension(path)); return(context.LoadFromAssemblyName(assemblyName)); }