Managed Extensibility framework in C#

Discussion in 'C#' started by MinalS, Apr 6, 2015.

  1. MinalS

    MinalS New Member

    Joined:
    Jul 8, 2014
    Messages:
    138
    Likes Received:
    32
    Trophy Points:
    0
    The following diagram shows the parts and containers present in the Managed Extensibility Framework.

    [​IMG]

    The container is used to find the parts from the catalog. The catalog finds the parts from the assembly or a directory. The container is used to connect and import or export the parts and thus making it available it for other hosting applications.

    The parts are present in the catalog. It uses the export to find the parts from the catalog. Several export providers can access the catalog and offers the exports from the catalog. For customizing the exports, the multiple export providers are connected in chains for the customizing exports.

    MEF contains of three categories as classes for hosting, primitives, and the classes dependent on the attribute based type. The hosting class contains the catalogs and containers. The primitive classes are used as a base class for extending the MEF architecture. The attribute based classes contains Import and Export attributes and provides extension methods for simplification of work.

    Import and Export Attributes



    In MEF, the host application loads the add ins dynamically. In MEF, the add in are referred as part. They are defined as imports and exports. The parts which are exports are added in the container that imports the parts. The catalog and the catalog list parts are useful for finding the parts.

    Consider a simple example of a Calculator console application containing add – ins from the library. For creating an independent application, add three assemblies. One assembly holds the contract used by both the add –ins and the executable.

    The contracts in the assembly are defined using two interfaces. They are ICalculator and IOperation.

    Code:
    
    using System.Collections.Generic;
    namespace MEFApplication
    {
        public interface ICalculator
        {
            IList<IOperation> GetOperations();
            double Calculate(IOperation operation, double[ ] operands);
        }
    }
    
    
    In the above snippet, the ICalculator interface defines methods as GetOperations and Calculate. The list of all operations is returned by the GetOperations method. Using the Calculate method the operation is added.

    The ICalculator interface uses the IOperation interface for returning the list of operations.

    Code:
    
    namespace MEFApplication
    {
        public interface IOperation 
        {
            string OperatorType { get; }
            int NumberOfOperands { get; }
        }
    }
    
    
    In the above code, the read only properties as OperatorType and NumberOfOperands are defined.

    The Calculator class provides the user with the implementation of the ICalculator interface. The Export attribute is used for exporting the part defined. The System.ComponentModel.Composition namespace.

    Code:
    
    using System;
    using System.Collection.Generic;
    using System.ComponentModel.Composition;
    
    namespace MEFApplication1
    {
        [ Export(typeof(ICalculator) ]
        public class Calculator : ICalculator
        {
            public IList<IOperation> GetOperations()
            {
                return new List<IOperation>()
                {
                    new Operation { OperatorType=”+”, NumberOfOperands=2},
                    new Operation{ OperatorType=”-“, NumberOfOperands=2},
                    new Operation{ OperatorType=”*“, NumberOfOperands=2},
                    new Operation{ OperatorType=”/“, NumberOfOperands=2}
                };
            }
        public double Calculate( Operation operation, double[ ] operands)
        {
            double output = 0;
            switch(operation.OperatorType)
            {
                case “+” :
                result = operands[0] + operands[1];
                break;
    
                case “-” :
                result = operands[0] - operands[1];
                break;
    
                case “*” :
                result = operands[0] * operands[1];
                break;
            
                case “/” :
                result = operands[0] / operands[1];
                break;
    
                default: 
                throw new InvalidOperationExcpetion ( String.Format(“invalid operation {0}”, operation.OperationType);
        
            }
            return output;
        }
    }
    }
    
    
    User can host the application as a simple console application. The Import attribute is used to set and get the object implementing the ICalculator.

    Code:
    
    using System;
    using System.Collection.Generics;
    using System.ComponentModel;
    using System.ComponentModel.Composition.Hosting;
    
    namespace MEFApplication1
    {
        class Program
        {
            [Import]
            public ICalculator Calculator{get;set;}
        }
    }
    
    
    In the Main method of the code, add the Run method. In the Run method, add the DirectoryCatalog is created.

    Code:
    
    public static void Main ( )
    {
        var p1 = new Program();
        p1.Run();
    }
    
    public void Run()
    {
        var catalog = new DirectoryCatalog(Settings.Default.AddInDirectory);
        var container = new CompositeContianer(catalog);
        try
        {
            container.ComposeParts(this);
        }
        catch(ChangeRejectedException e )
        {
            Console.WriteLine(e.Message);
            return;
        }
    }
    
    
    In the above code, the DirectoryCatalog is created and initialized in the AddInDirectory available in the configuration file. The CompositeContainer is initialized with the DirectoryCatalog to get the parts. ComposeParts is the extension of the method and extends the container class. The exception of the ChangeRejectedException is thrown, the exception is caught and the method exists.

    The Calculator property is used to get the methods from the ICalculator interface. The previously created add ins are used by the GetOperations method.

    Code:
    
    var operations = Calculator.GetOperations();
    var operationDict = new SortedList<string, IOperations>();
    foreach(var item in operations)
    {
        Console.WriteLine(“OperatorType : {0}, NumberOfOperands : {1}”, item.OperatorType, item.NumberOfOperands);
        operationDict.Add(item.OperatorType, item);
    }
    
    string select = null;
    do
    {
        try
        {
            Console.WriteLine(“Operation selected is”);
            select = Console.ReadLine();
            if(select.ToLower() == “exit” | | operationDict.ContainsKey(select))
            continue;
            var operation = operationDict[select];
            double [ ] operands = new double [ operation.NumerOfOperands ];
            for ( int i = 0; i<operation.NumberOfOperands;i++)
            {
                Console.Write(“\t operand [0] “,i+1);
                string selectoper = Console.Read();
                operands[i] = double.Parse(selectoper);
            }
            double output = Calculator.Operate(operation, operands);
            Console.WriteLine(“output: {0}”, output);
        }
        catch(FormatException e )
        {
            Console.WriteLine(e.Message);
            continue;
         }
    }while(selectoper ! = “exit”);
    }
    
    

    Composition Containers



    The CompositionContainer class is the container for all the parts. The hosting is defined in the System.ComponentModel.Composition.Hosting namespace. User can assign multiple ExportProvider objects in the class constructor.

    Add the following code in the constructor of the composition containers.

    Code:
    
    private Program()
    {
        var catalog = new DirectoryCatalog(Properties.Settings.Default.AddInDirectory);
        container = new CompositionContainer(catalog);
        try
        {
            this.container = ComposeParts (this);
        }
        catch ( CompositionException compositionException)
        {
            Console.WriteLine(compositionException.ToString());
        }
    }
    
    
    In the above code, the ComposeParts attribute is an extension method defined with the AttributeModelServices. It provides user with the methods that use attributes and reflection. They are used for accessing the information and add parts to the container.

    Catalogs



    The catalog is used for defining the MEF searches for the parts requested by the user. The CompositionContainer requires a ComposablePartCatalog for finding the parts. The DirectoryCatalog derives from the ComposablePartsCatalog.

    There are several catalogs that can be used in MEF. They are as listed below:
    1. DirectoryCatalog: It is used for searching the parts within the diectory
    2. AssemblyCatalog: It is used for searching the parts within the referenced assembly. The catalog is immutable and the parts cannot be changed.
    3. TypeCatalog: It searches for the imports within the list of types
    4. AggregateCatalog: It is defined as the catalogs of catalog. It can be created from multiple ComposablePartCatalog objects.
    1. DirectoryCatalog class

    The class finds the attributed parts in the assemblies in a directory specified by the user. The class is derived from the System.ComponentModel.Composition.Hosting.DirectoryCatalog namespace.

    Properties of the DirectoryCatalog class
    1. FullPath: It is used to get the translated absolute path used by the object
    2. Parts: It gets the parts definitions that are present in the catalog
    3. Path: It gets the path observed by the object
    4. SearchPattern: It gets the pattern passed to the constructor
    Methods of the DirectoryCatalog class
    1. Dispose(): It is used to release all the resources used by the catalog
    2. Finalize: It is used to free the resources and perform the cleanup operations
    3. GetType: It is used to get the type of the current instance
    4. ToString: It gets a string representation of the catalog
    Consider the following example to demonstrate the use of the directory catalog.

    Code:
    
    public class Demo
    {
        [Import]
        public Demo1 value { get; set; }
    }
    
    class Program
    {
        static void Main ( string[ ] args )
        {
            DirectoryCatalog catalog = new DirectoryCatalog(“ .”);
            CompositionContainer con = new CompositionContainer(catalog);
            Demo d = new Demo();
            Console.WriteLine(d.value.value);
            Console.Read();
        }
    }
    
    
    In the above code, the DirectoryCatalog object is used to search the application executing from the parts. An import is used to test the catalog.

    A matching export is created using the following DLL file. Add a Class Library to the solution and add the following code.

    Code:
    
    [Export]
    public class Demo1 
    {
        public String value =” The Demo Value”;
    }
    
    
    2. AssemblyCatalog class

    The class is used to find the attributed parts in the managed code assembly. It is inherited from the System.ComponentModel.Composition.Hosting.AssemblyCatalog namespace.

    Properties of the AssemblyCatalog class
    1. Assembly: It is used to get the assembly whose attribute types are present in the catalog
    2. Parts: It is used to get the parts definitions present in the catalog

    Methods of the AssemblyCatalog class
    1. GetExports: It is used to get the collection of exports that match the condition specified by the user
    2. MemberwiseClone: It is used to create a shallow copy of the object
    3. GetType: It is used to get the type of the current instance
    4. GetEnumerator: It is used to return an enumerator that is used for iterating through the catalog
    Consider the following example to demonstrate the use of AssemblyCatalog class

    Code:
    
    class NewProgram
    {
        [Import]
        public Ass1 ass1 { get; set; }
    }
    
    class Program
    {
        static void Main ( string[ ] args )
        {
            AggregateCatalog cat = new AggregateCatalog();
            cat.Catalogs.Add(new AssemblyCatalog (typeof(Ass1).Assembly) );
            CompositionContainer con = new CompositionContainer(cat);
            NewProgram n1 = new NewProgram();
            con.SatisfyImportsOnce(n1);
            Console.WriteLine(n1.ass1.data);
            Console.ReadLine();
            con.Dispose();
        }
    }
     
    
    A matching export is created using the following DLL file. Add a Class Library to the solution and add the following code.

    Code:
    
    [Export]
    class Ass1 
    {
        public string data { get { return “New Data”; } }
    }
    
    
    3. TypeCatalog class

    The TypeCatalog class is used as a repository of different types that form Import and Export types. It is inherited from the System.ComponentModel.Composition.Hosting.TypeCatalog namespace.

    When the user needs to add the TypeCatalog either pass the array of Types or an Enumerable of Types used by the catalog.

    Consider the following example to show the TypeCatalog class.

    Code:
    
    public class Container1
    {
        [Export]
        public string Name { get; set; }
        
        [Export]
        public string GetName ()
        {
            return this.Name;
        }
    
    }
    
    
    The above code contains some of the members that are exposed to the external world. When user passes the type to a TypeCatalog, it exposes export definitions and imports Import definitions.

    Code:
    
    static void Main ( string [ ] args )
    {
        TypeCatalog cat1 = new TypeCatalog ( typeof(Container1) ) ;
        Console.WriteLine(catalog.Parts.Count());
        Console.Read();
    }
    
    
    The code will return the number of Types passed by the catalog. User can pass many types in the TypeCatalog.
     
    Last edited by a moderator: Jan 21, 2017
  2. coderzone

    coderzone Super Moderator

    Joined:
    Jul 25, 2004
    Messages:
    736
    Likes Received:
    38
    Trophy Points:
    28
    Very well explained.
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice