Creating a functional programming model for MEF

Disclaimer: This is a prototype, not production ready code. It is more illustrative of what you can do with MEF, and how things work under the covers.

The other day I was working one of our internal partners who is looking to integrate MEF into their framework stack. One of the interesting ideas that came out of that discussion was around a need they had to add POCO instances directly to a catalog (in addition to using our standard attributed part).

Now MEF supports the ability to add existing instances to the container through the AddExportedObject method, but that did not suit their need.  Instead they wanted these instances to actually be parts. Primarily because the types they were instantiating were not attributed MEF parts, and they did not want to incur the reflection cost.

I started thinking down the path of creating a programming model where the part definitions are actually wrapping instances. What I mean by programming model, is teach MEF a new way to represent parts, exports and imports. In MEF parlance, a programming model is almost like a type system, though far less complex. For more on programming models themselves, i'd refer you to Daniel's nice post on programming models themselves here.

Out of the box, MEF ships with an attributed programming model, however others can be created by implementing on top of a set of abstractions we call the primitives. What’s really nice about MEF is that all of the models can safely interact with one another in the container.

Building an instance model however is problematic in that parts in MEF should be lazily instantiated. I realized (probably due much influence of my Autofac workmate Nick Blumhardt) that the right way to go was not build an instance model, but rather build a model for representing functions as parts. And so, the FuncCatalog was born.

FuncCatalog

The FuncCatalog allows you to add functions directly to itself, and to associate those functions with a type to be exported. Each function gets a single parameter which is an ExportProvider. This allows you to build up an instance within your function, that can have constructor parameters pulled from the EP, similar to the registration style in Autofac.

Below is a sample acceptance test that illustrates how this works. In the example I am adding a function to funcCatalog which creates an OrderService. In the OrderService’s constructor, I am passing in an ILogger that I retrieved from the Export Provider.

[TestMethod]
public void FuncPartCanImportFromTheContainer()
{
    var catalog = newAggregateCatalog();
    catalog.Catalogs.Add(newTypeCatalog(typeof (AttributedLogger)));

    var funcCatalog = new FuncCatalog();
    funcCatalog.AddPart<OrderService>(
        ep => new OrderService(ep.GetExportedObject<ILogger>()));
    catalog.Catalogs.Add(funcCatalog);
   
    var container = new CompositionContainer(catalog);
    var batch = new CompositionBatch();
    batch.AddExportedObject<ExportProvider>(container);
    container.Compose(batch);
   
    var service = container.GetExportedObject<OrderService>();
    Assert.IsNotNull(service.Logger);
}

In terms of what the code is doing, I am first creating an aggregate catalog (a catalog of catalogs). Then I am adding to it a type catalog which contains an AttributedLogger (that is a logger with an ExportAttribute on it). Next I am creating a FuncCatalog which I am adding the new func part to. Notice how the lambda passes ep.

        ep => new OrderService(ep.GetExportedObject<ILogger>())

Next I am creating the container, and then adding itself to itself (via the batch) with ExportProvider as the contract. This is to allow the FuncPart to import the ExportProvider so it can use it to resolve other dependencies.

Finally I am asking the container to grab me an OrderService, which I am then checking to see if there is a logger present. Remember the logger actually was an attributed part that was added through MEF’s normal catalogs. So right here we have an illustration of multiple models living side by side.

How is it done?

As I mentioned above, I created a custom programming model. Depending on the model, this can be a lot or a little work. Andreas Haakanson has a project on CodePlex that simplifies creating such programming models, but that is for another overdue post :-)  Below I’ll detail the approach I took in order to give you a view into how programming models work.

Programming model players

Below are the main abstractions you  need to implement for building your own programming model which live in the System.ComponentModel.Composition.Primitives namespace.

image

Here’s  a quick summary of the responsibilities for each of these classes.

  • ComposablePartDefinition – Schema for a part, analogous to a type in many respects. As a matter of fact in our default Attributed Programming Model (APM), the Composable Part Definition wraps a type. Aside from being schema, the other main responsibility for CPD is to create a composable part.
  • ImportDefinition – An import definition is carries information about a contract that a part needs, it’s import. In the APM, import definitions are created for properties decorated with the ImportAttribute, or constructor parameters if the constructor has an ImportingConstructorAttribute.
  • ExportDefinition - An export definition carries information about a contract that a part offers up, it’s export. In the APM, an export definition is created for each member that is decorated with the ExportAttribute. This includes the class itself, or methods / properties.
  • ComposablePartCatalog – The catalog aggregates part definitions, which the container will query during composition in order to find available exports. The catalog does not create any parts, it only returns requested definitions. In our APM, the catalogs read assemblies and types in order to create these definitions.
  • ComposablePart – The part itself. If the CPD is the schema, then the part is the instance. This does not mean it is the actual instance that is being returned from the container. No. The part contains an instance which will get created only at the time when the first exported object actually pulled from it. There’s a difference between an export and an exported object, but I’ll resist to go deeper and try to explain it for now.

In my new model I implemented FuncCatalog, FuncExportDefinition, FuncPart, and FuncPartDefinition. I did not need a new ImportDefinition as the standard one was fine. Also my parts only support a single import, namely an ExportProvider.

image

FuncExportDefinition

Ok, so first stop is to build a FuncExportDefinition. In my case I need a definition that carries a custom function. So here it is.

 public class FuncExportDefinition : ExportDefinition
{
    public FuncExportDefinition(string contractName, 
        Func<ExportProvider,object> factory) :
        base(contractName, null)
    {
        Factory = factory;
    }

    public Func<ExportProvider, object> Factory { get; private set; }
}

 

 

Pretty simple, I basically allow associating a contract and an additional func which accepts an ExportProvider as a parameter and returns object. Now notice the second parameter I pass to the base class is null. That represents metadata. I decided for simplicity to not allow support of metadata, though that could easily be added back.

FuncPartDefinition

Now that I can define Funcs as exports, I need a PartDefinition which can carry that information, and manufacture a part. This one was a bit tricky, below are the important pieces.

 public abstract class FuncPartDefinition : ComposablePartDefinition
{}

public class FuncPartDefinition<TContract> : FuncPartDefinition 
{
    private static ContractBasedImportDefinition 
        _exportProviderImportDefinition;


    static FuncPartDefinition()
    {
        string importContractName = CompositionServices.GetContractName
            (typeof(ExportProvider));
        _exportProviderImportDefinition = new 
            ContractBasedImportDefinition(
            importContractName, null,
            ImportCardinality.ZeroOrOne, false, false,
            CreationPolicy.Any);
    }

    public FuncPartDefinition(Func<ExportProvider, object> factory)
    {
        _exportDefinitions.Add(new FuncExportDefinition
            (CompositionServices.GetContractName(typeof(TContract)),
            factory));
        _importDefinitions.Add(_exportProviderImportDefinition);
    }

    public FuncPartDefinition()
        : this((ep)=>(TContract) Activator.
            CreateInstance(typeof (TContract)))
    {
    }

    public override ComposablePart CreatePart()
    {
        return new FuncPart<TContract>(this);
    }
}

As I mentioned earlier, my func parts need to access an ExportProvider so they can retrieve things from the container. The question was how to do this. I could make the ExportProvider a parameter on the constructor of the part. Then however, I would have to pass it in to the catalog, which would pass it in to the part. This is further problematic as catalogs can actually be passed to several containers. So I decided the easiest way to do it, was to have the part actually import the ExportProvider through MEF’s composition, that is similar to the way I would import on an attributed part through a constructor param.

In order to do this, all I need is to add a single ImportDefinition to every part instance. The static constructor of FuncPartDefinition does the work of creating this definition. The definition never changes, and it is cheaper to create it once, which is  why I made it static.

The instance constructor accepts the  func. It then goes and creates a FuncExportDefinition which it adds to the collection of export definitions. Next it adds the export provider import. I added an additional overload just as a convenience which simply creates the type. Probably just being gratuitous ;-)

Finally the CreatePart method goes and creates a FuncPart passing in the definition (the part’s schema) which leads us to our next suspect.

FuncPart

This guys job is to pass back export definitions of our func, to the container on request. Those definitions can later be activated to invoke the actual func.

 public class FuncPart<TContract> : ComposablePart 
{
    private FuncPartDefinition<TContract> _definition;
    private ExportProvider _provider;

    public FuncPart(FuncPartDefinition<TContract> definition)
    {
        _definition = definition;
    }

    public override object GetExportedObject(ExportDefinition definition)
    {
        var funcExportDefinition = definition as FuncExportDefinition;
        return funcExportDefinition.Factory(_provider);
    }

    public override void SetImport(ImportDefinition definition, 
        IEnumerable<Export> exports)
    {
        _provider = exports.First().GetExportedObject() as ExportProvider;
    }

    public override IEnumerable<ExportDefinition> ExportDefinitions
    {
        get { return _definition.ExportDefinitions; }
    }

    public override IEnumerable<ImportDefinition> ImportDefinitions
    {
        get { return _definition.ImportDefinitions; }
    }
}

When the part gets constructed, it stores a copy of it’s definition. The ExportDefinitions and ImportDefinitions delegate directly to the part definitions members. In the SetImport method I have got a bit of a hack going on. This method will get called by the composition engine to set the imports. In the method, I am grabbing the first export passed in and then assuming it is the export provider. This is actually an OK assumption in my case, since there is only a single import that I allow in my programming model. However, I really should be verifying that it is passing me the right definition.

And just when you thought I was done with hacks, another one :-) GetExportedObject takes the definition passed to it and assumes it is a FuncExportDefinition. Again, this is an ok assumption in the cases where I am using it, but it should be more bullet proof and not make those assumptions. Anyway, once it has the definition  unwrapped, it grabs the factory and invokes it passing in the provider.

FuncCatalog

Last stop on our journey is the func catalog.  He’s actually pretty straightforward. I added a few convenience methods on him so that you don’t have to create parts a head of time.

 public class FuncCatalog : ComposablePartCatalog,     
    INotifyComposablePartCatalogChanged
{
    private List<ComposablePartDefinition> _parts = new List<ComposablePartDefinition>();

    public FuncPartDefinition AddPart<T>(
        Func<ExportProvider, object> factory)
    {
        var addedParts = new List<FuncPartDefinition>();
        var definition = new FuncPartDefinition<T>(factory);
        _parts.Add(definition);
        
        addedParts.Add(definition);
        OnChanged(addedParts);
        return definition;

    }

    public void AddParts(params FuncPartDefinition[] parts)
    {
        _parts.AddRange(parts);
        OnChanged(parts);
    }

    public void RemoveParts(params FuncPartDefinition[] parts)
    {
        _parts.RemoveAll(c => parts.Contains(c));
        OnChanged(parts);
    }
    
    public override IQueryable<ComposablePartDefinition> Parts
    {
        get
        {
            return _parts.AsQueryable();
        }
    }

    private void OnChanged(IEnumerable<FuncPartDefinition> parts)
    {
        var args = new ComposablePartCatalogChangedEventArgs(
            parts.Cast<ComposablePartDefinition>());
        Changed(this, args);
    }

    public event EventHandler<ComposablePartCatalogChangedEventArgs> 
        Changed = delegate { };
}

First thing is the catalog implements INotifyComposablePartCatalogChanged. This is to allow the catalog to notify the container when parts are added or removed from it. Implementing a catalog only requires to to override one property, namely the Parts property, which as you can see returns a queryable of Parts. The rest of the methods are concerned with the mutability of the container. Now catalogs do not have to be mutable, as you can handle loading up all the part defs in the constructor. However, for usability sake, I wanted mine to  be mutable. This means that I need to have methods for adding, removing, and I need to support notification.  The code should be pretty easy to follow.

So what have we learned?

Well first thing we learned that MEF supports alternative programming models other than the attributed model we ship in the box. Next, we learned about the key concepts involved in authoring your own programming model. In this case the model was very, very simple, which is why I was able to cover it in a single post. I am not recommending every one go out an author their own model. Lastly we saw learned that parts can be functions :-)

If your interested in other applications of programming models in MEF, I recommend you check out Nick Blumhart’s posts on Ruby. Also don’t forget to check out Andreas’s provider based programming model on MefContrib.

https://cid-f8b2fd72406fb218.skydrive.live.com/self.aspx/blog/FuncCatalogExtensions.zip