/// <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());
        }
Beispiel #2
0
        /// <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));
        }