Method export problem in convention-based part registration

Dec 20, 2011 at 12:43 PM
Edited Dec 20, 2011 at 12:58 PM

I've encountered a problem while trying to export a method in MEF 2 Preview 4 (and the new Preview 5).

Searching the problem leads me to this unanswered discussion: Method export fails when using RegistrationBuilder

I don't repeat the details of the problem. It's thoroughly described in that discussion. In a word an ArgumentException saying "MethodInfo must be a runtime MethodInfo object." is thrown by the framework when using method export and convention-based part registration (RegistrationBuilder). I've checked both attribute-based (ImportAttribute) and conventin-based (ImportProperty) import methods.

This is the call stack:

System.ComponentModel.Composition.CodePlex.dll!System.ComponentModel.Composition.Primitives.ExportedDelegate.CreateDelegate(System.Type delegateType) Line 40	C#
System.ComponentModel.Composition.CodePlex.dll!Microsoft.Internal.ContractServices.TryCast(System.Type contractType, object value, out object result) Line 32 + 0x28 bytes	C#
System.ComponentModel.Composition.CodePlex.dll!System.ComponentModel.Composition.ReflectionModel.ImportingItem.Cast(System.Type type, System.ComponentModel.Composition.Primitives.Export export) Line 102 + 0x10 bytes	C#
System.ComponentModel.Composition.CodePlex.dll!System.ComponentModel.Composition.ReflectionModel.ImportingItem.CastSingleExportToImportType(System.Type type, System.ComponentModel.Composition.Primitives.Export export) Line 91 + 0xf bytes	C#
System.ComponentModel.Composition.CodePlex.dll!System.ComponentModel.Composition.ReflectionModel.ImportingItem.CastExportsToSingleImportType(System.ComponentModel.Composition.Primitives.Export[] exports) Line 81 + 0x3d bytes	C#
System.ComponentModel.Composition.CodePlex.dll!System.ComponentModel.Composition.ReflectionModel.ImportingItem.CastExportsToImportType(System.ComponentModel.Composition.Primitives.Export[] exports) Line 47 + 0xc bytes	C#
System.ComponentModel.Composition.CodePlex.dll!System.ComponentModel.Composition.ReflectionModel.ReflectionComposablePart.SetImport(System.ComponentModel.Composition.ReflectionModel.ImportingItem item, System.ComponentModel.Composition.Primitives.Export[] exports) Line 247 + 0xe bytes	C#
System.ComponentModel.Composition.CodePlex.dll!System.ComponentModel.Composition.ReflectionModel.ReflectionComposablePart.SetImport(System.ComponentModel.Composition.Primitives.ImportDefinition definition, System.Collections.Generic.IEnumerable exports) Line 210	C#
System.ComponentModel.Composition.CodePlex.dll!System.ComponentModel.Composition.Hosting.ImportEngine.PartManager.TrySetImport(System.ComponentModel.Composition.Primitives.ImportDefinition import, System.Collections.Generic.IEnumerable exports) Line 84	C#
System.ComponentModel.Composition.CodePlex.dll!System.ComponentModel.Composition.Hosting.ImportEngine.TrySatisfyImportSubset(System.ComponentModel.Composition.Hosting.ImportEngine.PartManager partManager, System.Collections.Generic.IEnumerable imports, System.ComponentModel.Composition.Hosting.AtomicComposition atomicComposition) Line 479 + 0x1a bytes	C#
System.ComponentModel.Composition.CodePlex.dll!System.ComponentModel.Composition.Hosting.ImportEngine.TrySatisfyImportsStateMachine(System.ComponentModel.Composition.Hosting.ImportEngine.PartManager partManager, System.ComponentModel.Composition.Primitives.ComposablePart part) Line 360 + 0x1a bytes	C#
System.ComponentModel.Composition.CodePlex.dll!System.ComponentModel.Composition.Hosting.ImportEngine.TrySatisfyImports(System.ComponentModel.Composition.Hosting.ImportEngine.PartManager partManager, System.ComponentModel.Composition.Primitives.ComposablePart part, bool shouldTrackImports) Line 438 + 0x18 bytes	C#
System.ComponentModel.Composition.CodePlex.dll!System.ComponentModel.Composition.Hosting.ImportEngine.SatisfyImportsOnce(System.ComponentModel.Composition.Primitives.ComposablePart part) Line 211 + 0x14 bytes	C#
System.ComponentModel.Composition.CodePlex.dll!System.ComponentModel.Composition.Hosting.CompositionContainer.SatisfyImportsOnce(System.ComponentModel.Composition.Primitives.ComposablePart part) Line 514	C#
System.ComponentModel.Composition.CodePlex.dll!System.ComponentModel.Composition.AttributedModelServices.SatisfyImportsOnce(System.ComponentModel.Composition.ICompositionService compositionService, object attributedPart) Line 200	C#

I've inspected the source code and found out the problem occurs when Delegate.CreateDelegate static method is called in CreateDelegate method of ExportedDelegate class (source). The Delegate.CreateDelegate method needs a RuntimeMethodInfo but the passed argument is of type CustomMethodInfo.

As I've understood in reflection context all types are mapped to CustomType and CustomType.GetMethods returns CustomMethodInfo objects.

I don't know if this is an issue but I would be glad if somebody knows a workaround for it.

Thanks

Dec 20, 2011 at 3:48 PM

Thanks very much for raising this - the original thread somehow slipped under the radar. I've now raised an issue in the tracker: http://mef.codeplex.com/workitem/14570

As a workaround, you can use property exports with delegates. So:

[Export]

public void Foo() { ... }

Can be replaced with a method/property pair:

[Export]

public Action FooExport { get { return Foo; } }

public void Foo() { ... }

Thanks again, and hope this workaround helps.

Nick