Reputation: 49
(Using .NET 8.0)
This is an update to the problem I posted here. I attempted to fix the issue with a custom AssemblyLoadContext like so:
public class PluginLoadContext : AssemblyLoadContext
{
private readonly AssemblyDependencyResolver _resolver;
public PluginLoadContext(string pluginPath) : base(true)
{
_resolver = new AssemblyDependencyResolver(pluginPath);
}
protected override Assembly? Load(AssemblyName assemblyName)
{
var assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
if (assemblyPath != null) return LoadFromAssemblyPath(assemblyPath);
return null;
}
protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
{
var libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
if (libraryPath != null) return LoadUnmanagedDllFromPath(libraryPath);
return IntPtr.Zero;
}
}
Which loads assemblies from the plugin directory with this extension method:
public static ContainerConfiguration WithAssembliesInPath(this ContainerConfiguration configuration, string path,
AttributedModelProvider conventions, SearchOption searchOption = SearchOption.TopDirectoryOnly)
{
ArgumentNullException.ThrowIfNull(configuration);
ArgumentNullException.ThrowIfNull(path);
foreach (var dir in Directory.GetDirectories(path))
{
var assemblies = Directory
.GetFiles(dir, "*.dll", searchOption)
.Select(
assemblyFilePath =>
{
AssemblyName? assemblyName = null;
try
{
assemblyName = AssemblyName.GetAssemblyName(assemblyFilePath);
}
catch (BadImageFormatException)
{
// Ignored, means the assembly is native.
}
return assemblyName is null
? null
: new PluginLoadContext(assemblyFilePath).LoadFromAssemblyPath(assemblyFilePath);
})
.Where(assembly => assembly != null);
configuration = configuration.WithAssemblies(assemblies, conventions);
}
return configuration;
}
Here is the plugin code:
//...
[ImportMany]
public IEnumerable<Lazy<IMyContract, MyContractMetadata>> AvailableContracts{ get; set; }
//...
public void Import()
{
var configuration = new ContainerConfiguration()
.WithAssembliesInPath(_settings.Value.PluginDirectory, SearchOption.AllDirectories);
try
{
using var host = configuration.CreateContainer();
host.SatisfyImports(this);
}
catch (Exception ex)
{
// Log this
}
}
However, when using the custom assembly load context the parts are not imported. But, when I try to load the parts in the default load context like so:
public static ContainerConfiguration WithAssembliesInPath(this ContainerConfiguration configuration, string path,
AttributedModelProvider conventions, SearchOption searchOption = SearchOption.TopDirectoryOnly)
{
ArgumentNullException.ThrowIfNull(configuration);
ArgumentNullException.ThrowIfNull(path);
foreach (var dir in Directory.GetDirectories(path))
{
var assemblies = Directory
.GetFiles(dir, "*.dll", searchOption)
.Select(
assemblyFilePath =>
{
AssemblyName? assemblyName = null;
try
{
assemblyName = AssemblyName.GetAssemblyName(assemblyFilePath);
}
catch (BadImageFormatException)
{
// Ignored, means the assembly is native.
}
return assemblyName is null
? null
: AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyFilePath); // This is the change
})
.Where(assembly => assembly != null);
configuration = configuration.WithAssemblies(assemblies, conventions);
}
return configuration;
}
It will successfully load the parts. The problem with using the default load context is it doesn't load the dependencies for the parts properly. What I am doing wrong with the custom load context?
Upvotes: 1
Views: 32