Monday, 30 April 2012

Implementing MEF with list of attributes

After working with Managed Extensibility Framework or MEF (http://mef.codeplex.com/) for a while, I came across a case when I needed to add attributes to different classes in order to distinguish implementation from classes.

As sample scenario you have different implementation of service and you want to set specific Ids of services to run in different way.

To do this using MEF is a bit different as we need to find out which implementation the one we want to use.

As solution I have chosen to use decoration something like this:
    [SignalSystemData(name, array)]
Where variables are:
  1.  name: variable name so we can identify the string between our classes and implementations.
  2.  array: related items for this implementation
And we come up with something like:

    [SignalSystemData("ServiceIds", new int[]{2,5,3 , 15,16,300,301,302,305})]




After searching modification of code the solution is here:




namespace ConsoleApplication1
{
   using System;
   using System.Collections.Generic;
   using System.ComponentModel.Composition;
   using System.ComponentModel.Composition.Hosting;
   using System.Linq;
   using System.Reflection;

    internal class Program
    {
        private static void Main(string[] args)
        {
            int serviceIdToCall = 305;

            var c = new Class1();
            var v = c.EditorSystemList;
           
            foreach (var lazy in v.Where(x=>x.Metadata.LongName=="ServiceIds"))
            {
                if (lazy.Metadata.ServiceId.Contains(serviceIdToCall))
                {
                    var v2 = lazy.Value;
                    // v2 is the instance of MyEditorSystem
                    Console.WriteLine(serviceIdToCall.ToString() + " found");

                }else
                {
                    Console.WriteLine(serviceIdToCall.ToString() + " not found");
                }
            }

            Console.ReadKey();
        }
    }

    public class Class1
    {
        [ImportMany]
        public IEnumerable<Lazy<IEditorSystem, IEditorSystemMetadata>> EditorSystemList;

        public Class1()
        {
            var catalog = new AggregateCatalog(
                new AssemblyCatalog(Assembly.GetExecutingAssembly()));
            var container = new CompositionContainer(catalog);
            container.ComposeParts(this);
            Console.Write("Composition completed");
        }
    }

    [Export(typeof (IEditorSystem))]
    [SignalSystemData("ServiceIds", new int[]{2,5,3 , 15,16,300,301,302,305})]
    public class MyEditorSystem2 : IEditorSystem
    {
        public void Test ()
        {
            Console.WriteLine("ServiceID : 2");
        }
    }

    [Export(typeof(IEditorSystem))]
    [SignalSystemData("ServiceIds", new [] {1, 20})]
    public class MyEditorSystem1 : IEditorSystem
    {
       
        #region Implementation of IEditorSystem

        public void Test()
        {
            Console.WriteLine("ServiceID : 1");
        }

        #endregion
    }


    public interface IEditorSystem
    {
        void Test();
    }

    [MetadataAttribute]
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    public class SignalSystemDataAttribute : ExportAttribute
    {
        public SignalSystemDataAttribute(string longName, params int[] serviceId)
            : base(typeof (IEditorSystem))
        {
            LongName = longName;
            ServiceId = serviceId;
        }

        public string LongName { get; set; }
        public int[] ServiceId { get; set; }

    }

    public interface IEditorSystemMetadata
    {
        string LongName { get; }
        int[] ServiceId { get; }
    }   
}