使用MEF加载带有嵌入式库的DLL
本文关键字:DLL 嵌入式 MEF 加载 使用 | 更新日期: 2023-09-27 18:01:03
我目前正在编写一个带有插件系统的应用程序套件,该插件系统在运行时使用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。然后,您可以将这些DLL添加到将用作缓存的列表中。
有没有更好的方法来进行这项工作?
我实现了一个与您的解决方案非常相似的解决方案,它对我来说非常好。正如您所看到的,我在_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;
}
}
}
}