Posterous theme by Cory Watilo

Creating a FakeExportProvider to help with testing MEF code

If you don’t know what the purpose of an export provider in MEF is, then I recommend you to read Using ExportProvider to customize container behavior Part I by Glenn Block for an in-depth description. The short version is that the export providers it so serve exports to the composition container. In this post I am going to show how to create an export provider which serves instances of objects by allowing you to directly register them for a specific contract. The export provider can then be passed to the composition container and provide known exports.


The first thing we need to do it to create the skeleton for the export provider.

/// <summary>/// Defines an <see cref="ExportProvider"/> which allows you to add object instances as/// exports for a specific contract. The provider is useful when you need to test MEF/// code and need control over the available exports./// </summary>public class FakeExportProvider : ExportProvider{    /// <summary>    /// Gets a list of <see cref="Export"/> objects which matches the provided <see cref="ImportDefinition"/>.    /// </summary>    /// <param name="definition">The <see cref="ImportDefinition"/> to get the exports for.</param>    /// <returns>An <see cref="IEnumerable{T}"/> object.</returns>    protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition)    {        throw new NotImplementedException();    }}

Nothing out of the ordinary here. The class inherits the ExportProvider base class and provides a (stubb) implementation of the abstract method GetExportsCore. This method is there the main work of the export provider will happen. It’s responsible for inspecting the provided ImportDefinition and return any exports which have been registered for the same contract that the definition contains. We’ll get back to the method once we’ve gotten some other plumbing out of the way.


/// <summary>/// Defines an <see cref="ExportProvider"/> which allows you to add object instances as/// exports for a specific contract. The provider is useful when you need to test MEF/// code and need control over the available exports./// </summary>public class FakeExportProvider : ExportProvider{    /// <summary>    /// Initializes a new instance of the <see cref="FakeExportProvider"/> class.    /// </summary>    public FakeExportProvider()        : this(new Dictionary<ExportDefinition, Collection<Export>>())    {    }    /// <summary>    /// Initializes a new instance of the <see cref="FakeExportProvider"/> class, using    /// the provided exports.    /// </summary>    /// <param name="exports">A <see cref="Dictionary{TKey, TValue}"/> object, containing the initial exports.</param>    public FakeExportProvider(Dictionary<ExportDefinition, Collection<Export>> exports)    {        this.Exports = exports;    }    /// <summary>    /// Gets or sets the list of available exports.    /// </summary>    /// <value>A <see cref="Dictionary{TKey, TValue}"/> object.</value>    protected Dictionary<ExportDefinition, Collection<Export>> Exports { get; set; }     /// <summary>    /// Gets a list of <see cref="Export"/> objects which matches the provided <see cref="ImportDefinition"/>.    /// </summary>    /// <param name="definition">The <see cref="ImportDefinition"/> to get the exports for.</param>    /// <returns>An <see cref="IEnumerable{T}"/> object.</returns>    protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition)    {        throw new NotImplementedException();    }}

It might look like a lot of code, but remove the comments and you’ll notice that what have been added are two constructors and a property. The property is used to store the object instances for a contract when they are registered. Actually it’s storing the Export object which contains the information needed to return the object instance once it’s asked to, which is when the GetExportedObject method on the export object is called. This can either be an explicit call made by yourself or happen internally in MEF when the composition is taking place, such as when an import is of a specific type and not the lazy export type.


So we now have a way to store the the exports, but we also need a way to add them to the export provider in the first place. Sure there is a constructor overload which enables us to pass in a dictionary of contracts and exports but we need a more natural way of adding instances to the provider.


/// <summary>/// Adds an export with a specified contract name./// </summary>/// <param name="contractName">A <see cref="String"/> containing the name of the contract.</param>/// <param name="export">The object to add as an export.</param>public void AddExport(string contractName, object export){    var found =        from e in this.Exports        where string.Compare(e.Key.ContractName, contractName, StringComparison.OrdinalIgnoreCase) == 0        select e;    if (found.Count() == 0)    {        ExportDefinition definition =            new ExportDefinition(contractName, new Dictionary<string, object>());        this.Exports.Add(definition, new Collection<Export>());    }    Export wrapper =        new Export(contractName, () => export);    found.First().Value.Add(wrapper);}/// <summary>/// Adds a list of exports with a specified contract name./// </summary>/// <param name="contractName">A <see cref="String"/> containing the name of the contract.</param>/// <param name="exports">A list of objects to add as exports.</param>public void AddExports(string contractName, IEnumerable exports){    foreach (var export in exports)    {        this.AddExport(contractName, export);    }}

The AddExport and AddExports method enables us to register a single or a collection of instances for a specific contract. These methods can be called multiple times for the same contract since the internal store is checked if there is an ExportDefinition stored for the provided contract name or not. If there is then it will be used to add the provided object instance(s). The AddExport method takes care of all the necessary steps to convert the contract name into an ExportDefinition and the instances to Export objects.


The time has not come to return to the GetExportsCore method and implement the logic to return the exports (if there are any) which matches a requested contract.


/// <summary>/// Gets a list of <see cref="Export"/> objects which matches the provided <see cref="ImportDefinition"/>./// </summary>/// <param name="definition">The <see cref="ImportDefinition"/> to get the exports for.</param>/// <returns>An <see cref="IEnumerable{T}"/> object.</returns>protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition){    var contractDefinition =        definition as ContractBasedImportDefinition;    if (contractDefinition != null)    {        string contractName =            contractDefinition.ContractName;        if (!string.IsNullOrEmpty(contractName))        {            var exports =                from e in this.Exports                where string.Compare(e.Key.ContractName, contractName, StringComparison.OrdinalIgnoreCase) == 0                select e.Value;            if (exports.Count() > 0)            {                return exports.First();            }        }    }    return Enumerable.Empty<Export>();}

The method casts the provided ImportDefinition to a ContractBasedImportDefinition instance. It does this to be able to easily extract the requested contract name. The ContractBasedImportDefinition class is part of MEF and can be located in the the System.ComponentModel.Composition.Primitives namespace. Once the name of the contract has been extracted it checks if there are any exports registered for it and if there are they are returned. If no exports could be found then an empty list is returned.


Using the export provider is as easy as creating an instance, registering the instances for the contracts of your choice and pass the entire provider to the composition container. Pretend you had a class called DefaultMessageService that you wanted to be returned for the contract Foo. The below nUnit tests shows how you could use the FakeExportProvider to accomplish this.


[Test]public void ContainerShouldReturnInstancesRegisteredForTheContract(){    FakeExportProvider provider =        new FakeExportProvider();    provider.AddExport("Foo", new DefaultMessageService());        var container =        new CompositionContainer(provider);    ContractBasedImportDefinition definition =        new ContractBasedImportDefinition(            "Foo",            ImportCardinality.ZeroOrOne,            true,            false);    var results =        container.GetExports(definition);    Assert.IsTrue(results.Count() == 1);    Assert.IsTrue(results.First().GetExportedObject().GetType() == typeof(DefaultMessageService));}

Notice that no catalog has been provided to the CompositionContainer, the only source of exports are the instances we have registered in the FakeExportProvider that was passed into the constructor of the container. If the test was modified so that instances were registered for a Bar contract as well


FakeExportProvider provider =    new FakeExportProvider();provider.AddExport("Foo", new DefaultMessageService());provider.AddExport("Bar", new BarMessageService());

then the test will still pass since only the instances which has been registered for the requested contract will be returned. That’s all there is to it! You can download the full source code at my codeplex page and it’s very likely that an extended version of this export provider will end up in a future release of the MEF Contrib project.


Media_httpdotnetshout_mjilw