Multiple services handled by one interface

Sep 18, 2008 at 4:30 PM
Specific topic continued from HERE -- working demo available HERE as MEF_QuickStart.zip.

For my POC (I don't really use a MessageBoxLogger;) I have two loggers which implement an ILogger interface.   The question arose in the referenced message thread on how to import and use a specific implementation - I offer a solution.  Would be interested in seeing other possible solutions.   I'm also new at LINQ so if there is a more efficient way to retrieve data from _logger in my DebugLogger and MessageBoxLogger readonly properties (in the IMPORTS section below) I'd appreciate the feedback.

EXPORTS

    [Export(typeof(ILogger))]
    [ExportMetadata("type", "DebugLogger")]
    public class DebugLogger : ILogger
    {
        public DebugLogger()
        {
        }
        public void Log(string message, LogCategoryType category, LogPriortyType priority)
        {
            Debug.WriteLine(message, string.Format("{0}({1})", category, priority));
        }
    }

    [Export(typeof(ILogger))]
    [ExportMetadata("type","MessageBoxLogger")]
    public class MessageBoxLogger : ILogger
    {
        public MessageBoxLogger()
        {
        }

        public void Log(string message,
            LogCategoryType category, LogPriortyType priority)
        {
            MessageBox.Show(message,
                string.Format("{0}({1})", category, priority));
        }
    }


IMPORT

        private ExportCollection<ILogger> _loggers = null;
        [Import(typeof(ILogger))]
        public ExportCollection<ILogger> Loggers
        {
            set { _loggers = value; }
        }
        public ILogger DebugLogger
        {
            get
            {
                ILogger returnValue = _loggers
                    .FirstOrDefault(m => m.Metadata["type"].ToString()
                        .Contains("DebugLogger")).GetExportedObject();
                return returnValue;
            }
        }
        public ILogger MessageBoxLogger
        {
            get
            {
                ILogger returnValue = _loggers
                    .FirstOrDefault(m => m.Metadata["type"].ToString()
                        .Contains("MessageBoxLogger")).GetExportedObject();
                return returnValue;
            }
        }
Sep 18, 2008 at 5:34 PM
BillKrat, what will happen if there is no debugLogger  in your IMPORT? Will it return a null or the I:Logger interface? same with MessageBoxLogger as well?

Also, so your IMPORT has definitive knowledge of what type of loggers you have.

Instead of making as properties in the IMPORT what will happen if I have a function that takes a Param and returns the ILogger? ( Assumption: nothing is done to the object that is instantiated).

What if I want my Biz App to look like this:

private ILogger getMeALogger(string loggerType)
{
    if thisApplication "can access" and "is allowed to use" Loggers from the catalog
     check if there is a logger of  loggerType
    if yes then return a Logger[loggerType]
}
Sep 19, 2008 at 11:37 AM
Another work-around: Loggers.Resolve<ILogger>("MessageBoxLogger"); via extension class.

Hi Ganesh, perhaps "solution" was a bad term, I should have said "work-around" for the constraints of the current design.  Constraints that will be addressed by the team as Glenn noted HERE in his Wed 10:40am comment.  In the meantime I offer a work-around :)   To answer your questions - it will crash if it returns null and IMPORT is tightly coupled; until a solution is provided this will allow us to get the job done. 

My work-around is evolving (more for the learning experience than anything else).  I can now localize my business logic in the extension class, i.e., if I wanted to add features such as returning a "default" (if the type is not found) or handling security/access.  My DebugLogger and MessageBoxLogger now look as follows:

    public ILogger DebugLogger{
        get {
            return Loggers.Resolve<ILogger>("DebugLogger");
        }
    }

    public ILogger MessageBoxLogger {
        get {
            return Loggers.Resolve<ILogger>("MessageBoxLogger");
        }
    }

    public static class MEFExtensions
    {
        public static T Resolve<T>(this ExportCollection<T> thisObj, string name)
        {
            return (T)thisObj
                .FirstOrDefault(m => m.Metadata["type"].ToString()
                    .Contains(name)).GetExportedObject();
        }
    }