MEF - 从嵌入式 DLL 获取程序集
MEF - Get assembly from embedded DLL
我正在使用 MEF 为我的 WPF 应用程序创建 "plugins"。其中一些插件我想直接嵌入到 EXE 文件中,因为 EXE 需要是独立的。我正在使用 Fody 的 Costura 来嵌入该资源以及我的所有其他参考资料。由于 exe 文件需要独立,我无法为这些插件创建目录并使用 DirectoyCatalog
我是否可以从嵌入式资源加载程序集,或者简单地指定程序集名称,例如:
catalog.Catalogs.Add(new AssemblyCatalog("My.Assembly.Name));
我试过遍历 Manifest 资源,但这些似乎是由 Fody 压缩的:
var resourceNames = GetType().Assembly.GetManifestResourceNames();
foreach (var resourceName in resourceNames)
任何help/suggestions赞赏。
好的,使用下面的 class(在 https://github.com/Sebazzz/EntityProfiler/blob/master/src/UI/EntityProfiler.Viewer/AppBootstrapper.cs 找到此代码并根据我的需要进行调整):
要使用它,您只需调用提取函数,它会在资源清单中找到任何 Costura Zip 文件并解压缩并注册它。
函数 returns 与函数中传递的字符串相匹配的所有程序集的字典。然后我遍历它们并添加到目录以供组合容器使用:
var assemblies = CosturaAssemblyExtractor.Extract(AppDomain.CurrentDomain, Assembly.GetExecutingAssembly(), "My.AssemblyName");
foreach (var assembly in assemblies)
{
catalog.Catalogs.Add(new AssemblyCatalog(assembly.Value));
}
container = new CompositionContainer(catalog);
Class:
public static class CosturaAssemblyExtractor
{
public static Dictionary<string, Assembly> Extract(AppDomain OrigDomain, Assembly ExecutingAssembly, string AssemblyStartsWith)
{
//var currentDomain = origDomain;
var assemblies = OrigDomain.GetAssemblies();
var references = new Dictionary<string, Assembly>();
var manifestResourceNames = ExecutingAssembly.GetManifestResourceNames().Where(x => {
return x.ToUpper().StartsWith(("costura." + AssemblyStartsWith).ToUpper()) && x.ToUpper().EndsWith(".dll.zip".ToUpper());
});
foreach (var resourceName in manifestResourceNames)
{
var solved = false;
foreach (var assembly in assemblies)
{
var refName = string.Format("costura.{0}.dll.zip", GetDllName(assembly, true));
if (resourceName.Equals(refName, StringComparison.OrdinalIgnoreCase))
{
references[assembly.FullName] = assembly;
solved = true;
break;
}
}
if (solved)
continue;
using (var resourceStream = ExecutingAssembly.GetManifestResourceStream(resourceName))
{
if (resourceStream == null) continue;
if (resourceName.EndsWith(".dll.zip"))
{
using (var compressStream = new DeflateStream(resourceStream, CompressionMode.Decompress))
{
var memStream = new MemoryStream();
CopyTo(compressStream, memStream);
memStream.Position = 0;
var rawAssembly = new byte[memStream.Length];
memStream.Read(rawAssembly, 0, rawAssembly.Length);
var reference = Assembly.Load(rawAssembly);
references[reference.FullName] = reference;
}
}
else
{
var rawAssembly = new byte[resourceStream.Length];
resourceStream.Read(rawAssembly, 0, rawAssembly.Length);
var reference = Assembly.Load(rawAssembly);
references[reference.FullName] = reference;
}
}
}
return references;
}
private static void CopyTo(Stream source, Stream destination)
{
var array = new byte[81920];
int count;
while ((count = source.Read(array, 0, array.Length)) != 0)
{
destination.Write(array, 0, count);
}
}
private static string GetDllName(Assembly assembly, bool withoutExtension = false)
{
var assemblyPath = assembly.CodeBase;
return withoutExtension ? Path.GetFileNameWithoutExtension(assemblyPath) : Path.GetFileName(assemblyPath);
}
}
我只需从当前的 AppDomain 加载程序集,就可以让它在我的项目中工作。
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
catalog.Catalogs.Add(new AssemblyCatalog(assembly));
}
我正在使用 MEF 为我的 WPF 应用程序创建 "plugins"。其中一些插件我想直接嵌入到 EXE 文件中,因为 EXE 需要是独立的。我正在使用 Fody 的 Costura 来嵌入该资源以及我的所有其他参考资料。由于 exe 文件需要独立,我无法为这些插件创建目录并使用 DirectoyCatalog
我是否可以从嵌入式资源加载程序集,或者简单地指定程序集名称,例如:
catalog.Catalogs.Add(new AssemblyCatalog("My.Assembly.Name));
我试过遍历 Manifest 资源,但这些似乎是由 Fody 压缩的:
var resourceNames = GetType().Assembly.GetManifestResourceNames();
foreach (var resourceName in resourceNames)
任何help/suggestions赞赏。
好的,使用下面的 class(在 https://github.com/Sebazzz/EntityProfiler/blob/master/src/UI/EntityProfiler.Viewer/AppBootstrapper.cs 找到此代码并根据我的需要进行调整):
要使用它,您只需调用提取函数,它会在资源清单中找到任何 Costura Zip 文件并解压缩并注册它。
函数 returns 与函数中传递的字符串相匹配的所有程序集的字典。然后我遍历它们并添加到目录以供组合容器使用:
var assemblies = CosturaAssemblyExtractor.Extract(AppDomain.CurrentDomain, Assembly.GetExecutingAssembly(), "My.AssemblyName");
foreach (var assembly in assemblies)
{
catalog.Catalogs.Add(new AssemblyCatalog(assembly.Value));
}
container = new CompositionContainer(catalog);
Class:
public static class CosturaAssemblyExtractor
{
public static Dictionary<string, Assembly> Extract(AppDomain OrigDomain, Assembly ExecutingAssembly, string AssemblyStartsWith)
{
//var currentDomain = origDomain;
var assemblies = OrigDomain.GetAssemblies();
var references = new Dictionary<string, Assembly>();
var manifestResourceNames = ExecutingAssembly.GetManifestResourceNames().Where(x => {
return x.ToUpper().StartsWith(("costura." + AssemblyStartsWith).ToUpper()) && x.ToUpper().EndsWith(".dll.zip".ToUpper());
});
foreach (var resourceName in manifestResourceNames)
{
var solved = false;
foreach (var assembly in assemblies)
{
var refName = string.Format("costura.{0}.dll.zip", GetDllName(assembly, true));
if (resourceName.Equals(refName, StringComparison.OrdinalIgnoreCase))
{
references[assembly.FullName] = assembly;
solved = true;
break;
}
}
if (solved)
continue;
using (var resourceStream = ExecutingAssembly.GetManifestResourceStream(resourceName))
{
if (resourceStream == null) continue;
if (resourceName.EndsWith(".dll.zip"))
{
using (var compressStream = new DeflateStream(resourceStream, CompressionMode.Decompress))
{
var memStream = new MemoryStream();
CopyTo(compressStream, memStream);
memStream.Position = 0;
var rawAssembly = new byte[memStream.Length];
memStream.Read(rawAssembly, 0, rawAssembly.Length);
var reference = Assembly.Load(rawAssembly);
references[reference.FullName] = reference;
}
}
else
{
var rawAssembly = new byte[resourceStream.Length];
resourceStream.Read(rawAssembly, 0, rawAssembly.Length);
var reference = Assembly.Load(rawAssembly);
references[reference.FullName] = reference;
}
}
}
return references;
}
private static void CopyTo(Stream source, Stream destination)
{
var array = new byte[81920];
int count;
while ((count = source.Read(array, 0, array.Length)) != 0)
{
destination.Write(array, 0, count);
}
}
private static string GetDllName(Assembly assembly, bool withoutExtension = false)
{
var assemblyPath = assembly.CodeBase;
return withoutExtension ? Path.GetFileNameWithoutExtension(assemblyPath) : Path.GetFileName(assemblyPath);
}
}
我只需从当前的 AppDomain 加载程序集,就可以让它在我的项目中工作。
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
catalog.Catalogs.Add(new AssemblyCatalog(assembly));
}