如何读取一个DLL插件MEF元数据,而不复制整个DLL到内存? [英] How to read MEF metadata in a DLL plugin without copying the entire DLL into memory?

查看:123
本文介绍了如何读取一个DLL插件MEF元数据,而不复制整个DLL到内存?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景:



我感兴趣的使用MEF使用C#在.NET提供一个WinForm应用程序插件架构4.0,但我不是一对夫妇的事情说清楚。



第一:我还没有与建筑的DLL但在C#供职于一切,我有点模糊对DLL组件的概念以及如何DLL正常加载到内存中(意思是,一次全部或部分根据需要)



意图:



该方案将是一个机器硬件控制框架,并将由一个主WinForm的图形用户界面,它与基本工具栏,菜单等的通用环境 - 但没有批量GUI内容。 (想想:MDI父但实际上没有)



该插件提供的所有控件的特定计算机。每个许多可能的插件将含有潜在的30至50个大的UserControls,各有数十种之多的WinForm控件和吨的支持代码拼成的各种机器的控制面板进行填充。



这意味着该主程序是一个轻量级总框架和插件包含批量GUI控件和功能,将在程序主用户界面中显示可包括大量的图标,图像,以及其他资源。这将使得该插件的DLL可能相当大。



的目标是允许用户从菜单中选择一个插件,然后经选择,负载并运行该插件,然后将填充面板,菜单和工具箱嘉豪大多是空的主界面。



要做到这一点,我需要从第一次提取元数据每一个插件来填充方案,该方案将包括插件名称,描述,图标,版本号和信息的其他位的初始菜单。



这里有几个问题:



通过MEF,如果我尝试从每个很多大型的DLL存储在一个插件读取的元数据在文件夹中,将整个DLL被复制到内存中访问元数据值过吗?



如果是这样,有什么办法可以打开每个DLL文件和只读元数据到内存中构建初始菜单 - 后来通过MEF加载完整选择DLL?



我假设通过MEF阅读插件典型DirectoryCatalog和AggregateCatalog模板将所有发现的DLL复制到内存中并存储在目录收藏。



执行的DLL包含一个连续的代码块(组装),也可以包含索引并复制到记忆个别需要(多组件)的多个独立的模块?



我可能不了解​​基本面,也许容易混淆的名词。我将不胜感激任何见解MEF,DLL和一般大会的加载行为。谢谢!


解决方案

通过MEF,如果我尝试从每个很多大型的DLL读取的元数据
存储在插件文件夹中,将整个的DLL被复制
分成存储器被访问的元数据值之前




据我了解整个DLL将被加载到内存中。这并没有什么关系,虽然MEF。 DirectoryCatalog 将加载到使用的 AssemblyCatalog ):// MSDN。 microsoft.com/en-us/library/x4cw969y.aspx\">Assembly.Load 。这种方法并不MEF的一部分,但它是.NET Framework的核心方法。大多数装载组件的装载这种方式。如果您监视运行的过程中使用的 Process Explorer的你可以看到的虚拟大小的将增加由加载的程序集的大小。所以,如果你加载巨大的程序集的虚拟大小的流程将是高的。




如果是这样,有没有办法打开每个DLL文件和只读的
的元数据到内存中构建初始菜单 - ?后来通过MEF加载
全选DLL




有方法可以做到这一点。



的一种方式是创建一个新的应用领域,在新的AppDomain创建 CompositionContainer中,并检查发现部分。然后序列化这些部件主要的AppDomain信息。最后卸载新的AppDomain。然后,你可以检查哪些地方,你真的需要,只加载包含它们的组件。如何做到这一点的例子可以在此回答被发现。



另一种方法是使用 Mono.Cecil能做到的。这是伟大的图书馆,可以帮助你检查组件无需加载它们。你可以在这样的方法, MEF的导出元数据结合起来:

 公共静态布尔IncludesTypeWithSpecificExportMetadata< T>(字符串assemblyPath,字符串名称,T值)
{
AssemblyDefinition assemblyDefinition = AssemblyDefinition.ReadAssembly (assemblyPath);

布尔typeWasFound = FALSE;

的foreach(类型定义类型定义在assemblyDefinition.MainModule.GetTypes())
{
的foreach(CustomAttribute customAttribute在typeDefinition.CustomAttributes)
{
如果( customAttribute.AttributeType.FullName == typeof运算(ExportMetadataAttribute).FullName)
{
串actualName =(字符串)customAttribute.ConstructorArguments [0] .value的; $ B $(B T)= actualValue(T)((CustomAttributeArgument)customAttribute.ConstructorArguments [1] .value的).value的;
如果(actualName.Equals(名称)及和放大器; actualValue.Equals(值))
{
typeWasFound = TRUE;
}
}
}
}

返回typeWasFound;
}



由于汇编文件路径和名称/值对这种方法将检查使用Mono.Cecil能做到,查找各类装饰着 ExportMetadataAttribute 并使用相同的名称/值对。




我假设通过MEF阅读插件典型DirectoryCatalog和AggregateCatalog
模板将复制所有的
中发现的DLL到内存中并存储在目录集合中。




真。




执行的DLL包含一个连续的代码块(组装),或者他们可以
包含被索引并复制到内存
多个独立块个别需要(多个程序集)?




我不知道这件事。您可能会发现在必要的.NET卷1唐盒或杰弗里里希特答案通过CLR C#。




我米大概不了解基本面,也许混淆
条款。我将不胜感激任何见解MEF,
DLL和组件的总体负担的行为。谢谢!




我上面提到的著作包括详细组件如何解决/加载等等等等。也看看苏珊库克的博客



现在我想问你一件事。你真的需要大文件嵌入到你的组件?如果你能找到另一种方式,那么你不需要任何的这一点。您的插件引擎将是一点点简单的



最后,我建议看看微软的智能客户端软件工厂。它可以做你提到的几乎每一样东西。这将需要一些努力去理解它,并感觉舒服,但在长远来看,这可能会为你节省大量的时间。


Background:

I'm interested in using MEF to provide a plug-in architecture in a WinForm application using C# with .NET 4.0, but I am not clear on a couple of things.

First: I have not worked at all with building DLLs yet in C#, and I'm a little fuzzy on the concept of DLL Assemblies and how a DLL is normally loaded into memory ( meaning, all at once or in pieces as needed )

Intent:

The program will be a machine hardware control framework, and will be made up of a primary WinForm GUI that is a generic environment with basic toolbars, menus, etc - but no bulk GUI content. ( Think: MDI Parent but not actually ).

The plug-ins provide all of the controls for a specific machine. Each of many possible plug-ins will contain potentially 30 to 50 large UserControls, each populated with many dozens of WinForm Controls and tons of support code that makes up the various machine control panels.

This means that the main program is a lightweight general framework and the plug-ins contain the bulk of the GUI controls and functionality that will be shown in the main program user interface, including lots of icons, images, and other resources. This will make the plug-in DLLs potentially quite large.

The goal is to allow the user to select a plug-in from a menu, and then upon selection, load and run the plug-in which will then fill the mostly empty main GUI with panels, menus, and toolboxes galore.

To do this, I need to first extract metadata from each plug-in to populate the initial menu for the program, which will include the plug-in title, description, icon, version numbers, and other bits of info.

Here are the questions:

With MEF, if I try to read the metadata from each of many large DLLs that are stored in a plug-in folder, will the entire DLL be copied into memory before the metadata values are accessed ?

If so, is there any way to open each DLL file and only read the metadata into memory to build the initial menu - then later load the full selected DLL through MEF ?

I am assuming that the typical DirectoryCatalog and AggregateCatalog template for reading plugins through MEF will copy all of the discovered DLLs into memory and store them in the catalog collection.

Do DLLs contain one contiguous code block ( assembly ), or can they contain multiple separate blocks that are indexed and copied to memory individually as needed ( multiple assemblies ) ?

I'm probably not understanding the fundamentals, and maybe confusing terms. I would appreciate any insight into the load behavior of MEF, DLLs, and Assemblies in general. Thanks !

解决方案

With MEF, if I try to read the metadata from each of many large DLLs that are stored in a plug-in folder, will the entire DLL be copied into memory before the metadata values are accessed ?

As far as I know the entire DLL will be loaded into memory. This does not have anything to do with MEF though. DirectoryCatalog will load the assembly (through AssemblyCatalog) using a call to Assembly.Load. This method is not part of MEF but it is a core method of the .NET Framework. Most of the loaded assemblies are loaded this way. If you monitor the process running your application using Process Explorer you can see that the Virtual Size will be increased by the size of the loaded assembly. So if you load huge assemblies the Virtual Size of your process will be high.

If so, is there any way to open each DLL file and only read the metadata into memory to build the initial menu - then later load the full selected DLL through MEF ?

There are ways to do this.

One way is to create a new application domain, create the CompositionContainer in the new AppDomain and check the discovered parts. Then serialize information about these parts to the main AppDomain. Finally unload the new AppDomain. Then you can check which parts you really need and only load the assemblies that contain them. An example on how to do this can be found in this answer.

Another approach is to use Mono.Cecil. This is great library that helps you inspect assemblies without loading them. You can combine it with MEF's Export Metadata in a method like this:

public static bool IncludesTypeWithSpecificExportMetadata<T>(string assemblyPath, string name, T value)
    {
        AssemblyDefinition assemblyDefinition = AssemblyDefinition.ReadAssembly(assemblyPath);

        bool typeWasFound = false;          

        foreach (TypeDefinition typeDefinition in assemblyDefinition.MainModule.GetTypes())
        {
            foreach (CustomAttribute customAttribute in typeDefinition.CustomAttributes)
            {
                if (customAttribute.AttributeType.FullName == typeof(ExportMetadataAttribute).FullName)
                {
                    string actualName = (string)customAttribute.ConstructorArguments[0].Value;
                    T actualValue = (T)((CustomAttributeArgument)customAttribute.ConstructorArguments[1].Value).Value;
                    if (actualName.Equals(name) && actualValue.Equals(value))                        
                    {
                        typeWasFound = true;                       
                    }
                }
            }
        }

        return typeWasFound;
    }

Given an assembly file path and a name/value pair this method will inspect the assembly using Mono.Cecil and look for types decorated with the ExportMetadataAttribute and with the same name/value pair.

I am assuming that the typical DirectoryCatalog and AggregateCatalog template for reading plugins through MEF will copy all of the discovered DLLs into memory and store them in the catalog collection.

True.

Do DLLs contain one contiguous code block ( assembly ), or can they contain multiple separate blocks that are indexed and copied to memory individually as needed ( multiple assemblies ) ?

I don't know about this. You might find the answer in "Essential .NET Volume 1" by Don Box or "C# via CLR" by Jeffrey Richter.

I'm probably not understanding the fundamentals, and maybe confusing terms. I would appreciate any insight into the load behavior of MEF, DLLs, and Assemblies in general. Thanks !

The books I mentioned above include in detail how assemblies are resolved/loaded blah blah. Also have a look at Suzanne Cook's blog.

Now I would like to ask you something. Do you really need to embed large files to your assemblies? If you can find another way then you will not need any of this. Your plug-in engine will be a little bit simple.

Finally I would suggest to have a look at Microsoft's Smart Client Software Factory. It can do pretty much everything you mention and more. It will take some effort to understand it and feel comfortable with it but in the long run it will probably save you loads of time.

这篇关于如何读取一个DLL插件MEF元数据,而不复制整个DLL到内存?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆