【问题标题】:MEF - Get assembly from embedded DLLMEF - 从嵌入式 DLL 获取程序集
【发布时间】:2016-09-07 11:14:47
【问题描述】:

我正在使用 MEF 为我的 WPF 应用程序创建“插件”。其中一些插件我想直接嵌入到 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)

感谢任何帮助/建议。

【问题讨论】:

    标签: c# wpf mef fody


    【解决方案1】:

    好的,这对我有用,使用下面的类(在https://github.com/Sebazzz/EntityProfiler/blob/master/src/UI/EntityProfiler.Viewer/AppBootstrapper.cs 找到此代码并进行调整以满足我的需要):

    要使用它,您只需调用 extract 函数,该函数将在资源清单中找到任何 Costura Zip 文件并将其解压缩并注册。

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

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

    【讨论】:

    • 目前的 costura 版本似乎附加了“压缩”而不是“压缩”。无论如何,与其至少进行第二次检查EndsWith(".dll.zip"),不如直接将try 转到DeflateStream,然后按原样进行错误复制。此外,Stream 已经有CopyTo()
    • @user1207289 不确定。可能是您传入的执行程序集吗?因为从 mstest 调用时这可能会有所不同?
    • @user1207289 你有我可以看的示例代码吗?
    • 好的。你得到了确切的错误信息吗?感谢不能共享所有代码。但是您可以设置一个真正基本的解决方案来复制错误并分享吗? @user1207289
    【解决方案2】:

    只需从当前 AppDomain 加载程序集,我就可以让它在我的项目中工作。

    foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
    {
        catalog.Catalogs.Add(new AssemblyCatalog(assembly));
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-11
      • 1970-01-01
      • 2011-10-17
      • 2017-11-02
      • 2014-12-05
      • 1970-01-01
      相关资源
      最近更新 更多