Introduction to MEF Programming – Importing Multiple Objects

Importing Multiple Objects

In the previous blog, we discussed the basic MEF attributes. Let us get into advance topics in MEF step by step.

In the previous example, we wrote the code for the main exe, contract library and MEF Part1. Imagine we have another class derived from IGreeting and implements the SayHelloWorld() function. The class diagram and sequence diagram is shown below.

image

Fig: Class diagram of the participating classes.

image

Fig: Sequence Diagram for the above classes

In the previous blog, i posted the code of all the participating classes. Let us add the new UserGreetingClass to the solution.

Coding the MEFPart2 Library:

  1. Add a New Project –> Visual C# –> Class Library.Enter Name as  MEFPart2. Click OK. Add the following code.
  2. Add a reference to the System.ComponentModel.Composition assembly.
  3. Add a reference to the ContractsLibrary.DLL assembly.
  4. Add the following using statement:
    • using System.ComponentModel.Composition; This allows us to specify the attributes for using MEF.
    • using ContractsLibrary;
  5. Add the following code.
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel.Composition;
  4. using ContractsLibrary;
  5.  
  6. namespace MefLabPart2
  7. {
  8.     [Export(typeof(IGreeting))]
  9.     public class UserGreeting : IGreeting
  10.     {
  11.         public string SayHelloWorld()
  12.         {
  13.             return "Hello " + Environment.UserDomainName;
  14.         }
  15.     }
  16. }

 

Compile the solution and copy the  MEFPart2.DLL to the MainExe\bin\Debug folder, where the MainExe.exe is located. Try running the application. The following error mesage comes up in the console.

The composition remains unchanged. The changes were rejected because of the following error(s): The composition produced a single composition error. The root cause is provided below. Review the CompositionException.Errors property for more detailed information.

1) More than one export was found that matches the constraint ‘((exportDefinition.ContractName == "ContractsLibrary.IGreeting") AndAlso (exportDefinition.Metadata.ContainsKey("ExportTypeIdentity") AndAlso "ContractsLibrary.IGreeting".Equals
(exportDefinition.Metadata.get_Item("ExportTypeIdentity"))))’.

Resulting in: Cannot set import ‘meflab1.Program.Greetings (ContractName="ContractsLibrary.IGreeting")’ on part ‘meflab1.Program’. Element: meflab1.Program.Greetings (ContractName="ContractsLibrary.IGreeting") –>  meflab1.Program

Press any key to continue . . .

The issue here is that the catalog contains two exports and the import is importing only one export. So when the container tries to match the imports and exports, it fails with the above error.

image

Fig: Debug information of the catalog.

The Import attribute will only be successfully composed when it matches one and only one export. Other cases will produce a composition error. An ordinary ImportAttribute attribute is filled by one and only one ExportAttribute. If more than one is available, the composition engine produces an error. To import more than one export that matches the same contract, use the ImportMany attribute. Imports marked with this attribute are always optional. For example, composition will not fail if no matching exports are present. The following class imports any number of exports of type IGreeting.

  1. class Program
  2. {
  3.     [ImportMany]
  4.     public IEnumerable<IGreeting> Greetings { get; set; }

 

Following is the code of the MainExe project.

using System; 
using System.IO; 
using System.Reflection; 
using System.ComponentModel.Composition; 
using System.ComponentModel.Composition.Hosting; 
//using System.ComponentModel.Composition.Primitives; 
using ContractsLibrary; 
using System.Collections.Generic; 
  
  
  
namespace meflab1 
{ 
    class Program 
    { 
      [ImportMany] 
      public IEnumerable<IGreeting> Greetings { get; set; } 
  
        static void Main(string[] args) 
        { 
            Program program = new Program(); 
            program.Run(); 
        } 
  
        public Program() 
        { 
            try 
            { 
                AggregateCatalog aggregatecatalogue = new AggregateCatalog(); 
                aggregatecatalogue.Catalogs.Add(new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory)); 
                CompositionContainer container = new CompositionContainer(aggregatecatalogue); 
                CompositionBatch batch = new CompositionBatch(); 
                batch.AddPart(this); 
                container.Compose(batch); 
            } 
            catch (FileNotFoundException fnfex) 
            { 
                Console.WriteLine(fnfex.Message); 
            } 
            catch (CompositionException cex) 
            { 
                Console.WriteLine(cex.Message); 
            } 
        } 
  
        void Run() 
        { 
            foreach (var mgreeting in Greetings) 
            { 
                if (mgreeting != null) 
                { 
                    Console.WriteLine(mgreeting.SayHelloWorld()); 
                    Console.ReadKey(); 
                } 
            } 
        } 
    } 
} 

 

Source Code is available at :

Microsoft: http://cid-38ecce05b21b8b44.office.live.com/self.aspx/MY%20Projects/mef%202.zip

(OR) Google: MEF Lab 2 (http://code.google.com/p/mef-dotnet/downloads/detail?name=mef%202.zip)

Have Fun !!!

 “If your actions inspire others to dream more, learn more, do more and become more, you are a leader.”

About these ads

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s