Search code examples
c#mefspring.net

MEF instantiation of an export part


First, the simple question.

Is it possible to receive an event when MEF (System.ComponentModel.Composition) creates an instance of a part? When this occurs I want to reflect over the created object and wire up various attributes. In Spring.Net this is possible with the IObjectPostProcessor interface.

The background is that I trying to implement Publisher/Subscriber pattern in MEF. Basically the subscriber class does this:

class MyContoller
{
   [Command("Print")]
   public void Print() { ... }

   [Command("PrintPreview")]
   public void PrintPreview() { ... }
}

And I want to detect when MyController is instantiated and wire up any methods that have the CommandAttribute.

A publisher, such as a menu item, would do Command.Get("Print").Fire() to publish the aforementioned event.

Second Question

Maybe there is an alternative pattern in MEF that I am missing!!!

I've seen some postings about MEF, Prism and the Event Aggregate, but it appears fairly complex.

FYI

Just for reference, here's the original for Spring.Net implementation:

class CommandAttributeProcessor : IObjectPostProcessor
{
  static ILog log = LogManager.GetLogger(typeof(CommandAttributeProcessor));

  public object PostProcessAfterInitialization(object instance, string objectName)
  {
     foreach (MethodInfo methodInfo in instance.GetType().GetMethods())
     {
        foreach (CommandAttribute attr in methodInfo.GetCustomAttributes(typeof(CommandAttribute), true))
        {
           if (log.IsDebugEnabled)
              log.Debug(String.Format("Binding method '{0}.{1}' to command '{2}'.", instance.GetType().Name, methodInfo.Name, attr.CommandName));

           Command command = Command.Get(attr.CommandName);
           command.Execute += (EventHandler) Delegate.CreateDelegate(typeof(EventHandler), instance, methodInfo);
        }
     }
     return instance;
  }

  public object PostProcessBeforeInitialization(object instance, string name)
  {
     return instance;
  }

}


Solution

  • You can use InterceptingCatalog from MEF Contrib (MEF Contrib on codeplex or you can install it by nuGet) and implement IExportedValueInterceptor interface to wire up methods that have CommandAttribute:

    //using System.ComponentModel.Composition;
    //using System.ComponentModel.Composition.Hosting;
    //using MefContrib.Hosting.Interception;
    //using MefContrib.Hosting.Interception.Configuration;
    
    public class CommandAttributeProcessor : IExportedValueInterceptor
    {
        public object Intercept(object value)
        {
            foreach (MethodInfo methodInfo in value.GetType().GetMethods())
            {
                foreach (CommandAttribute attr in methodInfo.GetCustomAttributes(typeof(CommandAttribute), true))
                {
                    // do something with command attribute
                }
            }
    
            return value;
        }
    }
    

    and at creating MEF catalog, you need to add interception configuration with your interceptor (CommandAttributeProcessor) and wrap your catalog in InterceptingCatalog like this:

    InterceptionConfiguration interceptionConfiguration = new InterceptionConfiguration();
    interceptionConfiguration.AddInterceptor(new CommandAttributeProcessor());
    InterceptingCatalog interceptingCatalog = new InterceptingCatalog(assemblyCatalog, interceptionConfiguration);
    CompositionContainer container = new CompositionContainer(interceptingCatalog);