Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MEF composition issue

I can't solve what seems to be a basic MEF problem: I have 2 "plugins" project (which we'll call P1 and P2), and a third project that is common to both plugins (which we'll call C). P1 and P2 both reference C.

When trying to import a component that lives in P1, it fails because this component has dependencies on components that live in C.

Here is the trace:

System.ComponentModel.Composition Warning: 1 : The ComposablePartDefinition 'MyCompany.Client.Pms.Plugin.InclusionList.ViewModel.InclusionListViewModel' has been rejected. The composition remains unchanged. The changes were rejected because of the following error(s): The composition produced multiple composition errors, with 4 root causes. The root causes are provided below. Review the CompositionException.Errors property for more detailed information.

1) No exports were found that match the constraint '((exportDefinition.ContractName = "MyCompany.Client.Plugins.Common.Controls.Selectors.PortfolioSelectors.ViewModel.ICalypsoBookSelectorViewModel") && (exportDefinition.Metadata.ContainsKey("ExportTypeIdentity") && "MyCompany.Client.Plugins.Common.Controls.Selectors.PortfolioSelectors.ViewModel.ICalypsoBookSelectorViewModel".Equals(exportDefinition.Metadata.get_Item("ExportTypeIdentity"))))'.

Resulting in: Cannot set import 'MyCompany.Client.Pms.Plugin.InclusionList.ViewModel.InclusionListViewModel.CalypsoBookSelectorViewModel (ContractName="MyCompany.Client.Plugins.Common.Controls.Selectors.PortfolioSelectors.ViewModel.ICalypsoBookSelectorViewModel")' on part 'MyCompany.Client.Pms.Plugin.InclusionList.ViewModel.InclusionListViewModel'. Element: MyCompany.Client.Pms.Plugin.InclusionList.ViewModel.InclusionListViewModel.CalypsoBookSelectorViewModel (ContractName="MyCompany.Client.Plugins.Common.Controls.Selectors.PortfolioSelectors.ViewModel.ICalypsoBookSelectorViewModel") --> MyCompany.Client.Pms.Plugin.InclusionList.ViewModel.InclusionListViewModel --> DirectoryCatalog (Path="C:\Work\mmtrader\dashboard\Code\Src\Dashboard\MM\Trader\bin\Debug\Plugins\Positions")

[...] (The 3 other problems are exactly the same, on different view models)

I have looked at the MEF catalog, and it turns out that MEF knows about those view models, so I don't know what's missing.

As requested by Dennis below, here are my import/export:

Export:

Export(typeof(ICalypsoBookSelectorViewModel))]
public class CalypsoBookSelectorViewModel : ScreenWithCleanupLifecycle, ICalypsoBookSelectorViewModel
{...}

Import:

[Import(typeof(ICalypsoBookSelectorViewModel))]
public ICalypsoBookSelectorViewModel CalypsoBookSelectorViewModel { get; set; }

And the catalog:

Catalog

Thanks in advance for your help!

like image 727
Antoine Jaussoin Avatar asked Sep 13 '12 08:09

Antoine Jaussoin


2 Answers

I finally found the problem, and it had nothing to do with the CalypsoBookSelectorViewModel that MEF was pointing the finger on.

Indeed, the ViewModel has dependencies on another component (a CalypsoBookSelectorModel), which in turn has a dependency on a IDispatcher component.

The problem was that this IDispatcher component, which was specified with a contract name (see below), was exported TWICE (once in each plugin), so MEF couldn't tell which one to use. The real problem of course is that MEF should have told me that, instead of pointing the finger to a class two levels up the chain.

Thanks Dennis for looking at the problem, and I hope this will help other people who'll get the same problem.

The Dispatcher import:

[Import(DispatcherNames.BackgroundDispatcherName, typeof(IDispatcher))]
public IDispatcher Dispatcher { get; set; }
like image 66
Antoine Jaussoin Avatar answered Oct 27 '22 23:10

Antoine Jaussoin


Your P1 imports something from C (more exactly, ICalypsoBookSelectorViewModel).

When MEF container tries to create P1, it also tries to resolve all imports, which P1 depends from. Hence, it performs search for export of ICalypsoBookSelectorViewModel type (indeed, contract name, but it doesn't matter in this case) in its own catalog and parent export providers.

If such export is not found (this is your case), MEF container remains composition unchanged.
To fix this, you should add [Export(typeof(ICalypsoBookSelectorViewModel))] to the corresponding type definition.

Of course, all this implies, that your catalog and export providers (if there are any) are initialized properly.

Note, that this export definitions are not equal:

public interface IA {}

[Export(typeof(IA))] // contract name is "IA"
public class A : IA {}

[Export] // contract name is "A"
public class A : IA {}

[Export]
public class Composed
{
    [Import] // MEF will search for exports like [Export(typeof(IA))]
    private IA field1;

    [Import] // MEF will search for exports like [Export]
    private A field1;
}
like image 21
Dennis Avatar answered Oct 27 '22 22:10

Dennis