Basics of Managed Extensibility Framework


Introduction:

The objective of this article is to present a new feature of .NET 4.0 which is known as Managed Extensibility Framework.

Managed Extensibility Framework provides a way to create applications that can be extended dynamically and those extensions can be reused among multiple applications.

MEF allows application developers to discover and consume extensions with no configuration required. It also lets extension developers easily encapsulate code and avoid fragile hard dependencies.

Some details about Managed Extensibility Framework:

  • When an application needs to consume external components, MEF provides a way to discover them implicitly.
     
  • There is a MEF component known as ComposablePart. It has two parts
     
    1. It defines all the capabilities the composable part offers

    2. Import : It defines the part's dependencies to other parts
       
  • These ComposableParts are discoverable at runtime & these are basically the extensions.
     
  • An extensible application using MEF declares import that can be filled by extension components & may also declare exports to expose services to extensions.
     
  • Each extension component declares an Export & may also declare Imports.
     
  • The core of the MEF composition model is the composition container which contains all the ComposableParts available & performs composition(connecting imports to exports).
     
  • The most common composition container is CompositionContainer.
I will explain the above mentioned points by creating a sample application.

Step 1:

Create a new Console application and give it a name MyMEF.

Figure1.gif

Figure 1:

Step 2:

Add a new class to the project.

Replica watches

Figure 2:

Step 3:

Give it a name MEFMain.cs.

Figure3.gif

Figure 3:

This is actually our host application that uses MEF to extend itself.

Step 4:

Now add a reference of System.ComponentModel.Composition to the project.

Figure4.gif

Figure 4:

This namespace provides classes that constitute the core of the Managed Extensibility Framework.

Step 5:

Again add a new class to the project.

Replica watches

Figure 5:

Step 6:

Give it a name Extension1.cs.

fake watch

Figure 6:

Step 7:

Modify the Extension1.cs as the following way.

using System;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
using System.ComponentModel.Composition;

namespaceMyMEF
{
classExtension1
    {
[Export]
publicstring Message
{
get
    {
return" This is Extension 1";
    }
}
    }
}

Explanation of the code:

We can view this class as an extension. It has only one Export component i.e. a string read only property.
I have defined the get accessor of the property which returns the value "This is Extension 1".

Step 8:

Modify the MEFMain class as the following way.

using System;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;

namespaceMyMEF
{
classMEFMain
    {
 
[Import]
publicstring Message { get; set; }

publicvoid HelloMEF()
{
CompositionContainer container = newCompositionContainer();
CompositionBatch batch = newCompositionBatch();
batch.AddPart(newExtension1());
batch.AddPart(this);
container.Compose(batch);
Console.WriteLine(Message);
Console.ReadLine();
}
 
    }
}

Explanation of the code:

I have added three namespaces here.

System.ComponentModel.Composition
System.ComponentModel.Composition.Hosting [Used by the developer of the host application]
System.Reflection [To retrieve information of the assembly]

Our host application has only one Import i.e. a string property Message which will be extended by the Export of Extension1. It has a method HelloMEF. In the method, I have created an instance of the CompositionContainer. Then I have added the composable part i.e. the instance of Extension1 & the application host itself to the instance of CompositionBatch. Then I have added the batch instance to the container. Now the container will perform the composition i.e. it will match the import to the correct export.

Step 9:

Modify the Program.cs as the following way.

using System;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;

namespaceMyMEF
{
classProgram
    {
staticvoid Main(string[] args)
        {
MEFMainmefobj = newMEFMain();
mefobj.HelloMEF();
        }
    }
}

Explanation of the code:

I have created an instance of my host application MEFMain and called its HelloMEF function.

Step 10:

Now run the project.

Figure7.gif

Figure 7:

The container has done the composition. For the reason, the string property Message of our host application has got the value from the Export of Extension1.

Step 11:

Add one more class (Extension2.cs) to the project.

Figure8.gif

Figure 8:

Step 12:

Modify the Extension2.cs as the following way.

using System;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
using System.ComponentModel.Composition;

namespaceMyMEF
{
[Export]
classExtension2
    {
publicstring GetMessage(string name)
{
return"Hello" + name;
}
publicstring GetMessage2(string name)
{
return"Hi" + name;
}
    }
}


Explanation of the code:

Here I have created one more extension and in this case the Export is the class itself. It has two methods that take a string argument & also return a string.

Step 13:

Modify MEFMain as the following way.

using System;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;

namespaceMyMEF
{
classMEFMain
    {

        [Import]
publicstring Message { get; set; }

[Import]
publicExtension2ext { get; set; }

publicvoid HelloMEF()
        {
CompositionContainer container = newCompositionContainer();
CompositionBatch batch = newCompositionBatch();
batch.AddPart(newExtension1());
batch.AddPart(newExtension2());
batch.AddPart(this);
container.Compose(batch);
Console.WriteLine(Message);
stringmsg = ext.GetMessage2("Urmi");
Console.WriteLine(msg);
Console.ReadLine();
        }
 
    }
}

Explanation of the code:

In my host application, I have added one more Import that is a property of type Extension2 that will be extended by Extension2.

In the HelloMEF function, I have created an instance of Extension2 and added it to the container. I have called one method (Here GetMessage2) of the Extension2 using the extended property ext.

Step 14:

Now run the project.

Figure9.gif

Figure 9:

Step 15:

Modify MEFMain as the following way.

using System;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;

namespaceMyMEF
{
classMEFMain
    {

        [Import]
publicstring Message { get; set; }

        [Import]
publicExtension2ext { get; set; }

publicvoid HelloMEF()
        {
CompositionContainer container = newCompositionContainer();
CompositionBatch batch = newCompositionBatch();
batch.AddPart(newExtension1());
batch.AddPart(newExtension2());
batch.AddPart(this);
container.Compose(batch);
Console.WriteLine(Message);
stringmsg = ext.GetMessage("Urmi");
Console.WriteLine(msg);
Console.ReadLine();
        }

    }
}

Here I have called the other method (Here GetMessage) of the Extension2 using the extended property ext.

Step 16:

Now run the project.

Figure10.gif

Figure 10:

Step 17:

Now modify MEFMain as the following way.

using System;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;

namespaceMyMEF
{
classMEFMain
    {
        [Import]
publicstring Message { get; set; }

        [Import]
publicExtension2ext { get; set; }

publicvoid HelloMEF()
        {

var catalog = newAssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly());
var container = newCompositionContainer(catalog);
container.ComposeParts(this);
//CompositionContainer container = new CompositionContainer();
//CompositionBatch batch = new CompositionBatch();
//batch.AddPart(new Extension1());
//batch.AddPart(new Extension2());
//batch.AddPart(this);
//container.Compose(batch);
Console.WriteLine(Message);
stringmsg = ext.GetMessage("Urmi");
Console.WriteLine(msg);
Console.ReadLine();
        }
    }
}

Explanation of the code:

Till now I have added the composable parts to the container explicitly. But by using catalog ,the container handles creating parts automatically rather than them having to be added explicitly. Here an instance of AssemblyCatalog is created with the executing assembly passed into the container's constructor. I am not adding the instance of Extension1 & Extension2 as it will be discovered in the catalog that was passed for the current assembly.

Step 18:

Now run the project.

Figure11.gif

Figure 11:

We get the same output.

Step 19:

Now modify Extension1.cs as the following way.

using System;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
using System.ComponentModel.Composition;

namespaceMyMEF
{
classExtension1
    {
        [Export]
publicstring Message
        {
get
            {
return" This is Extension 1";
            }
        }

[Import]
publicExtension2 ext1 { get; set; }
 
publicvoidGetMsgExt()
{
string m = ext1.GetMessage("Uday");
Console.WriteLine(m);
}

    }
}


Explanation of the code:

Now I am adding am Import to the Extension1 that will be extended by Export of Extension2. In MEF, the extensions can depend on each other.

Step 20:

Now modify MyMEF as the following way.

using System;
usingSystem.Collections.Generic;
usingSystem.Linq;
usingSystem.Text;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;

namespaceMyMEF
{
classMEFMain
    {

        [Import]
publicstring Message { get; set; }

        [Import]
publicExtension2ext { get; set; }

publicvoid HelloMEF()
        {

//var catalog = new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly());
//var container = new CompositionContainer(catalog);
//container.ComposeParts(this);

CompositionContainer container = newCompositionContainer();
CompositionBatch batch = newCompositionBatch();
Extension1extobj = newExtension1();
batch.AddPart(extobj);
batch.AddPart(newExtension2());
batch.AddPart(this);
container.Compose(batch);
Console.WriteLine(Message);
extobj.GetMsgExt();
stringmsg = ext.GetMessage("Urmi");
Console.WriteLine(msg);
Console.ReadLine();
        }
 
    }
}

Step 21:

Now run the project.

Replica watches

Figure 12:

erver'>
Up Next
    Ebook Download
    View all
    Learn
    View all