简体   繁体   中英

AssemblyLoadContext cannot find in assembly based on type

I cannot seem to get a DefinedType based on a interface (IStartupPlugin), it seems to work with AssemblyLoadContext.Default.LoadFromAssemblyPath however when using my own class it doesn't :(

var raw = AssemblyLoadContext.Default.LoadFromAssemblyPath(pluginPath + Path.DirectorySeparatorChar + fqName + ".dll");
var raw2 = assemblyContext.LoadFromAssemblyPath(pluginPath + Path.DirectorySeparatorChar + fqName + ".dll");

bool hasDefined = raw.DefinedTypes
                     .Where(x => typeof(IStartupPlugin).IsAssignableFrom(x) && x != null && x != typeof(IStartupPlugin))
                     .Any();

bool hasDefined2 = raw2.DefinedTypes
                       .Where(x => typeof(IStartupPlugin).IsAssignableFrom(x) && x != null && x != typeof(IStartupPlugin))
                       .Any();
public class PluginAssemblyContext : AssemblyLoadContext
{
    private readonly AssemblyDependencyResolver _resolver;

    public PluginAssemblyContext(string mainAssemblyToLoadPath) : base(isCollectible: true)
    {
        _resolver = new AssemblyDependencyResolver(mainAssemblyToLoadPath);
        this.LoadFromAssemblyPath(mainAssemblyToLoadPath);
    }

    protected override Assembly Load(AssemblyName name)
    {
        string assemblyPath = _resolver.ResolveAssemblyToPath(name);
        if (assemblyPath != null)
        {
            return LoadFromAssemblyPath(assemblyPath);
        }

        return null;
    }
}
hasDefined = true
hasDefined2 = false

Both of them is expected to have true as value hasDefined and hasDefined2

It's usually a bad practice to run such code within a constructor. Define a static (extension) method in a static class then load the desired assembly from anywhere in your app using an instance of your custom PluginAssemblyContext class. Concretely, try this:

public class PluginAssemblyContext : AssemblyLoadContext
{
    private readonly AssemblyDependencyResolver _resolver;

    public PluginAssemblyContext(string mainAssemblyToLoadPath) : base(isCollectible: true)
    {
        _resolver = new AssemblyDependencyResolver(mainAssemblyToLoadPath);
    }


    protected override Assembly Load(AssemblyName name)
    {
        string assemblyPath = _resolver.ResolveAssemblyToPath(name);
        if (assemblyPath != null)
        {
            return LoadFromAssemblyPath(assemblyPath);
        }

        return null;
    }
}

Define this class somewhere within a namespace with proper using s...

public static class PluginAssemblyContextExtensions
{

    public static Assembly FromAssemblyPath(this AssemblyLoadContext context, string path)
    {

        return context.LoadFromAssemblyPath(path);

    }

}

...from somewhere else (preferably within a static method/constructor), call the above code when your app has finished starting. I didn't have a chance to test this but I suspect the smell of your code comes from within the PluginAssemblyContext constructor you defined. Please let me know if I'm right (or wrong).

It seems I have goofed with the creation of the assembly resolver! I used the path to the '.dll' file (mainAssemblyToLoadPath), however it seems like it asked for the path to the plugin directory (main directory), or so I guessed it seems to work fine now :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM