Using Prism/MEF Dependency Injection with a plain old class

Topics: Prism v4 - WPF 4
Aug 19, 2013 at 7:55 PM
I've got a pretty good idea how DI works in Prism when you have an IModule. However, many of my classes where I want DI are not modules, they are plain old classes. If I use the [Import] statement, I never see any injection occur. If I use the [Export] attribute and provide an implementation of the IModule interface, I get injection. I can't imagine I need to provide an IModule implementation on every class so what am I missing?

To illustrate the problem, I've added a simple class to the Prism 4.1 Quickstarter solution called 'ModularityWithMef.Desktop'. This class is added to the 'ModuleA' project:

Class1.cs:
    namespace ModularityWithMef.Desktop
    {
        using System;
        using System.ComponentModel.Composition;
        using ModuleTracking;

        public class Class1
        {
            private IModuleTracker moduleTrackerField;

            [Import(typeof(IModuleTracker))]
            public IModuleTracker ModuleTracker
            {
                get
                {
                    return this.moduleTrackerField;
                }
                set
                {
                    this.moduleTrackerField = value;
                }
            }
        }
    }
The setter is never hit. If I decorate it with an [Export] statement, I can hit the setter, but then I get a message that I need to provide an 'Initialization()' method for any class decorated with an [Export] attribute. What am I missing here? I see the advantage of using attribute based DI, but I can't imagine that I have to implement IModule on every class that uses DI.
Aug 20, 2013 at 1:13 AM
Edited Aug 20, 2013 at 1:21 AM
OK, I answered my own question. It has everything to do with the decorator and how you instantiate 'Class1'. That is, you need to decorate Class1 above with the [Export] attribute, then when you create the object using the CompositionContainer, you'll get the injection to work:
            Class1 instance = compositionContainer.GetExportedValue<Class1>();
The most difficult part was getting a CompositionContainer in the loaded module. For this, I used DI to insert the ServiceLocator in the class when it was built. I have to say that my instincts agree with the article I read calling the static Service Locators the 'Anti-Pattern'. That method of doing things swaps several baked-in dependencies for a single baked-in dependency, but that's another thread. Anyway, the module is initialized with a service locator like so:
        [ImportingConstructor]
        public ModuleA(ILoggerFacade logger, IServiceLocator serviceProvider)
        {
            if (logger == null)
            {
                throw new ArgumentNullException("logger");
            }
            if (serviceProvider == null)
            {
                throw new ArgumentNullException("serviceProvider");
            }

            this.serviceLocator = serviceProvider as MefServiceLocatorAdapter;
            this.logger = logger;
        }
Then I was able to use it when the module was initialized:
        public void Initialize()
        {
            var compositionContainer = this.serviceLocator.GetInstance<CompositionContainer>();
            var class1 = compositionContainer.GetExportedValue<Class1>();
        }