1

Console application tries to load plugins using MEF from special "plugins" folder. On the other hand, binary folder of application contains "legacy" version of plugin "PluginAdd.dll". Console application fails with error:

Unhandled Exception: System.Reflection.ReflectionTypeLoadException: Unable to lo
ad one or more of the requested types. Retrieve the LoaderExceptions property fo
r more information.
   at System.Reflection.RuntimeModule.GetTypes(RuntimeModule module)
   at System.Reflection.RuntimeModule.GetTypes()
   at System.Reflection.Assembly.GetTypes()
   at System.ComponentModel.Composition.Hosting.AssemblyCatalog.get_InnerCatalog
()

How can I solve the issue and request from MEF load plugin only from dedicated folder (and not from binary folder)?

Sample loaded to git (project MEF-loading-issue): https://github.com/constructor-igor/TechSugar/trunk/MEF/MEF

Plugins loaded by next code:

public class Client
{
    [ImportMany]
    public Lazy<ICommandPlugin, IDictionary<string, object>>[] CommandPlugins { get; set; }

    public void LoadPlugins()
    {
        var aggregateCatalog = new AggregateCatalog();               

        var pluginAssemblyCatalog = new AssemblyCatalog(@"..\..\..\@PluginBinaries\PluginAdd.dll");            
        aggregateCatalog.Catalogs.Add(pluginAssemblyCatalog);

        var container = new CompositionContainer(aggregateCatalog);
        container.ComposeParts(this);
    }
}

Config file of application contains path to plugin folder:

<probing privatePath="..\..\..\@PluginBinaries"/>

UPD1 added full exception stack trace

Unhandled Exception: System.Reflection.ReflectionTypeLoadException: Unable to lo
ad one or more of the requested types. Retrieve the LoaderExceptions property fo
r more information.
   at System.Reflection.RuntimeModule.GetTypes(RuntimeModule module)
   at System.Reflection.RuntimeModule.GetTypes()
   at System.Reflection.Assembly.GetTypes()
   at System.ComponentModel.Composition.Hosting.AssemblyCatalog.get_InnerCatalog
()
   at System.ComponentModel.Composition.Hosting.AssemblyCatalog.GetExports(Impor
tDefinition definition)
   at System.ComponentModel.Composition.Hosting.AggregateCatalog.GetExports(Impo
rtDefinition definition)
   at System.ComponentModel.Composition.Hosting.CatalogExportProvider.InternalGe
tExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)
   at System.ComponentModel.Composition.Hosting.CatalogExportProvider.InnerCatal
ogExportProvider.GetExportsCore(ImportDefinition definition, AtomicComposition a
tomicComposition)
   at System.ComponentModel.Composition.Hosting.ExportProvider.TryGetExportsCore
(ImportDefinition definition, AtomicComposition atomicComposition, IEnumerable`1
& exports)
   at System.ComponentModel.Composition.Hosting.CatalogExportProvider.GetExports
Core(ImportDefinition definition, AtomicComposition atomicComposition)
   at System.ComponentModel.Composition.Hosting.ExportProvider.TryGetExportsCore
(ImportDefinition definition, AtomicComposition atomicComposition, IEnumerable`1
& exports)
   at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(Import
Definition definition, AtomicComposition atomicComposition)
   at System.ComponentModel.Composition.Hosting.AggregateExportProvider.GetExpor
tsCore(ImportDefinition definition, AtomicComposition atomicComposition)
   at System.ComponentModel.Composition.Hosting.ExportProvider.TryGetExportsCore
(ImportDefinition definition, AtomicComposition atomicComposition, IEnumerable`1
& exports)
   at System.ComponentModel.Composition.Hosting.CompositionContainer.GetExportsC
ore(ImportDefinition definition, AtomicComposition atomicComposition)
   at System.ComponentModel.Composition.Hosting.ExportProvider.TryGetExportsCore
(ImportDefinition definition, AtomicComposition atomicComposition, IEnumerable`1
& exports)
   at System.ComponentModel.Composition.Hosting.ExportProvider.GetExports(Import
Definition definition, AtomicComposition atomicComposition)
   at System.ComponentModel.Composition.Hosting.ImportEngine.TryGetExports(Expor
tProvider provider, ComposablePart part, ImportDefinition definition, AtomicComp
osition atomicComposition)
   at System.ComponentModel.Composition.Hosting.ImportEngine.TrySatisfyImportSub
set(PartManager partManager, IEnumerable`1 imports, AtomicComposition atomicComp
osition)
   at System.ComponentModel.Composition.Hosting.ImportEngine.TrySatisfyImportsSt
ateMachine(PartManager partManager, ComposablePart part)
   at System.ComponentModel.Composition.Hosting.ImportEngine.TrySatisfyImports(P
artManager partManager, ComposablePart part, Boolean shouldTrackImports)
   at System.ComponentModel.Composition.Hosting.ImportEngine.SatisfyImports(Comp
osablePart part)
   at System.ComponentModel.Composition.Hosting.ComposablePartExportProvider.<>c
__DisplayClass2.<Compose>b__0()
   at System.ComponentModel.Composition.Hosting.CompositionServices.TryInvoke(Ac
tion action)
   at System.ComponentModel.Composition.Hosting.ComposablePartExportProvider.Com
pose(CompositionBatch batch)
   at System.ComponentModel.Composition.Hosting.CompositionContainer.Compose(Com
positionBatch batch)
   at System.ComponentModel.Composition.AttributedModelServices.ComposeParts(Com
positionContainer container, Object[] attributedParts)
   at MEF_loading_issue.Client.LoadPlugins() in d:\My\MyProjects\@TechSugar\Tech
Sugar.Samples\trunk\MEF\MEF\MEF-loading-issue\Program.cs:line 40
   at MEF_loading_issue.Program.Main() in d:\My\MyProjects\@TechSugar\TechSugar.
Samples\trunk\MEF\MEF\MEF-loading-issue\Program.cs:line 19

UPD2 added screen with exception message enter image description here

UPD3 same issue described in CompositionContainer loading wrong directory through DirectoryCatalog, but not found exact answer

Community
  • 1
  • 1
constructor
  • 1,412
  • 1
  • 17
  • 34
  • Can you please provide the content of `LoaderExceptions` of your Exception ? (All the useful infos are inside) – rducom Mar 03 '15 at 16:11
  • added full stack trace. MEF failed, because tries to load "legacy" plugin from binary folder. how to ask it to load plugin from necessary folder only? – constructor Mar 03 '15 at 16:18
  • You added the stacktrace, it's the Message of LoaderExceptions which is interesting. – rducom Mar 03 '15 at 16:22
  • screen with message and other exception's details added to post – constructor Mar 03 '15 at 21:34
  • So the interesting part is "Method [...] does not have an implementation". And you fill find your answer here : http://stackoverflow.com/questions/948785/typeloadexception-says-no-implementation-but-it-is-implemented – rducom Mar 03 '15 at 21:39
  • Method "Action" not implemented in "legacy" plugin binary. I don't understand why MEF loads "legacy" plugin, instead of load "good" plugin binary from defined path in AssemblyCatalog constructor. – constructor Mar 03 '15 at 22:04

2 Answers2

2

Found a workaround: instead of

var pluginAssemblyCatalog = new AssemblyCatalog(@"..\..\..\@PluginBinaries\PluginAdd.dll");

can be used

var pluginAssemblyCatalog = new AssemblyCatalog(Assembly.LoadFrom(@"..\..\..\@PluginBinaries\PluginAdd.dll"));

In the case, MEF loads plugin from dedicated file and doesn't load from "binary" folder.

constructor
  • 1,412
  • 1
  • 17
  • 34
2

The Load context is generally preferable to the LoadFrom context. So when MEF goes to load an assembly from a file, it will first get the assembly name, and try doing an Assembly.Load on it to load it in the Load context. Only if this fails will it load the assembly in the LoadFrom context.

So the reason the legacy version of the plugin is being loaded is because that's the version that's available in the Load context, which MEF prefers.

It might be better to simply remove the legacy version of the plugin from your app's binary folder. I don't know why it's there so I don't know if that's an option for you.

Daniel Plaisted
  • 16,674
  • 4
  • 44
  • 56
  • ok, now I understand better difference between Load and LoadFrom, but it's not clear why I define **exact path to assembly file**, but MEF can ingore the path and load assembly from "default context". – constructor Mar 05 '15 at 22:00
  • @constructor It gets the assembly name from the file and tries to do an `Assembly.Load()` on that name first. That's how it is able to prefer the Load context. You can see the code in the `LoadAssembly` method here: http://mef.codeplex.com/SourceControl/latest#redist/src/ComponentModel/System/ComponentModel/Composition/Hosting/AssemblyCatalog.cs – Daniel Plaisted Mar 23 '15 at 23:30