从网络共享文件夹加载MEF插件

11

我非常苦恼,尝试着找出为什么会出现这个问题,希望有人能够帮助我。

我的程序使用MEF来加载插件。我希望系统的客户端和服务器部分都能够使用位于服务器上的相同的插件存储。

我的问题是,当我将插件位置设置为“C:\Users\Administrator\Desktop\ClientPlugins”时,插件可以正常加载。如果我将位置更改为“\\XRP-SERVER\Users\Administrator\Desktop\ClientPlugins”,则插件无法加载。

当我在Windows资源管理器中输入“\\XRP-SERVER\Users\Administrator\Desktop\ClientPlugins”时,可以找到该位置,并且插件DLL文件也在那里。

请问是否有人可以帮助解决这个问题。

如果需要更多信息,请告诉我。

根据建议,我尝试编辑配置文件以包含以下内容,但这并没有解决问题……

  <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <runtime>
        <loadFromRemoteSources enabled="true"/>
      </runtime>

此致敬礼

Ash

4个回答

8
安全策略通常会禁用加载远程代码(即,外部位置上的程序集)。
您可以尝试以下配置更改:
<runtime>
    <loadFromRemoteSources enabled="true"/>
</runtime>

另一个需要注意的是,当你从网络位置复制文件时,它们通常会在其备用数据流中指定一个区域。在资源管理器中,可以通过在查看文件属性时使用“取消锁定”命令来删除它。或者,您可以按照Mike Hadlow博客中的说明编程地从备用数据流中删除区域。

当我看到这个时,我的眼睛亮了起来,因为我认为它会起作用。但似乎并没有:(我已经将其放置在配置文件中,但在使用 '\XRP-SERVER\Users\Administrator\Desktop\ClientPlugins' 路径时仍无法加载。还有其他想法吗? - user589195

4

昨天我遇到了这个问题,将问题缩小到了MEF如何加载程序集。 当你创建DirectoryCatalog时,它会依次创建一组AssemblyCatalogs。 每个AssemblyCatalog执行以下操作:

    AssemblyName assemblyName = AssemblyName.GetAssembly();
    Assembly.Load(assemblyName);

调用 Assembly.Load 会抛出沙箱异常(由于我目前无法解释的原因),因此没有发现任何部分,因为它悄悄地捕获了这个错误。

有趣的是,调用 Assembly.LoadFrom(<pathToYourDll>) 来返回一个 Assembly 是可以正常工作的(不会抛出异常)。将其与 AssemblyCatalog 的重载构造函数相结合,该构造函数以 Assembly 作为输入,你就可以得到一个解决方法!

因此,我不使用 DirectoryCatalog,而是列出路径中的所有 DLL,并迭代地创建 AssemblyCatalog 并将其添加到我的 CompositionContainer 中。

注意:我在 App.Config 中使用了 loadFromRemoteSources="true" 标志,这是必需的,否则它总是会崩溃。

希望这有所帮助。


我正在尝试这个过程,一直跟随你的步骤,直到你将AssemblyCatalog添加到CompositionContainer时。我在CompositionContainer上找不到add方法。能否请您更详细地解释一下这一点? - user589195
没问题,我已经弄清楚了,你需要创建一个聚合目录,然后将你的程序集目录添加到其中,最后将你的聚合目录添加到组合容器中。 - user589195
请告诉我如果你找到了为什么这个方法有效而标准方法无效的原因 :) 我敢说微软也会对此感兴趣 :) 再次感谢你的答案 :) - user589195
我查看了Reflector,但找不到原因。我猜这可能与Load和LoadFrom之间上下文的差异有关(请参见此处)。自从我上次回答以来,我还发现LoadFrom可能存在危险,我在这里遇到了这个问题:使用LoadFrom可以加载两次相同的DLL,并导致奇怪的行为。如果你要使用LoadFrom,你必须要严格执行。:) - sebd

3

只是澄清一下,sebd的答案是有效的。

这是我使用的最终代码。

string[] files = Directory.GetFiles(ClientPluginStore, "*.dll", SearchOption.TopDirectoryOnly);

AggregateCatalog aggCat = new AggregateCatalog();

aggCat.Catalogs.Add(catalog);

foreach ( string file in files )
{
    Assembly ass = Assembly.LoadFrom(file);

    AssemblyCatalog assCat = new AssemblyCatalog(ass);

    aggCat.Catalogs.Add(assCat);
}

_container = new CompositionContainer(aggCat);

0

尝试使用 System.IO.Path.PathSeparator 代替 \?

或者先将文件获取到客户端位置?

我不太确定,但我会尝试一下。


谢谢,我会尝试路径分隔符。未来的任务是通过WCF从服务器流式传输插件,如果客户端无法访问共享位置。我想先让共享位置正常工作,并且想要理解为什么它不能正常工作 :) - user589195
另外一件事是,当我考虑它时:使用“file://”? - Anton
我已经确认我以C#可以读取的格式提供了路径。 int fCount = Directory.GetFiles("\\XRP-SERVER\Users\Administrator\Desktop\ClientPlugins", ".", SearchOption.TopDirectoryOnly).Length;Console.WriteLine(fCount);这将返回1,即插件dll。 - user589195
1
那么,反斜杠就是答案了吗? - Anton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接