private static AssemblyLoadContext CreateLoadContext(string assemblyPath, Core.ILogger logger = null)
        {
            var validatedPath = ValidateFilePath(assemblyPath, logger);

            if (validatedPath == null)
            {
                return(null);
            }

            var mainAssemblyName = Path.GetFileNameWithoutExtension(validatedPath);
            var builder          = new AssemblyLoadContextBuilder();

            // Set base directory.
            var baseDir = Path.GetDirectoryName(validatedPath);

            builder.SetBaseDirectory(baseDir);
            logger?.LogTrace($"Base directory: '{baseDir}'");

            // Add deps file as a source for finding dependencies.
            var depsJsonFile = Path.Combine(baseDir, $"{mainAssemblyName}.deps.json");

            if (File.Exists(depsJsonFile))
            {
                builder.AddDependencyContext(depsJsonFile);
                logger?.LogTrace($"Added '{depsJsonFile}' as a deps file dependency");
            }

            // Add runtimeconfig file as a source for finding dependencies.
            var pluginRuntimeConfigFile = Path.Combine(baseDir, $"{mainAssemblyName}.runtimeconfig.json");

            builder.TryAddAdditionalProbingPathFromRuntimeConfig(pluginRuntimeConfigFile, includeDevConfig: true, out _);

            return(builder.Build());
        }
        private static IReadOnlyList <Assembly> LoadAssemblyFromName(
            AssemblyLoadContext loadContext,
            AssemblyName assemblyName,
            IEnumerable <string> dependencyDirectories,
            Core.ILogger logger = null)
        {
            // If assembly exists in any of the dependency paths then load it from there.
            var dependencyPath = dependencyDirectories.
                                 Select(d =>
            {
                try
                {
                    return
                    (Directory.EnumerateFiles(d, $"{assemblyName.Name}.dll", SearchOption.AllDirectories).
                     FirstOrDefault());
                }
                catch (Exception)
                {
                    return(null);
                }
            }).
                                 Where(p => p != null).
                                 FirstOrDefault();

            if (!string.IsNullOrEmpty(dependencyPath))
            {
                return(LoadAssemblyFromPath(loadContext, dependencyPath, dependencyDirectories, logger));
            }

            // Otherwise load by name from the context.
            var output = new List <Assembly>();

            try
            {
                output.Add(loadContext.LoadFromAssemblyName(assemblyName));
                logger?.LogTrace($"Loaded assembly: '{output[0].FullName}'");
            }
            catch (Exception e)
            {
                if (logger != null)
                {
                    logger?.LogWarning($"Failed to load assembly: {e.Message.ToDistinctLines()}");
                }
                return(Array.Empty <Assembly>());
            }

            // Load referenced assemblies.
            foreach (var referencedAssemblyName in output[0].GetReferencedAssemblies())
            {
                if (!IsAssemblyLoaded(referencedAssemblyName))
                {
                    output.AddRange(
                        LoadAssemblyFromName(loadContext, referencedAssemblyName, dependencyDirectories, logger));
                }
            }

            return(output);
        }
        private static IReadOnlyList <Assembly> LoadAssemblyFromPath(
            AssemblyLoadContext loadContext,
            string path,
            IEnumerable <string> dependencyDirectories,
            Core.ILogger logger = null)
        {
            // Validate path.
            var validatedPath = ValidateFilePath(path, logger);

            if (validatedPath == null)
            {
                return(Array.Empty <Assembly>());
            }

            // Load assembly.
            var output = new List <Assembly>();

            try
            {
                output.Add(loadContext.LoadFromAssemblyPath(validatedPath));
                logger?.LogTrace($"Loaded assembly: '{output[0].FullName}'");
            }
            catch (Exception e)
            {
                if (logger != null)
                {
                    logger?.LogWarning($"Failed to load assembly: {e.Message.ToDistinctLines()}");
                }
                return(Array.Empty <Assembly>());
            }

            // Load referenced assemblies.
            foreach (var referencedAssemblyName in output[0].GetReferencedAssemblies())
            {
                if (!IsAssemblyLoaded(referencedAssemblyName))
                {
                    output.AddRange(
                        LoadAssemblyFromName(loadContext, referencedAssemblyName, dependencyDirectories, logger));
                }
            }

            return(output);
        }