Custom Object Factories in MEF

May 6, 2012 at 12:48 AM

I originally asked this question at stackoverflow, however got no answer.  

Consider the following model that works well with MEF.

 

public interface IProducer
{
    void Produce();
}

[Export(typeof(IProducer))]
public class Producer : IProducer
{
    public Producer()
    {
        // perform some initialization
    }

    public void Produce()
    {
        // produce something
    }
}

public class Consumer
{
    [Import]
    public IProducer Producer
    {
        get;
        set;
    }

    [ImportingConstructor]
    public Consumer(IProducer producer)
    {
        Producer = producer;
    }

    public void DoSomething()
    {
        // do something
        Producer.Produce();
    }
}

 

 

However, the creation of Producer has become complex enough that it can no longer be done within the constructor and the default behavior no longer suffices. I'd like to introduce a factory and register it using a custom FactoryAttribute on the producer itself. This is what I have in mind:

 

[Export(typeof(IProducer))]
[Factory(typeof(ProducerFactory))]
public class Producer : IProducer
{
    public Producer()
    {
        // perform some initialization
    }

    public void Produce()
    {
        // produce something
    }
}

[Export]
public class ProducerFactory
{
    public Producer Create()
    {
        // Perform complex initialization
        return new Producer();
    }
}

public class FactoryAttribute : Attribute
{
    public Type ObjectType
    {
        get;
        private set;
    }

    public FactoryAttribute(Type objectType)
    {
        ObjectType = objectType;
    }
}

 

If I had to write the "new" code myself, it may very well look as follows. It would use the factory attribute, if it exists, to create a part, or default to the MEF to create it.

 

public object Create(Type partType, CompositionContainer container)
{
    var attribute = (FactoryAttribute)partType.GetCustomAttributes(typeof (FactoryAttribute), true).FirstOrDefault();
    if (attribute == null)
    {
        var result = container.GetExports(partType, null, null).First();
        return result.Value;
    }
    else
    {
        var factoryExport = container.GetExports(attribute.ObjectType, null, null).First();
        var factory = factoryExport.Value;
        var method = factory.GetType().GetMethod("Create");
        var result = method.Invoke(factory, new object[0]);
        container.ComposeParts(result);
        return result;
    }
}

 

It may even an better approach if I could implement some convention such that for a given import (say IProducer) which has no export, MEF would check if the container has any export if IProducerFactory, construct it and then call "Create" to produce an instance of IProducer.  In that case there is no need for an attribute.

I started to write my own custom export factory, but I'm a tad clueless how to proceed:

 

public class FactoryExportProvider : ExportProvider
{
    protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition,
                                                          AtomicComposition atomicComposition)
    {
        // What to do here? 
    }
}

There are several examples that require that the application knows exactly how to create the factories when the application starts.  In my case, I'd like to avoid that and discovery the factories at runtime to keep my application loosely coupled.  This will improve reuse and reduce maintenance in the various applications that share the parts.

Thanks,

Werner

May 7, 2012 at 12:32 AM
Edited May 7, 2012 at 5:20 AM

The question is really how to get MEF to use a common pattern, aka the abstract factory pattern.  So to simplify the question, I simply want MEF to use an export of IProducerFactory to create instances of IProducer.  Assume I have an assembly of call "objectmodel.dll" which cannot be modified.

public interface IProducerFactory
{
    IProducer Create();
}

public interface IProducer
{
}

[Export]
public class Consumer
{
   [ImportingConstructor]
   public Consumer(IProducer producer)
   {
   }
}

Now someone implements an assembly "Concrete.dll"

internal sealed class ConcreteProducer : IProducer
{
}

[Export(typeof(IProducerFactory))]
public sealed class ConcreteProducerFactory : IProducerFactory
{
     public IProducer Create()
     {
         return new ConcreteProducer();
     }
}

 How do I implement an ExportProvider so that MEF can create an instance of ConcreteProvider using the ConcreteProducerFactory, which was unknown when "objectmodel.dll" was compiled?  If I can implement this using conventions (and no attributes), so much better.

May 7, 2012 at 2:50 AM

Hi,

Your posts are really long and complex and that may be the reason you had trouble getting help on stack overflow.  Anyway, now that you have simplified things a bit with your follow up post, I think I have a suggestion for you.  Don't worry about implementing your own export provider, just export the Create method on your factory.

internal sealed class ConcreteProducer : IProducer
{
}

public sealed class ConcreteProducerFactory : IProducerFactory
{
     [Export(typeof(Func<IProducerFactory>))]
     public IProducer Create()
     {
         return new ConcreteProducer();
     }
}

 

Then you can import the method wherever you like.  This is perfectly legal and I've used it myself.  Maybe there is a reason why this wont work in your scenario, if so, please explain why.

Thanks,

Jim

 

May 7, 2012 at 5:19 AM

Thanks Jim,

A couple of questions:

  • How owns the lifetime of the object that is created by the function? From what I understand the consumer does.  
  • The solution requires changes to the consumer. Is there a solution where I don't have to change the consumer?

Werner

May 8, 2012 at 12:07 AM

Hi Werner,

Apart from the custom ExportProvider solution (which can be very complex) I don't think there is an out-of-the-box way to achieve this without code changes to the client.

Cheers,
Nick

May 8, 2012 at 12:38 AM
MEF Contrib has an interception extensibility point (InterceptingCatalog) It is primarily there for integrating with something like Castle Dynamic Proxy. It might work for your needs.

Sent from my Windows Phone

From: Bloudraak
Sent: 5/5/2012 5:48 PM
To: Glenn Block
Subject: Custom Object Factories in MEF [MEF:354659]

From: Bloudraak

I originally asked this question at stackoverflow, however got no answer.

Consider the following model that works well with MEF.

public interface IProducer
{
    void Produce();
}

[Export(typeof(IProducer))]
public class Producer : IProducer
{
    public Producer()
    {
        // perform some initialization
    }

    public void Produce()
    {
        // produce something
    }
}

public class Consumer
{
    [Import]
    public IProducer Producer
    {
        get;
        set;
    }

    [ImportingConstructor]
    public Consumer(IProducer producer)
    {
        Producer = producer;
    }

    public void DoSomething()
    {
        // do something
        Producer.Produce();
    }
}

However, the creation of Producer has become complex enough that it can no longer be done within the constructor and the default behavior no longer suffices. I'd like to introduce a factory and register it using a custom FactoryAttribute on the producer itself. This is what I have in mind:

[Export(typeof(IProducer))]
[Factory(typeof(ProducerFactory))]
public class Producer : IProducer
{
    public Producer()
    {
        // perform some initialization
    }

    public void Produce()
    {
        // produce something
    }
}

[Export]
public class ProducerFactory
{
    public Producer Create()
    {
        // Perform complex initialization
        return new Producer();
    }
}

public class FactoryAttribute : Attribute
{
    public Type ObjectType
    {
        get;
        private set;
    }

    public FactoryAttribute(Type objectType)
    {
        ObjectType = objectType;
    }
}

If I had to write the "new" code myself, it may very well look as follows. It would use the factory attribute, if it exists, to create a part, or default to the MEF to create it.

public object Create(Type partType, CompositionContainer container)
{
    var attribute = (FactoryAttribute)partType.GetCustomAttributes(typeof (FactoryAttribute), true).FirstOrDefault();
    if (attribute == null)
    {
        var result = container.GetExports(partType, null, null).First();
        return result.Value;
    }
    else
    {
        var factoryExport = container.GetExports(attribute.ObjectType, null, null).First();
        var factory = factoryExport.Value;
        var method = factory.GetType().GetMethod("Create");
        var result = method.Invoke(factory, new object[0]);
        container.ComposeParts(result);
        return result;
    }
}

It may even an better approach if I could implement some convention such that for a given import (say IProducer) which has no export, MEF would check if the container has any export if IProducerFactory, construct it and then call "Create" to produce an instance of IProducer. In that case there is no need for an attribute.

I started to write my own custom export factory, but I'm a tad clueless how to proceed:

public class FactoryExportProvider : ExportProvider
{
    protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition,
                                                          AtomicComposition atomicComposition)
    {
        // What to do here? 
    }
}

There are several examples that require that the application knows exactly how to create the factories when the application starts. In my case, I'd like to avoid that and discovery the factories at runtime to keep my application loosely coupled. This will improve reuse and reduce maintenance in the various applications that share the parts.

Thanks,

Werner

May 8, 2012 at 3:56 PM

Werner, cancel that :) I just realized that property exports, combined with CreationPolicy.NonShared, will do what you need.

First, export your IProducerFactory as a regular part (so that it can be imported by the constructor below).

Then, the following part will create a new instance for every consumer:

[PartCreationPolicy(CreationPolicy.NonShared)]
public class ProducerFactoryAdapter
{
   IProducerFactory _factory;

   [ImportingConstructor]
   public ProducerFactoryAdapter(IProducerFactory factory)
   {
      _factory = factory;
   }

   [Export]
   public IProducer Producer
   {
      get { return _factory.Create(); }
   }
}

Hope this helps,

Nick

May 13, 2012 at 5:07 AM

Thanks mate.  It gets me closer to where I want to be.

I hope that in the near future, I'd be able to register a factory method through attributes or convention/registration, so that one can use the abstract factory pattern without adding unnecessary code.  With Unity it was a trivial matter. 

Werner

 

May 19, 2012 at 10:22 PM

I decided not to use MEF for numerous reasons, but especially because it is too intrusive and rather fragile.  Instead, I'm using a bunch of Unity extensions that provide the same feature set MEF provides without having to change existing classes, properties or write additional classes to wrap classes so they can be used with MEF.  

Thanks for helping me. It was really appreciated.

Werner