加载程序集时发生冲突的依赖项

Posted

技术标签:

【中文标题】加载程序集时发生冲突的依赖项【英文标题】:Conflicting dependencies when loading an assembly 【发布时间】:2014-07-25 18:39:02 【问题描述】:

我在尝试编写插件处理程序时遇到了一些问题。

我有一个主应用程序“AppA”,它引用了“AssemblyX”。

AppA 还加载了许多实现“IPlugin”接口的插件程序集。但是,这些插件也可能引用“AssemblyX”,甚至可能是旧版本。

所以最初的问题是通过 Assembly.LoadFrom() 加载插件时与 AssemblyX 发生冲突。

在这里进行了一些研究后,我尝试将插件加载到新的 AppDomain 中。这本身并没有解决问题。接下来我创建了一个继承自 MarshalByRefObject 的 ProxyDomain 类。仍然没有喜悦。

最后我让插件本身继承自 MarshalByRefObject,这确实取得了更大的成功,但是当我尝试将 List 绑定到 ListView 时,它抱怨“System.MarshalByRefObject'不包含名为'SomeProperty'的属性” .

请有人看一下我的代码,看看是否可以进行任何更改:

public partial class WebForm1 : System.Web.UI.Page

    protected void Button1_Click(object sender, EventArgs e)
    
        AssemblyX x = new AssemblyX();
        x.GetStuff("a", "b");

        lstConfig.DataSource = PluginLoader.Load(Path.Combine(PluginLoader.GetPluginFolderPath(), "ExamplePlugins.dll"));
        lstConfig.DataBind();
    


public class PluginLoader

    public static List<IPlugin> Load(string file)
    
        var plugins = new List<IPlugin>();

        ProxyDomain pd = new ProxyDomain();

        Assembly ass = pd.GetAssembly(file);

        try
        
            AppDomainSetup adSetup = new AppDomainSetup();

            string fileName = Path.GetFileName(file);

            string path = file.Replace(fileName, "");

            adSetup.ApplicationBase = path;

            AppDomain crmAppDomain = AppDomain.CreateDomain("ProxyDomain", null, adSetup);

            foreach (Type t in ass.GetTypes())
            
                Type hasInterface = t.GetInterface(typeof(IPlugin).FullName, true);

                if (hasInterface != null && !t.IsInterface)
                

                    IPlugin plugin = (IPlugin)crmAppDomain.CreateInstanceAndUnwrap(ass.FullName, t.FullName);
                    plugins.Add(plugin);
                
            
        
        catch (Exception ex)
        

        

        return plugins;
    

public class ProxyDomain : MarshalByRefObject

    public Assembly GetAssembly(string assemblyPath)
    
        try
        
            return Assembly.LoadFrom(assemblyPath);
        
        catch (Exception ex)
        
            throw ex;
        
    


public interface IPlugin

    string SomeProperty  get; set; 
    void DoSomething();


[Serializable]
public class ExamplePlugin : MarshalByRefObject, IPlugin

    public string SomeValue
    
        get
        
            AssemblyX x = new AssemblyX(); // Referencing a previouus version of AssemblyX 
            return x.GetStuff("c");
        
        set
        

        
    

    public void DoSomething()  

注意:PluginExamples.dll 可能包含多个插件类。

【问题讨论】:

你试试 System.Addins 命名空间的东西吗? MAF 可以解决许多关于版本控制的问题(如果它们不能简单地使用适当的清单文件解决)... 【参考方案1】:

如果我理解正确,您可以在 app.config 中像这样指定 AssemblyX 的特定版本:

<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="AssemblyX" publicKeyToken="3d67ed1f87d44c89" />
        <codeBase version="3.0" href=".\ver30\AssemblyX.dll"/>
        <codeBase version="5.0" href=".\ver50\AssemblyX.dll"/>
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

如果版本的公钥令牌不同,则必须指定 2 个单独的条目。

【讨论】:

嗨,我不想重定向,因为版本可能不兼容。例如,应用程序需要使用第 5 版的 AssemblyX,但插件可能只使用第 2 版的 AssemblyX。 这不是重定向,而是告诉框架如何绑定不同版本的程序集。上面的示例正是解决您遇到的问题的方法。

以上是关于加载程序集时发生冲突的依赖项的主要内容,如果未能解决你的问题,请参考以下文章

在 AppDomain 问题中加载具有依赖项的程序集

加载依赖于另一个域的程序集时的 FileNotFound [重复]

无法加载文件或程序集或其依赖项之一。访问被拒绝。问题是随机的,但发生一次后,它会继续

尝试加载反应式程序集时,Expression Blend 4 失败

COM 互操作加载程序集时 AppDomain 的路径

从具有依赖关系的另一个文件夹加载另一个应用程序域中的程序集