Introduction
I am not going cover detail about
MEF or not going describe functionality of MEF. One can find good material over
the net for MEF, so I am not going to post redundant information. What I feel
is MEF is an extensibility framework provided by Microsoft. Many other
extensibility framework exists but MEf is easy to initiate. Today I am going
develop a sample application which demonstrate how to import/export components.
Kindly note that this is just a small effort so that beginner can start working
with MEF.
Using the code
In this article we are going to
cover following topic:
1)
Develop Component behavior: This will be an
interface which functionality exported by components and consume by our host
application.
2)
Host Application: Application that seeks for
component to be compose.
3)
ExportLib1, ExportLib2: These are components –
actual implementation of our component behavior
4)
Main Application: This uses all these.
So lets start with 1st
part of our application.
1) Create
Contract library which contains IComponent
interface as shown below. Through this interface our component will
communicate.
namespace Contracts
{
public interface
IComponent
{
string Description { get; }
string ManipulateOperation(params double[]
args);
}
}
2) Create library ImportingLib, this contains
a class that actually host and calls the components. Here one has to add System.ComponentModel.Composition
assembly. Code for Importer class
shown as below.
using System;
using
System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
using
System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Contracts;
namespace ImportingLib
{
public class
Importer
{
[ImportMany(typeof(IComponent))]
private IEnumerable<Lazy<IComponent>>
operations;
public void
DoImport()
{
//An
aggregate catalog that combines multiple catalogs
var
catalog = new AggregateCatalog();
//Add all
the parts found in all assemblies in
//the
same directory as the executing program
catalog.Catalogs.Add(
new
DirectoryCatalog(
Path.GetDirectoryName(
Assembly.GetExecutingAssembly().Location
)
)
);
//Create
the CompositionContainer with the parts in the catalog.
CompositionContainer
container = new CompositionContainer(catalog);
//Fill
the imports of this object
container.ComposeParts(this);
}
public int
AvailableNumberOfOperation
{
get
{ return operations != null
? operations.Count() : 0; }
}
public List<string> CallAllComponents(params
double[] args)
{
var
result = new List<string>();
foreach
(Lazy<IComponent>
com in operations)
{
Console.WriteLine(com..Description);
result.Add(com.Value.ManipulateOperation(args));
}
return
result;
}
}
}
This host imports components implementing IComponent and lists them into private variable operations. The DoImport method initializes list. Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
gives a path in which our executing assembly resides.MEF will automatically start searching all assemblies in the directory where the calling program resides.
This is done by creating DirectoryCatelog on that folder and then adding it to
the main AggregateCatelog. Property AvailableNumberOfOperation
returns the number of found operations and CallAllComponents
method calls all the exporting components and returns the result.
3)
As
our host is ready for import functionality now major task is to develop
component that exports desired functionality. For demonstration I developed two
class library which contains classes that implement IComponent interface. Their code section shown as below.
using System;
using
System.ComponentModel.Composition;
using
System.Collections.Generic;
using System.Linq;
using System.Text;
using Contracts;
namespace ExportSumLib
{
[Export(typeof(IComponent))]
public class
SumOfNumberComponent : IComponent
{
public string
Description
{
get
{ return "Summation
of components"; }
}
public string
ManipulateOperation(params double[] args)
{
string
result = "";
double
count = 0;
bool
first = true;
foreach
(double d in
args)
{
if
(first)
{
count = d;
first = false;
}
else
count += d;
result += d.ToString() + " + ";
}
return
result.Trim('+', '
') + " = " +
count.ToString();
}
}
}
Here you can see the code of SumOfNumberComponent
class. This class built in ExportingLib1.dll file.
You’ve add reference for Contracts.dll and System.ComponentModel.Composition.
Same way develop another library called ExportingLib2.dll which
contains SubstractOfNumberComponent
class. Code of that class shown as below.
using System;
using
System.Collections.Generic;
using System.Linq;
using System.Text;
using
System.ComponentModel.Composition;
using Contracts;
namespace ExportSubstractLib
{
[Export(typeof(IComponent))]
public class
SubstractOfNumberComponent : IComponent
{
public string
Description
{
get
{ return "Subtraction
of components"; }
}
public string
ManipulateOperation(params double[] args)
{
string
result = "";
double
count = 0;
bool
first = true;
foreach
(double d in
args)
{
if
(first)
{
count = d;
first = false;
}
else
count -= d;
result += d.ToString() + " - ";
}
return
result.Trim('-', '
') + " = " +
count.ToString();
}
}
}
Now let’s move to the final step of this exercise.
Create an application that uses all these stuffs.
4) Develop a console application called MEFApplication. Add reference of
ImportingLib.dll. now write down code section shown below.
using System;
using
System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MEFApplication
{
class Program
{
static void
Main(string[] args)
{
var
t = new ImportingLib.Importer();
t.DoImport();
Console.WriteLine("{0} component(s) are imported successfully.",
t.AvailableNumberOfOperation);
var
result = t.CallAllComponents(125, 5, 10, 27, 45, 19, 10);
foreach
(string s in
result)
{
Console.WriteLine(s);
}
Console.Read();
}
}
}
Before executing application do one thing go to the Project
Properties->Build option and set building path of each application to bin\Debug folder of MEFApplication project. Now build whole
project and see the magic.
You can when you execute MEFApplication
project it will show 2 component(s) are
imported successfully. message and rest messages. If you remove any of
library from ExportingLib1.dll or ExportingLib2.dll message will change to 1 component(s) are imported successfully.