MEF: "Unable to load one or more of the requested types. Retrieve the LoaderExceptions for more information"

d7samurai picture d7samurai · Oct 26, 2010 · Viewed 12.2k times · Source

Scenario: I am using Managed Extensibility Framework to load plugins (exports) at runtime based on an interface contract defined in a separate dll. In my Visual Studio solution, I have 3 different projects: The host application, a class library (defining the interface - "IPlugin") and another class library implementing the interface (the export - "MyPlugin.dll").

The host looks for exports in its own root directory, so during testing, I build the whole solution and copy Plugin.dll from the Plugin class library bin/release folder to the host's debug directory so that the host's DirectoryCatalog will find it and be able to add it to the CompositionContainer. Plugin.dll is not automatically copied after each rebuild, so I do that manually each time I've made changes to the contract/implementation.

However, a couple of times I've run the host application without having copied (an updated) Plugin.dll first, and it has thrown an exception during composition:

Unable to load one or more of the requested types. Retrieve the LoaderExceptions for more information

This is of course due to the fact that the Plugin.dll it's trying to import from implements a different version of IPlugin, where the property/method signatures don't match. Although it's easy to avoid this in a controlled and monitored environment, by simply avoiding (duh) obsolete IPlugin implementations in the plugin folder, I cannot rely on such assumptions in the production environment, where legacy plugins could be encountered.

The problem is that this exception effectively botches the whole Compose action and no exports are imported. I would have preferred that the mismatching IPlugin implementations are simply ignored, so that other exports in the catalog(s), implementing the correct version of IPlugin, are still imported.

Is there a way to accomplish this? I'm thinking either of several potential options:

  • There is a flag to set on the CompositionContainer ("ignore failing imports") prior to or when calling Compose
  • There is a similar flag to specify on the <ImportMany()> attribute
  • There is a way to "hook" on to the iteration process underlying Compose(), and be able to deal with each (failed) import individually
  • Using strong name signing to somehow only look for imports implementing the current version of IPlugin

Ideas?

Answer

Wim Coenen picture Wim Coenen · Oct 26, 2010

I have also run into a similar problem.

If you are sure that you want to ignore such "bad" assemblies, then the solution is to call AssemblyCatalog.Parts.ToArray() right after creating each assembly catalog. This will trigger the ReflectionTypeLoadException which you mention. You then have a chance to catch the exception and ignore the bad assembly.

When you have created AssemblyCatalog objects for all the "good" assemblies, you can aggregate them in an AggregateCatalog and pass that to the CompositionContainer constructor.