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

ASP.NET MVC 2 - Passing Parameters to Silverlight application

by 17. November 2009 22:07

In our SDMS application (source code here) we pass parameters from our ASP.NET MVC 2 application to our Silverlight application.   We have a ISystemConfiguration implementation that contains the following information from our ASP.NET MVC 2 Web.Config file (watch window below).  I should note here that we'll have one configuration file to manage our entire application (MVC 2 and Silverlight).


Since config on line 78 is a singleton we have effectively updated our unity container to contain the same parameter object that our MVC 2 application contains (the contents of it's Web.Config file).   See THIS BLOG for more information on the Serialization/Deserialization process.

You'll find in the Library.Demo.ASPMVC2 application of our SDMS solution that we can easily upgrade our MVC 2 application to have Unity support by merely changing the classes that the Global.asax and Controllers derive from using our MVCContrib project (see the LibraryDoc.chm file for details).   Unity allows us to easily support Multi-targeting which means our ASP.NET MVC2, WPF and Silverlight applications all share the same codebase.   Below we see the only Silverlight specific code that was required in our Bootstrapper class was to deserialize the XML String back into our ISystemConfiguration object.   We don't have to do this in WPF (which also shares this code) because it's Unity container already contains it . 

 

Note for PRISM readers: We have to configure our container, and deserialize our parameter object, in GetModuleCatalog because it is called from the UnityBootstrapper's CreateContainer command which occurs prior to CreateShell (see sequence diagram here); we want to ensure we have everything registered before we buildup our view, presenter and call the presenters OnGetModuleCatalog() where the application specific work is done.  

An important part of passing our parameter object is to first make it available to MVC 2.   You'll find that we didn't have to make any changes to a default MVC 2 application (outside of the classes derived from) which indicates that the MVCContrib infrastructure did all of the work of pulling the configuration information out of the Web.Config file into our parameter object for us.  

Below you'll see that we tap into the Master page to call our own html extension SetContainer() on line 57 of the top window in the image below.   Our extension simply takes the parameter object, Serializes it using our object extension, and then passes the resulting xml string into ViewData["InitParams"]



Next we have to get our ViewData["InitParams"] that was set in line 54 above (bottom window) into Silverlight.  The following excerpt from our Library.Demo.ASPMVC2\Views\Home\Silverlight.aspx shows us how this is done:

As a result of the above the Silverlight's App.xaml.cs file will receive the serialized parameter (xml string) in it's Application_Startup method on it's StartupEventArgs (e.InitParams).

private void Application_Startup(object sender, StartupEventArgs e)
{
    BootStrapper bootstrapper = new BootStrapper(new MainPage(), e);
    bootstrapper.Run();
    // The following was moved into MainPage.Show()
    // => this.RootVisual = new MainPage();
}

We'll pass this into our Bootstrapper which it will store it in an args field which brings us full cycle to our first image where our serialized string is retrieved via 

      var para = args.InitParams["InitParams"]

private StartupEventArgs args;
public BootStrapper(object sender, StartupEventArgs e)
{
    view = sender
as IShellView;
    args = e;
}

Serialize / Deserialize POCO objects - Silverlight and WPF (multi-targeting code)

by 17. November 2009 21:28

In our SDMS application (source code here) we have a library that is multi-targeting (shared codebase) for ASP.NET MVC2, Silverlight and WPF, as you'll see in the image below the "only" differences will be the App.xaml and Mainxxxx.xaml files.   To pull this off we give the CAG Bootstrapper a little more work to do.

One of the jobs of the GetModuleCatalog() method in the Bootstrapper is to deserialize our parameter object (more on parameter object in my next blog).   We have to do this in GetModuleCatalog because it is called within the UnityBootstrapper's CreateContainer command which occurs prior to CreateShell (see sequence diagram here).  Note that we do this with the object extension DeserializeObject

The following code will permit us to serialize and deserialize our POCO object.   The code resides in this applications UnityContrib project in the Extensions\ObjectExtension class.

 

Unity 2.0 update - comprehensive error reporting! Important in PRISM/DI environment.

by 7. August 2009 02:43

I keep my finger on the pulse of Microsoft's newest technologies and updates; I typically find that they make my life a lot easier by helping me to be more productive for my clients.   The latest Unity 2.0 updates did not disappoint!

On THIS LINK (image below) you'll find the following information on the Unity 2.0 update which is currently available for download in the http://www.codeplex.com/Unity downloads area:

Anyone having to troubleshoot an enterprise level application that uses dependency injection will appreciate the new power provided to us.  In my case I use the PRISM framework and have spent my fair share of time locating errors caused by a failure to register a dependency.

THIS WEBCAST shows that within a few minutes (literally) we can track down and resolve (no pun intended) an issue.

 

CompositeWPF/Prism - Adding modules after BootStrapper

by 27. February 2009 06:32

The following sequence diagram shows us that the InitializeModules() method is the last process run http://global-webnet.net/UML/prism.htm

Examining the baseclass code we find that the following is what actually loads the modules; suggesting that it is safe to run again because of  the statement in bold:

       private void LoadModuleTypes(IEnumerable<ModuleInfo> moduleInfos)
       {
            if (moduleInfos == null)
            {
                return;
            }

            foreach (ModuleInfo moduleInfo in moduleInfos)
            {
                if (moduleInfo.State == ModuleState.NotStarted)
   
             {
                    if (this.ModuleNeedsRetrieval(moduleInfo))
                    {
                        this.BeginRetrievingModule(moduleInfo);
                    }
                    else
                    {
                        moduleInfo.State = ModuleState.ReadyForInitialization;
                    }
                }
            }
            this.LoadModulesThatAreReadyForLoad();
        }


I did a quick Proof of Concept with the StockTraderRI application to see if it was as easy as what was suggested to add a module after the BootStrapper process;  I added the line in bold below to the App() class

namespace StockTraderRI
{
    public partial class App : Application
    {
        public App()
        {
            this.Startup += this.Application_Startup;
            this.Exit += this.Application_Exit;
            this.UnhandledException += this.Application_UnhandledException;

            InitializeComponent();
        }

        private void Application_Startup(object sender, StartupEventArgs e)
        {
            //this.RootVisual = new Shell();
            var bootstrapper = new StockTraderRIBootstrapper();
            bootstrapper.Run();

            // Watch module will not load without this line
            bootstrapper.PostCatalogProcessing(); 
        }

I then updated the StockTraderRIBootstrapper as follows. 

namespace StockTraderRI
{
    public partial class StockTraderRIBootstrapper : UnityBootstrapper
    {
        protected override IModuleCatalog GetModuleCatalog()
        {
            var catalog = new ModuleCatalog();
            catalog.AddModule(typeof(MarketModule))
                .AddModule(typeof(PositionModule), "MarketModule");
                //.AddModule(typeof(WatchModule), "MarketModule");   <= remarked out
                //.AddModule(typeof(NewsModule));                                <= remarked out

            return catalog;
        }

        public void PostCatalogProcessing()
        {
            ModuleCatalog catalog = (ModuleCatalog)Container.Resolve<IModuleCatalog>();
           
            catalog.AddModule(typeof(WatchModule), "MarketModule");
            catalog.AddModule(typeof(NewsModule));
            InitializeModules();
        }

Prism/WCF - Cannot find ServiceReferences.ClientConfig in .xap application package

by 3. January 2009 03:52

I'm using Prism (V8) to create a Silverlight application.  The main Project is the SDMS.Silverlight project which loads the EmployeeModule via it's BootStrapper.GetModuleCatalog() method.

The EmployeeModule references a WCF Web Service to obtain the Employee list - the ServiceProvider service (shown in EmployeeModule/ServiceReferences below) has a corresponding ServiceReferences.ClientConfig file which is not being found by Silverlight when the EmployeeService.GetEmployeeList() executes.

When I launch the application I receive the the following error:

     Cannot find 'ServiceReferences.ClientConfig' in the .xap application package  

 

Silverlight obviously found the EmployeeModule assembly but cannot find the ServiceReferences.ClientConfig it contains.

The cure is to provide the Application assembly (SDMS.Silverlight) with a reference to it.  This can be easily done by right clicking on the file and selecting copy - it will copy the fullpath to the clipboard.

Next you'll want to go to the main assembly, in our case SDMS.Silverlight, and add an existing item - the IMPORTANT PART is to click the down triangle on the "Add" button and select "Add Link" as shown in the image below:

Now as the EmployeeModule's ServiceProvider is updated the main assembly will also be updated.  Our silverlight application now runs without issue. 

Tags: , ,

Unity

Integrating IIS WCF and Unity

by 3. January 2009 01:45

Our open source Solution Development Management System (SDMS) will use WCF services as a data source for both it's Silverlight and Desktop applications.  To maximize reusability it was necessary to implement Unity so that we can utilize dependency injection within our services.

Initial google research quickly revealed that WCF Behaviors would provide the necessary hooks so that a Unity Container could be instantiated, configured and used to resolve the applicable service.

Of the resources available I found the following to be instrumental to understanding and integrating unity into WCF via behaviors; the MSDN article provides details on WCF Behaviors: 

  Integrating the Policy Injection Application Block with WCF Services
  http://msdn.microsoft.com/en-us/magazine/cc136759.aspx

In this Webcast (Windows 7 users may have to right click and Save Target as to view it) I demonstrate how we can easily switch between the Services and ServicesStub classes below with a simple Web.Config configuration change.  Note: both of these classes implement IServices.

 

Below we show the "Stubs" configuration being utilized:

We'll change "Stubs" to "Services" (see arrow below) to utilize the other class.

And receive the following results:

To implement the Unity Behavior all that was required was to add a reference to the UnityBehavior project and make the following Web.Config changes within the Service to utilize the behavior.

Note:   If you do not want to provide a Unity Configuration in the Web.Config all you would have to do is change the line below (pointed to by the arrow) to:

     return container.Resolve(type);

And it will resolve the default service - in this case SDMSService.Services.

Source code available HERE on the Source Code tab (changeset 27387)

Tags: ,

Unity

Unity - factory pattern and extensibility

by 13. October 2008 08:28

The Unity and Workflow infrastructure, created for the MAMLConverter application, provides an extensible framework.  For example, to add a new HTML tag (for conversion to MAML) a developer only has to update the Resource file, add the new Tag<newTag>Command.cs file, compile and deploy.   An excerpt from the TagH2Command.cs command follows:

namespace Workflow.Library.TagCommands

{

    /// <summary>

    /// H2 tag

    /// </summary>

    public class TagH2Command : TagCommandBase

    {

        /// <summary>

        /// Executes this instance.

        /// </summary>

        public override void Execute()

        {

            // TODO: support attributes

            MAMLTag = Resources.h2;

        }

    }

Unity simplifies matters, we don't have an actual Factory class however we do have a class used to register the ITagCommands that will be used by Unity to resolve the concrete class. 

As each html tag hits the ElementProcessorActivity (in a ReplicatorActivity) it request the MAMLTag from the service.

The service turns to Unity to resolve the ITagCommand for the specified htmlTag

/// <summary>

/// Gets the MAML tag.

/// </summary>

/// <param name="htmlTag">The HTML tag.</param>

/// <returns></returns>

public string GetMAMLTag(string htmlTag)

{

    // We'll use the unity container as a factory

    ITagCommand TagCommand;

 

    // Ensure we have a configured ITagCommand - workaround:

    // http://www.codeplex.com/unity/WorkItem/View.aspx?WorkItemId=1991

    try

    {

        TagCommand = UnityContainer.Resolve<ITagCommand>(htmlTag);

        TagCommand.Execute();

    }

    catch

    {

        return htmlTag;

    }

    return TagCommand.MAMLTag;

}

 

Workflow - separation of concerns

by 13. October 2008 02:02

I'm enjoying workflow emmensely, I particularly like that we're forced to code in a manner that has us focus on the concerns of the Activity's Use Case.

For example the TagProcessorActivity and ElementProcessorActivity represented below:

Each of the above activities (pointed to by arrows) have a CodeActivity, SetCurrentElementCode and HtmlTagCode respectively; these code activities have a sole purpose in life.   The HtmlTag's purpose is to update/set the MAMLTag property to the value returned by the ProcessorService (service is set in SequenceActivityBase via Unity container).

The TagProcessorActivity (executes first) has the sole responsibility of setting the current element; the ReplicatorActivity provides us a CurrentIndex to notify us of our position in the Replicator list.  The TagProcessorActivity uses a method on our DataState object (of type IMAMLState) to update our state object; an excerpt from the MAMLState class follows:

/// <summary>

/// Sets the current element.

/// </summary>

/// <param name="activity">The activity.</param>

/// <returns></returns>

public ElementEnt SetCurrentElement(Activity activity)

{

    if (activity == null || activity.Parent ==null)

        return null;

    if (!(activity.Parent.Parent != null

            && activity.Parent.Parent is ReplicatorActivity))

        return null;

 

    ReplicatorActivity grandParent =

        activity.Parent.Parent as ReplicatorActivity;

    ElementBeingProcessed = grandParent.CurrentIndex;

    CurrentElement = (ElementEnt)

        grandParent.InitialChildData[grandParent.CurrentIndex];

    return CurrentElement;

}

Note: the [Sequence]ActivityBase is responsible for setting up the Activity so that the state is available; an excerpt from the ActivityBase follows:

protected override void OnActivityExecutionContextLoad(IServiceProvider provider)

{

    IWFState<IMAMLState> State;

    base.OnActivityExecutionContextLoad(provider);

    State = provider

        .GetService(typeof(IWFState<IMAMLState>)) as IWFState<IMAMLState>;

    Logger = State.UnityContainer.Resolve<ILoggerFacade>();

    ProcessorService = State.UnityContainer.Resolve<ITagProcessorService>();

    DataState = State.Data;

 

    WireupActivity(this);

}

 

At each level of processing there is a clear, testable separation of concern.

 

Source code available at http://www.Codeplex.com/MAMLConverter


 

Unity - a Workflow Trojan Horse

by 11. October 2008 00:40

Workflow is very powerful but I felt crippled without the Unity Container that I've come to depend on heavily in any application, no matter how large or small.   Case in point a new utility I'm working on to convert HTML to MAML so that I can take advantage of Sandcastles Help File Builder's  ConceptualContent which consist of MAML formated help files (no HTML).  Workflow seems optimal for this purpose.  The first requirement is (was) to plug in a Unity Container.

Workflow does offer the ability to register services that can be accessed from within activities, all that is required is to set an ExternalDataExchange attribute on your interface:

[ExternalDataExchange]

public interface IWFState<T>

{

    T Data { get; set; }

    IUnityContainer UnityContainer { get; set; }

    ILoggerFacade Logger { get; set; }

    void WireupActivity(Activity activity);

}

Then you load the service

public IWFState<T> State

{

    get { return _state; }

    set

    {

        _state = value;

        OnStateSet();

    }

}
/// <summary>

/// Loads the local services.

/// </summary>

public virtual void LoadLocalServices()

{

    ExternalDataExchangeService localServices = 
         new ExternalDataExchangeService();

    AddService(localServices);

    localServices.AddService(State);

}

 

However, this requires a redundant registration process (since I've already registered services with Unity).   I decided to use Unity as a trojan horse; I'll load one service, my state object which contains my UnityContainer, and then use my existing services via a UnityContainer property.  Important note:  some activities, i.e., Replicator and While will have to serialize referenced objects; any interfaces that Unity has to resolve in these activities will have to have [Serializable] attributes;

This permits my Activity to look as follows (ActivityBase has a UnityContainer property that returns State.UnityContainer):

namespace MAMLConvert.Activities.Logger

{

    /// <summary>

    /// Debug Logger

    /// </summary>

    public partial class LoggerDebugActivity : ActivityBase

  {

    public LoggerDebugActivity()

    {

      InitializeComponent();

    }

        protected override ActivityExecutionStatus

            Execute(ActivityExecutionContext executionContext)

        {

            UnityContainer.Resolve<ILoggerFacade>().Log(

                "Logging via Unity in the Activity!",

                    Category.Debug, Priority.None);

 

            return base.Execute(executionContext);

        }

  }

}

/// <summary>

/// Tests the workflow base ensure args is set on empty constructor.

/// </summary>

[TestMethod]

public void TestMAMLWorkflowBaseStartsAssignedWorkflow()

{

    using (MAMLWorkflowRuntime wfrt = new MAMLWorkflowRuntime())

    {

        Assert.IsNotNull(wfrt.Container);

        Assert.IsTrue(wfrt.Args.Count > 0, 
               "Should contain at least a UnityContainer");

        Assert.AreEqual("Initialized", wfrt.State.Data.MockInfo);

        Assert.AreEqual(wfrt.State.Logger.GetType().FullName,

            MockContainer.Resolve<ILoggerFacade>().GetType().FullName);

 

        wfrt.Start(typeof(HtmlToMAML));

    }

}

 

The above unit test yields the following results: 

 

Debug(None): !! ACTIVITY WIREUP loggerDebug
Debug(None): !! ACTIVITY WIREUP loggerTrace
Debug(None): !! ACTIVITY WIREUP loggerMessageBox
Debug(None): !! ACTIVITY WIREUP loggerEmail
Debug(None): !! ACTIVITY WIREUP Logger
Debug(None): ==> Logger STATUS CHANGE - Status: Executing  Result: None
Debug(None): ==> Logger EXECUTING:
Debug(None): ==> loggerDebug STATUS CHANGE - Status: Executing  Result: None
Debug(None): ==> loggerDebug EXECUTING:
Debug(None): Logging via Unity in the Activity!
Debug(None): ==> loggerDebug STATUS CHANGE - Status: Closed  Result: Succeeded
Debug(None): ==> loggerDebug CLOSED:
Debug(None): ==> Logger STATUS CHANGE - Status: Closed  Result: Succeeded
Debug(None): ==> Logger CLOSED:

 

Source code available at http://www.CodePlex.com/MAMLConverter
 

Notice

Blog videos and references to CodePlex projects are no longer valid