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
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(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.