I understand that starting with MEF 2, MEF supports composing open generic types into closed types. I'm trying to compose a closed type from types exported from two different assemblies added to the same composition container and I'm receiving an ImportCardinalityMismatchException. I'm using conventions for one of the assemblies because it's not under my control. For the other I have used attributes.
I'm not exactly sure how to phrase my question as I find the terminology around generics rather confusing but I'm looking to compose my new closed type without explicitly implementing my own class, inheriting from Foo, and supplying it my FooUser type parameter. I don't know if this is an issue with how I'm doing this or if it has something to do with the fact that the types are in different assemblies.
In one assembly I have the following:
public class Foo<T> where T : Bar {}
public class Bar {}
In another assembly I have the following:
[Export]
public class Bar2 : Bar {}
[Export]
public class Something
{
[ImportingConstructor]
public Something([Import(typeof(Foo<>))] Foo<Bar2> foo) {}
}
In my registration code I have done the following:
var conventions = new RegistrationBuilder();
conventions.ForType(typeof(Foo<>)).Export();
var aggregateCatalog = new AggregateCatalog();
var catalog = new AssemblyCatalog(typeof(Foo<>).Assembly, conventions);
aggregateCatalog.Catalogs.Add(catalog);
catalog = new AssemblyCatalog(typeof(Something).Assembly);
aggregateCatalog.Catalogs.Add(catalog);
catalog = new AssemblyCatalog(typeof(Bar2).Assembly);
aggregateCatalog.Catalogs.Add(catalog);
var container = new CompositionContainer(aggregateCatalog, CompositionOptions.DisableSilentRejection);
var batch = new CompositionBatch();
batch.AddExportedValue(container);
container.Compose(batch);
Later I try to export my value thusly:
container.GetExportedValue<Something>();
Exception:Thrown: "No exports were found that match the constraint: ContractName Foo(Bar2) RequiredTypeIdentity Foo(Bar2)" (System.ComponentModel.Composition.ImportCardinalityMismatchException) A System.ComponentModel.Composition.ImportCardinalityMismatchException was thrown: "No exports were found that match the constraint: ContractName Foo(Bar2) RequiredTypeIdentity Foo(Bar2)"
I've looked in my conventions instance and in the container I have my parts i.e. Foo{0}, Bar2, and Something. I still receive the System.ComponentModel.Composition.ImportCardinalityMismatchException however.
I have seen this done in more abstract cases, say where one has IRepository but not where one has something more concrete nor for items spanning assemblies. Any assistance would be greatly appreciated. Barring anything helpful, I'll probably just inherit from the offending types and be done with it.
Edit: I just built the very simplified example detailed above on the off chance that I am actually doing something different in my real world project than I am here and I have vary similar results. I've renamed a few types to bring them in line with my simplified example.
The composition produced a single composition error. The root cause is provided below. Review the CompositionException.Errors property for more detailed information.
1) No exports were found that match the constraint: ContractName CompositionTestLibrary.Foo(CompositionTestLibrary2.Bar2) RequiredTypeIdentity CompositionTestLibrary.Foo(CompositionTestLibrary2.Bar2)
Resulting in: Cannot set import 'CompositionTest.Something..ctor (Parameter="foo", ContractName="CompositionTestLibrary.Foo(CompositionTestLibrary2.Bar2)")' on part 'CompositionTest.Something'. Element: CompositionTest.Something..ctor (Parameter="foo", ContractName="CompositionTestLibrary.Foo(CompositionTestLibrary2.Bar2)") --> CompositionTest.Something --> AssemblyCatalog (Assembly="CompositionTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
Resulting in: Cannot get export 'CompositionTest.Something (ContractName="CompositionTest.Something")' from part 'CompositionTest.Something'. Element: CompositionTest.Something (ContractName="CompositionTest.Something") --> CompositionTest.Something --> AssemblyCatalog (Assembly="CompositionTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
In the following line you should not use the
conventions
variable, so you should changeto
Using
conventions
here will effectively not export anything from the assembly whereFooUser
andSomething
are defined, so you won't be able to get a composed value ofSomething
. Removing it will will allowSomething
to be exported and composed.