AppDomain.Load() fails with FileNotFoundException

前端 未结 2 1343
难免孤独
难免孤独 2021-02-03 13:01

I\'m trying to load my plugin dll into separate AppDomain, but Load() method fails with FileNotFoundException. Moreover, it seems like setting PrivateBinPath property of AppDoma

相关标签:
2条回答
  • 2021-02-03 13:37

    Thanks a lot to DedPicto and James Thurley ; I was able to implement a complete solution, I posted in this post.

    I had the same problem as Emil Badh : if you try to return from "Loader" class an interface that represents a concrete class that is unknown in current AppDomain, you get a "Serialization Exception".

    It is because the concrete type tries to be deserialized. The solution: I was able to return from "Loader" class a concrete type of a "custom proxy" and it works. See referenced post for details :

    // Our CUSTOM PROXY: the concrete type which will be known from main App
    [Serializable]
    public class ServerBaseProxy : MarshalByRefObject, IServerBase
    {
        private IServerBase _hostedServer;
    
        /// <summary>
        /// cstor with no parameters for deserialization
        /// </summary>
        public ServerBaseProxy ()
        {
    
        }
    
        /// <summary>
        /// Internal constructor to use when you write "new ServerBaseProxy"
        /// </summary>
        /// <param name="name"></param>
        public ServerBaseProxy(IServerBase hostedServer)
        {
            _hostedServer = hostedServer;
        }      
    
        public string Execute(Query q)
        {
            return(_hostedServer.Execute(q));
        }
    
    }
    

    This proxy could be returned and use as if it was the real concrete type !

    0 讨论(0)
  • 2021-02-03 14:01

    when you load an assembly into the AppDomain in that way, it is the current AppDomain's PrivateBinPath that is used to find the assembly.

    For your example, when I added the following to my App.config it ran fine:

    <runtime>
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
        <probing privatePath="[PATH_TO_PLUGIN]"/>
      </assemblyBinding>
    </runtime>
    

    This is not very useful to you though.

    What I did instead was to create a new assembly that contained the IPostPlugin and IPluginsHost interfaces, and also a class called Loader that looked like this:

    public class Loader : MarshalByRefObject
    {
        public IPostPlugin[] LoadPlugins(string assemblyName)
        {
            var assemb = Assembly.Load(assemblyName);
    
            var types = from type in assemb.GetTypes()
                    where typeof(IPostPlugin).IsAssignableFrom(type)
                    select type;
    
            var instances = types.Select(
                v => (IPostPlugin)Activator.CreateInstance(v)).ToArray();
    
            return instances;
        }
    }
    

    I keep that new assembly in the application root, and it doesn't need to exist in the plugin directories (it can but won't be used as the application root will be searched first).

    Then in the main AppDomain I did this instead:

    sandbox.Load(typeof(Loader).Assembly.FullName);
    
    Loader loader = (Loader)Activator.CreateInstance(
        sandbox,
        typeof(Loader).Assembly.FullName,
        typeof(Loader).FullName,
        false,
        BindingFlags.Public | BindingFlags.Instance,
        null,
        null,
        null,
        null).Unwrap();
    
    var plugins = loader.LoadPlugins(AssemblyName.GetAssemblyName(f.FullName).FullName);
    
    foreach (var p in plugins)
    {
        p.Init(this);
    }
    
    _PostPlugins.AddRange(plugins);
    

    So I create an instance of the known Loader type, and then get that to create the plugin instances from within the plug-in AppDomain. That way the PrivateBinPaths are used as you want them to be.

    One other thing, the private bin paths can be relative so rather than adding d.FullName you could add pluginsDir + Path.DirectorySeparatorChar + d.Name to keep the final path list short. That's just my personal preference though! Hope this helps.

    0 讨论(0)
提交回复
热议问题