I'm use attribute-free approach to configuring MEF.
I'm read following articles:
http://msdn.microsoft.com/en-us/magazine/jj133818.aspx
http://blogs.microsoft.co.il/blogs/bnaya/archive/2013/01/12/mef-2-0-mini-series-part-4-fluent-import.aspx
Test code (console application project, .NET 4.5):
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Registration;
using System.Linq;
namespace MEF2
{
public interface IPlugin
{
void Run();
}
public interface IPluginMetadata
{
string Name { get; }
string Version { get; }
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
public class PluginMetadataAttribute : ExportAttribute, IPluginMetadata
{
public string Name { get; set; }
public string Version { get; set; }
public PluginMetadataAttribute(string name, string version)
: base(typeof(IPlugin))
{
Name = name;
Version = version;
}
}
[PluginMetadata("Plugin1", "1.0.0.0")]
public class Plugin1 : IPlugin
{
public void Run()
{
Console.WriteLine("Plugin1 runed");
}
}
[PluginMetadata("Plugin2", "2.0.0.0")]
public class Plugin2 : IPlugin
{
public void Run()
{
Console.WriteLine("Plugin2 runed");
}
}
class Program
{
CompositionContainer container;
IEnumerable<Lazy<IPlugin, IPluginMetadata>> plugins = Enumerable.Empty<Lazy<IPlugin, IPluginMetadata>>();
static void Main(string[] args)
{
var program = new Program();
foreach (var plugn in program.plugins) {
Console.WriteLine("{0}, {1}", plugn.Metadata.Name, plugn.Metadata.Version);
plugn.Value.Run();
}
}
Program()
{
var builder = new RegistrationBuilder();
builder
.ForTypesDerivedFrom<IPlugin>()
.Export<IPlugin>();
builder
.ForType<Program>()
.Export()
.ImportProperties<IPlugin>(
propertyFilter => true,
(propertyInfo, importBuilder) => {
importBuilder.AsMany();
}
);
var catalog = new AggregateCatalog(
new AssemblyCatalog(typeof(Program).Assembly, builder)
);
container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
}
Exports works fine.
But when I try import many it doesn't work.
Please help me solve this problem.
This is not an attribute free (imperative) approach since the export is attributed (declarative). Your custom metadata attribute derives from ExportAttribute
.
For this code to work you need to do the following:
AssemblyCatalog
. Without this the registration builder cannot be used.Lazy<IPlugin, IPluginMetadata>
since this is what is being exported.ComposeParts
with GetExports
.The updated constructor code is:
var builder = new RegistrationBuilder();
builder
.ForType<Program>()
.Export()
.ImportProperties<Lazy<IPlugin, IPluginMetadata>>(
propertyFilter => true,
(propertyInfo, importBuilder) =>
{
importBuilder.AsMany();
}
);
var catalog = new AggregateCatalog(
new AssemblyCatalog(typeof(Program).Assembly, builder)
);
container = new CompositionContainer(catalog);
//container.ComposeParts(this);
plugins = container.GetExports<IPlugin, IPluginMetadata>();
I'm not sure how to make this work with ComposeParts
yet. I will have a look at it. Also the custom metadata does not have to derive from ExportAttribute
. It can derive from System.Attribute
. This will let you have a imperative export as well.