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;
}
}
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);