【问题标题】:MEF Composition Error Because of Assembly Names?由于程序集名称导致的 MEF 组合错误?
【发布时间】:2013-11-19 14:07:30
【问题描述】:

提前感谢您查看此问题!

我正在使用 MEF 在项目中加载一些程序集。一切都很好,直到我们更改了包含接口的文件的名称。

为了更清楚,我先总结一下事情发生的场景,然后事情发生的场景,然后在没有发生的情况下具体展示异常和导致异常的代码。

工作场景如下:

我们有一个名为 IPlugin 的接口,它在名为 Common-1-0.dll 的程序集中定义。

我们有一些针对 Common-1-0.dll 编译的插件程序集。

加载插件的应用程序是针对 Common-1-0.dll 编译的。

这是不工作的场景:

我们有一个名为 IPlugin,它在名为 Common-1-1.dll 的程序集中定义。接口从 Common-1-0.dll 没有变化。

我们有一些针对 Common-1-0.dll 编译的插件程序集。

加载插件的应用程序是针对 Common-1-1.dll 编译的。

现在的问题:

当我在第二个场景中运行下面的代码时,我得到一个 CompositionException(如下面的代码所示)。这似乎是因为插件是针对 Common-1-0.dll 编译的,而尝试进行组合的应用程序是针对 Common-1-1.dll 编译的。两个文件之间的代码没有任何变化,只是名称。

所以我们希望能够加载针对任何程序集构建的插件,只要该程序集导出正确的接口,但我不确定我是否可以使用 MEF 做到这一点。这就是我想知道这个问题的结果。

代码:

    private void LoadPlugins(string directory, string searchPattern = "", bool recursive = false)
    {
        Trace.Agent.Status("Loading plugin(s) from {0}{1}{2}", directory, Path.DirectorySeparatorChar, searchPattern);

        try
        {
            var directoryCatalog = string.IsNullOrEmpty(searchPattern)
                                           ? new DirectoryCatalog(directory)
                                           : new DirectoryCatalog(directory, searchPattern);
            _container = new CompositionContainer(new AggregateCatalog(directoryCatalog));

            _container.ComposeParts(this);
        }
        catch (CompositionException exc)
        {
            Trace.Agent.Exception(exc);
        }

        if (recursive)
        {
            foreach (string dir in Directory.GetDirectories(directory))
            {
                LoadPlugins(Path.Combine(directory, dir), recursive:true);
            }
        }
    }

组合异常:

导出 'TestPlugin.TestPlugin (ContractName="Common.IPlugin")' 不能分配给类型 'Common.IPlugin'。

【问题讨论】:

  • 您是否尝试使用程序集绑定重定向?
  • 这个我不熟悉,没试过,但我会研究一下。
  • 如果程序集的名称实际上不同,您认为程序集绑定重定向会起作用吗?用它指定一个通用名称并让它使用更新版本看起来相当容易,但是有一个例子,当你看到'common-1-0.dll'时说使用'common-1-1.dll '?
  • 它不查找 dll 的名称,它会查找 publicKeyToken。您必须签署您的程序集并使用相同的密钥编译程序集的两个版本,以便 publicKeyToken 不会更改。这样,您可以定义从版本 0.0.0.0-1.1.0.0 到 1.1.0.0 的重定向,这意味着一切都应该使用新版本。
  • 好吧抱歉,当然两个 dll 的程序集名称必须相同。因此,如果您对这些程序集(以版本为后缀)确实有不同的名称,那么您就是...

标签: c# .net plugins mef


【解决方案1】:

我想我找到了解决您的问题的方法,它有点被黑了,但无论如何。

因此,如果您以不同的方式命名程序集,例如assembly1.0 和 assembly1.1 这会导致问题,因为您不能简单地将程序集重定向到新版本。 通常您只需保持相同的程序集名称并增加版本号。这样您就可以毫无问题地重定向(只要代码支持它)。

解决方案是通过附加到当前 AppDomain 的 AssemblyResolve 事件来侵入程序集解析机制。

        AppDomain currentDomain = AppDomain.CurrentDomain;

        currentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler);

        LoadPlugins(currentDomain.BaseDirectory);

        var x = _container.GetExport<IPlugin>().Value;

在事件处理程序中,您可以简单地返回“新”程序集

    private static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args)
    {
        if (args.Name.StartsWith("PluginCore1.0"))
        {
            return typeof(IPlugin).Assembly;
        }
        return null;
    }

这工作,也没有签名的程序集(没有公钥令牌)。

要触发 resolve 事件,您仍然必须在 app.config 中定义程序集重定向:

<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
  <dependentAssembly>
    <assemblyIdentity name="PluginCore1.0"
                      culture="neutral" />

    <bindingRedirect oldVersion="1.0.0.0" newVersion="1.1.0.0" />
  </dependentAssembly>
</assemblyBinding>

再次,我强烈建议使用相同的程序集名称(不带版本后缀)并简单地使用应该可以正常工作的程序集重定向机制。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-03
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    相关资源
    最近更新 更多