2

我目前正在编写一个带有插件系统的应用程序套件,该系统使用 MEF 框架在运行时加载插件。

我目前已经设置了我的顶级 WPF 应用程序之一,以将其引用的 DLL 嵌入为嵌入式资源,并使用此处描述的方法在运行时加载它们。

这工作正常,我得到运行良好的单文件 WPF 应用程序。

但是,我的另一个顶级控制台应用程序使用 MEF 框架在运行时加载插件(WPF 应用程序是固定的并明确包含插件)。我的插件本身对各种库有几个依赖项,控制台应用程序从中加载插件的扩展文件夹中到处都是各种库 dll。

我想将每个插件的依赖项嵌入其中,以便我的扩展目录仅包含顶级 DLL 文件。我上面使用的方法不适合这种方法,因为插件组件找不到所需的依赖项,因为它只是正在搜索这些嵌入式资源的执行程序集。

我当前的 OnResolveAssembly 方法如下所示:

public static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
{
    Assembly executingAssembly = Assembly.GetExecutingAssembly();
    var assemblyName = new AssemblyName(args.Name);

    string path = assemblyName.Name + ".dll";
    if (assemblyName.CultureInfo.Equals(CultureInfo.InvariantCulture) == false)
    {
        path = String.Format(@"{0}\{1}", assemblyName.CultureInfo, path);
    }

    using (Stream stream = executingAssembly.GetManifestResourceStream(path))
    {
        if (stream == null)
            return null;

        var assemblyRawBytes = new byte[stream.Length];
        stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);

        return Assembly.Load(assemblyRawBytes);
    }
}

我认为最好的方法是添加功能以跟踪列表中加载的所有程序集,一旦以这种方式加载了新程序集,递归地执行相同的操作;随时加载其中的任何嵌入式 DLL。然后,您可以将这些 DLL 添加到将充当缓存的列表中。

是否有更好的方法来进行此操作?

4

1 回答 1

2

我已经实施了一个与您的解决方案非常相似的解决方案,它对我来说效果很好。_references如您所见,我在字典中跟踪已加载的程序集。

就我而言,我不需要以任何递归方式“急切地”加载所有嵌入式依赖项,而是我的嵌入式程序集确实按需向应用程序主机注册。

public static class ApplicationHost
{
    private static readonly Dictionary<string, Assembly> _references = new Dictionary<string, Assembly>();

    [STAThread]
    private static void Main()
    {
        AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => _references.ContainsKey(args.Name) ? _references[args.Name] : null;
        RegisterAssemblyAndEmbeddedDependencies();
        // continue application bootstrapping...
    }

    public static void RegisterAssemblyAndEmbeddedDependencies()
    {
        var assembly = Assembly.GetCallingAssembly();
        _references[assembly.FullName] = assembly;
        foreach (var resourceName in assembly.GetManifestResourceNames())
        {
            using (var resourceStream = assembly.GetManifestResourceStream(resourceName))
            {
                var rawAssembly = new byte[resourceStream.Length];
                resourceStream.Read(rawAssembly, 0, rawAssembly.Length);
                var reference = Assembly.Load(rawAssembly);
                _references[reference.FullName] = reference;
            }
        }
    }
}
于 2014-05-06T17:37:43.480 回答