2016-09-07 46 views
1

我正在使用MEF为我的WPF应用程序创建“插件”。我想将这些插件中的一些直接嵌入到EXE文件中,因为EXE需要独立运行。我正在使用Fody的Costura嵌入资源以及所有其他参考资料。由于exe文件需要独立,我无法为这些插件创建目录并使用DirectoyCatalogMEF - 从嵌入式DLL获取程序集

有没有办法从嵌入式资源加载程序集,或者只是指定程序集名称,例如:

catalog.Catalogs.Add(new AssemblyCatalog("My.Assembly.Name)); 

我试图通过清单资源循环,但这些似乎是由Fody被拉链:

var resourceNames = GetType().Assembly.GetManifestResourceNames(); 
      foreach (var resourceName in resourceNames) 

任何帮助/建议表示赞赏。

回答

2

确定,所以得到这个工作对我来说,使用下面的类(发现这个代码在https://github.com/Sebazzz/EntityProfiler/blob/master/src/UI/EntityProfiler.Viewer/AppBootstrapper.cs和调整,以满足我的需要):

要使用它,你只需要调用提取功能将找到任何Costura邮编资源清单中的文件并对其进行解压缩并注册。

该函数返回与函数中传递的字符串匹配的所有程序集字典。然后我遍历并添加到目录由组合物的容器一起使用:

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); 

类别:

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); 
    } 
}