'Loading Dlls of a specific interface type on program startup

I am trying to create a modular environment to host Web APIs. I can break out various endpoints to separate projects, add them as a dependency to a "master" API project and call the endpoints successfully. Now I would like to change the program to not have to make each module a dependency in the project but rather have the "master" app look for files with a certain interface and load those dynamically at startup.

private static IEnumerable<IModule> DiscoverModules()
    {
  var type = typeof(IModule);
  var types = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll")
               .Select(x => Assembly.Load(AssemblyName.GetAssemblyName(x)))
               .SelectMany(x => x.GetTypes().Where(x=>x.IsClass && 
               x.IsAssignableTo(typeof(IModule))));
  return  types.Select(Activator.CreateInstance).Cast<IModule>();
}

I've gotten this to find the DLLs but it fails at the point of "Assembly.Load" claiming that it cannot find the file specified even though the file resides in the BaseDirectory.

Can dynamically loading libraries be accomplished without adding them as a dependency in the application?

The goal is to be able to load new endpoints without recompiling the "master" application. Is there a better way to accomplish this?



Solution 1:[1]

try this for .Net6

public void LoadModule(IConfiguration configuration, IServiceCollection services)
{
    AssemblyLoadContext? loadContext = null;

    try
    {
        string tempLoadContextName = Guid.NewGuid().ToString();

        loadContext = new AssemblyLoadContext(tempLoadContextName, true);

        foreach (var dllFile in Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory, "*.External.dll"))
        {
            Assembly assembly = loadContext.LoadFromAssemblyPath(dllFile);

            var modules = assembly.DefinedTypes.Where(x => x.IsClass && x.IsAssignableTo(typeof(IServiceDependencyConfig)));

            foreach (var module in modules)
            {
                var loadedModule = (IServiceDependencyConfig)Activator.CreateInstance(module)!;

                loadedModule.AddServiceDependencyConfig(services, configuration);
            }
        }
    }
    finally
    {
        loadContext?.Unload();
    }
}

where IServiceDependencyConfig is

public interface IServiceDependencyConfig
{
    IServiceCollection AddServiceDependencyConfig(IServiceCollection services, IConfiguration configuration);
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1