Unity Strategy for MEF

by 22. August 2010 11:22

The Prism 4.0 CTP has support for Unity and MEF, but not both at the same time.   In my case this is a problem because I'd like to use MEF for what it is designed for (extensibility / add-ins) and use Unity for what it was designed for (dependency injection).

To achive my requirements I'm going to use the extensibility hooks within Unity, more specifically; a strategy.   Surprisingly the power of strategies are not emphasized and there is not a lot of documentation on the subject.  The "walkthrough" in the Unity 2.0 documentation gives an example of how to create an extension and strategy but I found the Unity unit test to be more complete (I used the SpyExtension as an example on how to construct my MEFStrategy).

The first test below PublicFromPublic() is a MEF unit test that I revamped to test my MEFContainer, which encapsulates and simplifies working with the MEF container and CompositionBatch within the strategy.

The second test lets the Unity container drive and depends on the strategy to add the parts to the batch within the MEFContainer.  The test verifies that the parts are not yet composed prior to executing Compose() and that they are composed following the Compose() method.

This strategy is still in its infant stages, I only started this weekend and have a ways to go before I plug it into Prism 4.0. 


using System.ComponentModel.Composition;
using MEFContrib.Base;
using MEFContrib.Strategy;
using Microsoft.Practices.Unity;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace TestStrategyToLoadMEF
{
    [TestClass]
    public class MEFStrategyFixture
    {
        [TestMethod]
        public void PublicFromPublic()
        {
            var importer = new AllPublicImportOnly { ImportA = 1, ImportB = 1 };
            var exporter = new AllPublicExportOnly { ExportA = 5, ExportB = 10 };
            new MEFContainer()
                .AddPart(importer)
                .AddPart(exporter)
                .Compose();
            Assert.AreEqual(5, importer.ImportA);
            Assert.AreEqual(10, importer.ImportB);
        }
        [TestMethod]
        public void TestStrategyToLoadMEF()
        {
            var mefContainer = new MEFContainer();
            var mefExtension = new MEFStrategyExtension(mefContainer);
 
            // Instantiate unity container and add MEF extension
            var container = new UnityContainer().AddExtension(mefExtension);
            // Initialize MEF parts
            var importer = new AllPublicImportOnly { ImportA = 1, ImportB = 2 };
            var exporter = new AllPublicExportOnly { ExportA = 5, ExportB = 10 };
            // Buildup importer/exporter (strategy kicks in)
            container.BuildUp(importer);
            container.BuildUp(exporter);
            // Register importer instance emulating use in other area of app
            container.RegisterInstance<AllPublicImportOnly>(importer);
            // Resolve MEF and Unity classes
            var importResolved = container.Resolve<AllPublicImportOnly>();
            var classThatImports = container.Resolve<TestClassThatImports>();
            // MEF parts have not yet been composed (Strategy adds them to batch)
            Assert.AreEqual(1, importResolved.ImportA);
            Assert.AreEqual(2, importResolved.ImportB);
            
            // Compose MEF parts
            mefContainer.Compose();
            // After composition exported values should be in place
            Assert.AreEqual(5, importResolved.ImportA);
            Assert.AreEqual(10, importResolved.ImportB);
            // Unity setter injection 
            Assert.AreEqual(20, classThatImports.ImportedClass.TestValue);
        }
    }
    
    public class TestClassThatImports
    {
        [Dependency]
        public TestClassToImport ImportedClass { getset; }
    }
    public class TestClassToImport
    {
        public TestClassToImport()
        {
            TestValue = 20;
        }
        public int TestValue { getset; }
    }
    public class AllPublicImportOnly
    {
        [Import("a")]
        public int ImportA { getset; }
        [Import("b")]
        public int ImportB { getset; }
    }
    public class AllPublicExportOnly
    {
        [Export("a")]
        public int ExportA { getset; }
        [Export("b")]
        public int ExportB { getset; }
    }
}
SOURCE: TestStrategyToLoadMef.zip (11.62 mb)
 

Tags: , ,

MEF | Unity

Notice

Blog videos and references to CodePlex projects are no longer valid