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);
        }