Exports, TypeIdentity and Contract names?

Jul 19, 2010 at 3:00 PM

Can someone please explain why this overload exists or what the purpose of it is?

 GetExport<T, TMetadataView>(string contractName)

I'd like to retrive an export based on a contractName but MEF prevents me to do this becuase of the requiredTypeIdentity which is based on the type parameter T.

I'm exporting a closed generic contract which dervies from a non generic contract. I then wish to import this closed generic contract as the non generic contract. That's perfectly safe to do. While this works with relying on injection I can not get the container to give the exports through any of the overloads. Instead I have to go do this...

public static IEnumerable<Lazy<T, TMetadataView>> GetNonSharedExports<T, TMetadataView>(this CompositionContainer container, Type contractType)
    var contractName = AttributedModelServices.GetContractName(contractType);
    var importDefinition = new ContractBasedImportDefinition(contractName
        , contractName // requiredTypeIdentity is the same as the contract
        , Enumerable.Empty<KeyValuePair<string, Type>>()
        , ImportCardinality.ZeroOrMore
        , false
        , true
        , CreationPolicy.NonShared

    var collection = new Collection<Lazy<T, TMetadataView>>();

    foreach (var export in container.GetExports(importDefinition, null))
        collection.Add(new Lazy<T, TMetadataView>(() => (T)export.Value, AttributedModelServices.GetMetadataView<TMetadataView>(export.Metadata), LazyThreadSafetyMode.PublicationOnly)); 

    return collection;
And all I wanted was to get NonShared exports, exported as a closed generic type, but imported as a non generic super type. This inheritance chain would allow it.
Jul 20, 2010 at 9:29 PM

The TypeIdentity is based on how you export the target type. For example:



you can also customize it

[Export("mycontractname", ContractType=typeof(ICustomContract))]

Jul 20, 2010 at 10:36 PM

Okay, I get it now... did some testing, came up with this to illustrate/reproduce the issue. Thanks haveriss! I went looking for documentation regarding this, couldn't find anything which explained the difference between contract name and contract type. I assumed they were interchangeable which they are clearly not.

class ExportAAttribute : ExportAttribute
    public ExportAAttribute(Type contractType)
        : base(AttributedModelServices.GetContractName(contractType), typeof(A))

interface A { }

interface B { }

interface C<T> { }

class X : A { }

[ExportA(typeof(C<B>))] // would this work?
class Y : A { }

class Program
    static void Main(string[] args)
        int i;

        var typeCatalog = new AssemblyCatalog(typeof(Program).Assembly);

        var container = new CompositionContainer(typeCatalog);

        var badExport = container.GetExports<C<B>>();

        i = 0;
        foreach (var export in badExport)
            Console.WriteLine("[{0}]: {1}", i++, export.Value.GetType()); // this throws exception, can not cast export to type of C<B>

        var goodExport = container.GetExports<A>(AttributedModelServices.GetContractName(typeof(C<B>)));

        i = 0;
        foreach (var export in goodExport)
            Console.WriteLine("[{0}]: {1}", i++, export.Value.GetType()); // works as originally intended


Jul 21, 2010 at 6:19 AM

Never mind, found this http://msdn.microsoft.com/en-us/library/ee155691.aspx#types_of_imports

Apparently we call this "Dynamic imports". Though, I'm not entierly optimistic about this somewhat subtle difference between contract name and contract type. I guess I'm a bit too hung up on wanting to use types everywhere and not considering the obvious. Just use a string...

Jul 21, 2010 at 6:49 PM

So, Contract name is an ID for that object instance associated with the export. It may usually be the type name, but it doesn't need to be.

The TypeIdentity on the other hand is an extra information about that object instance. It's used to prevent cast exceptions.