2016-09-07 53 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); 
    } 
}