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;
}

ASP.NET MVC2 Framework and Unity Dependency Injection Container

by 11. August 2009 01:48

SOURCE CODE AVAILABLE HERE

As always the new Microsoft Technologies keep rolling out the door; each one making the prior obsolete because the new technologies keep making things easier and easier.

Having been bogged down by the CompositeWPF/PRISM and ISO-15926 (on the international development team) I had no room on even my backburner for MVC - at least until now :)

As with every technology, if I can't use Dependency Injection (more specifically Unity) right out of the box then this is the first thing I must do before moving forward - MVC was no different.  

Unfortunately the existing blogs, such as David Hadens (which I found instrumental in completing my objectives) were out of date.  MVC2 will pull the rug out from under these blogs because the IControllerFactory interface for CreateController no longer provides a "type" - it provides a "string" which will simply hold the controllerName; not as easy to work with.

public interface IControllerFactory
{
    IController CreateController(RequestContext requestContext, 
                                 string controllerName);
    void ReleaseController(IController controller);
}

Since the currently documented methods won't work and I'll want to ensure maximum backwards compatibility (now and in the future) I decided to take the Unity Interception route.    I will get the current factory (line 7/8) and register it as an instance (line 13) so that later when we Resolve IControllerFactory in the CustomControllerFactory (line 14) it will be wrapped as required for interception.   Notice that we also register a named IControllerFactory so that we can resolve it to specify it as the new ControllerFactory (line 31).

GlobalBase.cs in MVCContrib\Base
    1 /// <summary>
    2 /// Initializes the ControllerFactory interception.
    3 /// </summary>
    4 private void InitializeInterception()
    5 {
    6     // Get a reference to the current controller factory
    7     IControllerFactory factory =
    8         ControllerBuilder.Current.GetControllerFactory();
    9 
   10     // Configure Interception - note we register an instance of
   11     // the factory so that we can retrieve it in CustomerControllerFactory
   12     Container.AddNewExtension<Interception>()
   13         .RegisterInstance<IControllerFactory>(factory)
   14         .RegisterType<IControllerFactory,CustomControllerFactory>("Custom")
   15         .Configure<Interception>()
   16         .AddPolicy("ControllerPolicy")
   17         .AddMatchingRule(Container.Resolve<ControllerMatchingRule>())
   18         .AddCallHandler<ControllerCallHandler>();
   19 
   20     // Use Interface Interceptor
   21     Container.Configure<Interception>()
   22         .SetInterceptorFor<IControllerFactory>(new InterfaceInterceptor());
   23 
   24     // Now we'll need the factory reference (resolved by Unity) because 
   25     // it will be wrapped as required for interception
   26     IControllerFactory unityFactory = 
   27         Container.Resolve<IControllerFactory>("Custom");
   28 
   29     // Set the new ControllerFactory to the resolved factory 
   30     // which will be configured for interception
   31     ControllerBuilder.Current.SetControllerFactory(unityFactory);
  32 }

As noted above, in our CustomControllerFactory class we'll resolve the "Original" IControllerFactory (which will be wrapped for interception) and execute the CreateController(requestContext, controllerName) on it - we let MVC2 handle processing as designed.

CustomControllerFactory.cs in MVCContrib\Factories
    1 public IController CreateController(RequestContext requestContext, string controllerName)
    2 {
    3 
    4     Logger.Log("BEFORE CREATE:: CustomControllerFactory.CreateController()", 
    5         Category.Debug, Priority.None);
    6 
    7     // IControllerFactory without name will return the original 
    8     // ControllerFactory.  We're going going to let it do it's job
    9     // and get a reference to the controller.
   10     IController controller = Container.Resolve<IControllerFactory>()
   11         .CreateController(requestContext, controllerName);
   12 
   13     Logger.Log(string.Format("AFTER CREATE:: CustomControllerFactory.CreateController() CREATED [{0}]", 
   14         controller.GetType().Name), Category.Debug, Priority.None);
   15 
   16     return controller;
   17 }

Now we can let our configured ControllerCallHandler Intercept the CreateController() method - we let it execute and upon return have a reference to our controller (line 19).   With the reference we set the Container property (to a child container)

    1 public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    2 {
    3     IMethodReturn msg;
    4     try
    5     {
    6         Logger.Log(string.Format("BEFORE::ControllerCallHandler.Invoke for {0}",
    7             input.Target.GetType().Name), 
    8             Category.Debug, Priority.None);
    9 
   10         msg = getNext()(input, getNext);
   11 
   12         // Create child container for each
   13         IUnityContainer childContainer = Container.CreateChildContainer();
   14 
   15         // If the controller is being handled by MVCContrib - implements IControllerBase
   16         // then we'll set the Container.  Attempts to do a BuildUp here do not work as
   17         // expected so the Container Setter is expected to perform a Container.Buildup(this)
   18         // See Base\ControllerBase Container setter for details
   19         if (msg.ReturnValue is IControllerBase)
   20             ((IControllerBase)msg.ReturnValue).Container = childContainer;
   21 
   22         Logger.Log(string.Format("AFTER::ControllerCallHandler.Invoke for {0}",
   23             input.Target.GetType().Name),
   24             Category.Debug, Priority.None);
   25 
   26     }
   27     catch (Exception ex)
   28     {
   29         msg = input.CreateExceptionMethodReturn(ex);
   30     }
   31 
   32     return msg;
   33 }

The ControllerBase (which controllers will derive from) will wire-up the controller - the Container setter code follows:

public IUnityContainer Container
{
    get { return _container; }
    set
    {
        // Don't set if already set
        if (_container != null && _container.GetType().ToString() == value.GetType().ToString())
            return;
 
        _container = value;
 
        // Buildup of MVCControllerBase so that we can
        // have logger and future types
        value.BuildUp(this);
 
        // We'll have a Logger now that this is built up.
        Logger.Log("ControllerBase::Container (setter) -- Performing Buildup of " + GetType().Name,
            Category.Debug, Priority.None);
 
        // The type will be that of the derived class.
        // BuildUp of the parent controller
        value.BuildUp(GetType(), this);
 
        // Notify controller
        OnContainerSet();
    }
}

With the internals covered I'll move on to my primary objective - Extensibility. I created my MVCContrib project with the notion that minimal code changes will be required to implement Unity in my ASP.NET MVC2 projects.  

Starting with the Global.ascx.cs file you'll find we derive from GlobalBase.  We'll override the virtual methods (letting the base handle some wire-up) and for the most part keep the Global.ascx.cs file intact.  Note how we subscribe to the OnApplicationStart event. 

namespace MvcApplication2
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801
 
    /// <summary>
    /// MVC Application
    /// </summary>
    public class MvcApplication : GlobalBase 
    {
        public static bool IsLoaded { get; set; }
 
        /// <summary>
        /// Initializes a new instance of the <see cref="MvcApplication"/> class.
        /// </summary>
        public MvcApplication()
        {
            if (!IsLoaded)
            {   // Ensure we only do this once
                this.OnApplicationStart += 
                    new EventHandler<EventArgs>(MvcApplication_OnApplicationStart);
                IsLoaded = true;
            }
        }
 
        /// <summary>
        /// Handles the OnApplicationStart event of the MvcApplication control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing 
        /// the event data.</param>
        void MvcApplication_OnApplicationStart(object sender, EventArgs e)
        {
            Logger.Log("OnApplicationStart", Category.Debug, Priority.None);
 
            RegisterRoutes(RouteTable.Routes);
        }
 
        /// <summary>
        /// Registers the routes.
        /// </summary>
        /// <param name="routes">The routes.</param>
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 
            routes.MapRoute(
                "Default",                                             
                "{controller}/{action}/{id}",                          
                new { controller = "Home", action = "Index", id = "" } 
            );
 
        }
 
        /// <summary>
        /// Hook into InitializeContainer
        /// </summary>
        protected override void OnInitializeContainer()
        {
            Logger.Log("OnInitalizeContainer ", Category.Debug, Priority.None);
 
            // Configures container in class external to Global.asax.cs
            // (see Container folder)
            ContainerInitialize initContainer = 
                Container.Resolve<ContainerInitialize>();
            initContainer.InitializeContainer();
        }
    }
}

In my HomeController.cs you'll find that all I really needed to do is derive from MVVCControllerBase.  When I click on the HOME link the logger reveals the following processing - note how the EventAggregator (published by service) was handled (in bold): 

Debug(None): BEFORE CREATE:: CustomControllerFactory.CreateController()
Debug(None): ControllerMatchingRule.Matches(member=[System.Web.Mvc.IControllerFactory])
Debug(None): ControllerMatchingRule.Matches(member=[System.Web.Mvc.IControllerFactory])
Debug(None): BEFORE::ControllerCallHandler.Invoke for Wrapped_IControllerFactory_0fb5a472127c4b4b932425e809665c62
DEBUG: HomeController:CTOR
Debug(None): ControllerBase::Container (setter) -- Performing Buildup of HomeController
Debug(None): HomeController::OnContainerSet()
Debug(None): AFTER::ControllerCallHandler.Invoke for Wrapped_IControllerFactory_0fb5a472127c4b4b932425e809665c62
Debug(None): AFTER CREATE:: CustomControllerFactory.CreateController() CREATED [HomeController]
Debug(High): CONTROLLER:HomeController  -- Index() 
 
Debug(None): HomeController.DataServiceHandler STATUS = [3 Records sent]
 
Debug(None): PresentationModel.Clients updated with 3 records
Debug(None): ControllerMatchingRule.Matches(member=[System.Web.Mvc.IControllerFactory])
Debug(None): ControllerMatchingRule.Matches(member=[System.Web.Mvc.IControllerFactory])
Debug(None): BEFORE::ControllerCallHandler.Invoke for Wrapped_IControllerFactory_0fb5a472127c4b4b932425e809665c62
Debug(None): AFTER::ControllerCallHandler.Invoke for Wrapped_IControllerFactory_0fb5a472127c4b4b932425e809665c62
Debug(None): CustomControllerFactory.ReleaseController() RELEASED [HomeController]
 
 
HomeController.cs in MVCApplication2\Controllers
 
namespace MvcApplication2.Controllers
{
[HandleError]
public class HomeController : MVCControllerBase
{
    public HomeController()
    {
        Debug.WriteLine("HomeController:CTOR", "DEBUG");
    }
 
    [Dependency]
    public IDataService service { get; set; }
 
    [Dependency]
    public IPresentationModel model { get; set; }
 
    [Dependency]
    public IEventAggregator Aggregator { get; set; }
 
    [Dependency]
    public IAggregatorEventTokens Tokens { get; set; }
 
    /// <summary>
    /// We don't have constructor injection since we're using CustomControllerFactory
    /// so we'll rely on notification when the container is set.  This will be processed
    /// everytime a page is hit and our EventAggregator is a singleton so we'll have to
    /// ensure we only subscribe one time.
    /// </summary>
    protected override void OnContainerSet()
    {
 
        Logger.Log("HomeController::OnContainerSet()", Category.Debug, Priority.None);
 
        // GetTokens will only return null if key is not already set
        if (Tokens.GetToken(GetType().FullName) == null)
        {
            Logger.Log("HomeController::Subscribed to DataServiceEvent -- EVENT HANDLER",
                Category.Debug, Priority.None);
 
            // Subscribe to the DataServiceEvent
            SubscriptionToken token = Aggregator.GetEvent<DataServiceEvent>()
                .Subscribe(DataServiceHandler, ThreadOption.PublisherThread, true);
 
            // Set the token so we don't subscribe more than once
            Tokens.SetToken(GetType().FullName, token);
        }
    }
 
    public void DataServiceHandler(DataServiceEventArgs e)
    {
        Logger.Log(string.Format(
            "HomeController.DataServiceHandler STATUS = [{0}]", e.Status), 
            Category.Debug, Priority.None);
    }
 
    public ActionResult Index()
    {
        ViewData["Message"] = "Welcome to ASP.NET MVC!";
        Logger.Log("CONTROLLER:HomeController  -- Index() ", 
            Category.Debug, Priority.High);
 
        // Call the data service to get client list
        model.Clients = service.GetClients();
        return View();
    }
 
    public ActionResult About()
    {
        Logger.Log("CONTROLLER:HomeController  -- About()", 
            Category.Debug, Priority.High);
 
        ViewData["ModelClients"] = string.Format("There are {0} clients loaded!", 
            model.Clients.Count);
        return View();
    }
}
}

SOURCE CODE AVAILABLE HERE

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.

 

Prism/WCF - single configuration file for ASP.NET, Silverlight and WCF

by 18. February 2009 23:07

For a functional demo, with the following principals applied, see our http://www.CodePlex.com/SDMS project.

In a recent blog I noted issues with Prism/Silverlight, WCF and configuration files.  I have since resolved this issue and respond to a programmers question below.

Hi,

I've read your post about problems with wcf service reference and have a question about your solution.

What if i have different wcf services and have more than one ServiceReference.ClientConfig. It would be impossible to add them all as link to shell project.

See Related WEBCAST

I resolved my issues with configuration files by programmatically setting the Binding and Address – I now have “one” configuration file (Web.Config) that services my ASP.NET, Silverlight and WCF Service(s).    The following is my DoctorServiceDAL (Presentation Tier’s Data Layer); after I do an “Add Web Reference” or “Update Web Reference” I delete the configuration file (not required). 

        public DoctorServiceDAL(IUnityContainer container)
        {
            try
            {
                // Set container reference for class use
                Container = container; 

                IServerConfiguration config = container.Resolve<IServerConfiguration>(); 

                // Use basic HttpBinding on both Silverlight and Desktop
                BasicHttpBinding binding =
                    new BasicHttpBinding(BasicHttpSecurityMode.None); 

               binding.Name = "bndDoctorService"; 

                // Get the WebServiceURI from the unity container
                Uri baseAddress = new Uri(config.WebServiceURI); 

                EndpointAddress address = new EndpointAddress(baseAddress); 

                // Instantiate our service using configured data
                client = new wcf.DoctorServiceClient(binding, address); 

                // Subscribe to the Completed events.  The DSEAxxxxx classes that
                // will actually handle setting up the event argument (which will be
                // raised below) are in the Data project (for service references).
                client.GetProviderListCompleted += AsyncCompleted;
                client.GetConfigurationCompleted += AsyncCompleted; 

                // Note: be sure to update applicable modules, i.e., PatientModule.cs
                //       after updating the above to ensure DSEAxxxx can be resolved!
            }
            catch (Exception ex)
            {
                Error = ex;
            }
        }

        /// <summary>
        /// Requests the doctor list.  When list is available it will
        /// be directed to the AsyncCompleted event (subscribed to in
        /// the Constructor)
        /// </summary>
        /// <param name="doctorID">The doctor ID.</param>
        public void RequestProviderData(int doctorID)
        {
            client.GetProviderListAsync(doctorID);
        }

       
        /// <summary>
        /// Request the system configuration parameter string
        /// </summary>
        public void RequestConfigurationString()
        {
            client.GetConfigurationAsync();
        }

        /// <summary>
        /// Executes when async calls are completed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e"></param>
        /// instance containing the event data.</param>
        void AsyncCompleted(object sender, AsyncCompletedEventArgs e)
        {
            // All Async callbacks will end up here
            // prepare global event argument
            IDoctorServiceEventArgs args = new DoctorServiceEventArgs();

            // Retrieve the name of the process that just completed
            // and strip off the CompletedEventArgs
            string name = e.GetType().Name.Replace("CompletedEventArgs", "");

            try // Use Unity Container as a factory
            {
                // Resolve it - it must be configured in the Module(s) that
                // use this data layer (reference PatientModule.cs)
                args = Container.Resolve<IDoctorServiceEventArgs>(name);

                // Set the properties to the result
                args.SetArgProperties(e);
            }
            catch (Exception ex)
            {
                Error = new Exception(string.Format("{0} was not configured in {1} \r\n{2}{3}",
                    name, GetType().FullName, ex.Message, ex.StackTrace));
               
            }

            // If anyone is subscribing to the event (which they should be)
            // then raise the event with the data returned
            if (OnDoctorServiceEvent != null)
                OnDoctorServiceEvent(this, (DoctorServiceEventArgs) args);

        }
    }
 

My Default.aspx.cs, code-behind file, has the following which provides information I will need.   Note that I pass it into Xaml1 for Silverlight (read BLOG) and to my WCF Service DoctorServiceClient which is injected into the WCF unity container for successive use (related BLOG). 

    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            // Retrieve Connection String
            string connectionString =
                ConfigurationManager.ConnectionStrings["PRMS"].ConnectionString;

            // Retrieve Web Service URIs
            string webServiceURI_Dev =
                ConfigurationManager.AppSettings["WebServiceURI-DEV"];
            string webServiceURI_IIS =
                ConfigurationManager.AppSettings["WebServiceURI-IIS"]; 

            // Retrieve Web Service Path
            string webServicePath =
                Request.ApplicationPath == "/" ? webServiceURI_Dev : webServiceURI_IIS; 

            // Set InitParameters for Silverlight use
            Xaml1.InitParameters = string.Format(
                "InitParameters=" +
                "ServerURL=http://{0};" +
                "ServerPath={1};" +
                "ConnString={2};" +
                "WebServiceURI={3}",
                    Request.Url.Authority,
                    Server.MapPath("~"),
                    connectionString,
                    webServicePath); 

            // Send parameters to WCF Service for its use
            new DoctorServiceClient().SetConfiguration(Xaml1.InitParameters);
        }
    }


After the above code runs I can obtain my configuration information from anywhere in the application (ASP.NET, Silverlight or WCF) by resolving the IServerConfiguration. 

 IServerConfiguration config = container.Resolve<IServerConfiguration>();

Below is the class that implements IServerConfiguration and does the heaviy lifting, note that I provide a mechanism to strongly type the values stored in InitParam:

using Microsoft.Practices.Unity;
using System.Collections;
using System.Collections.Generic;
using System;
namespace Library.Interface.Configuration
{
    public class ServerConfiguration : AppBase, IServerConfiguration
    {
        private IDictionary<string, string> constructorParam;
        public IDictionary<string, string> InitParam { get; set; } 

        public ServerConfiguration(IUnityContainer container) : base(container)
        {
            try
            {
                InitParam = new Dictionary<string, string>();
                constructorParam = container.Resolve<IDictionary<string, string>>("InitParameters");
                string paraString = constructorParam["InitParameters"];
                string[] paraList = paraString.Split(';');
                foreach (string para in paraList)
                {
                    string[] keyValue = para.Split('=');
                    InitParam.Add(new
                        KeyValuePair<string, string>(keyValue[0], keyValue[1]));
                }
            }
            catch (Exception ex)
            {
                Error = ex;
            }
        } 

        public string WebServerURL
        {
            get { return InitParam["ServerURL"]; }
        }
        public string WebServerPath
        {
            get { return InitParam["ServerPath"]; }
        }
        public string WebServiceURI
        {
            get { return InitParam["WebServiceURI"]; }
        } 
    }
}

 

 

Passing Server information to Silverlight Client

by 12. January 2009 12:02

Get Source Here (upgraded to Feb 2009 release of CompositeWPF/Prism)

Uses the CompositeWPF/Prism, Unity and the PresentationModel

Many of us ASP.NET Developers are accustomed to querying our HttpContext.Current object for information about our environment, i.e., we can use it's Server.MapPath("~"); to find our current folder path.

The problem with Silverlight is that it isn't running on the Server - it is running on the client (users computer); it doesn't have access to the HttpContext object.   This can result in having to hardcode information in a configuration file.

We can communicate with the server via WCF services, but it comes with it's own burden of configuration files (created by "Add Web Service") which can become unmanagable quickly in an enterprise level application with 20+ modules.   In recent communications with the Silverlight WCF Services Team I was notified that this is an issue they hope to resolve in SL3 (within the context of providing a SvcUtil.exe for Silverlight).

There is a way we can easily pass information to our Silverlight modules without having to hit the server again - after all, it was the server that served up the page.

THE KEY POINT IN OUR DEMO IS NO CONFIGURATION FILE IS REQUIRED BY OUR MODULE 

The data flow for our server information follows (once data hits the Unity Container it will be available to all modules):

 

For our demo we are working with two property values

  1. ServerURL (http://...) 
  2. ServerPath (C:\..)

Within the context of the attached project, our website's Default.aspx code behind file will load the InitParameters dynamically as follows:

    public partial class _Default : System.Web.UI.Page

    {

        protected void Page_Load(object sender, EventArgs e)

        {

            Xaml1.InitParameters = string.Format(

                "InitParameters="+

                "ServerURL=http://{0};"+

                "ServerPath={1}",

                    Request.Url.Authority,

                    Server.MapPath("~"),

                    ClientQueryString);

        }

    }

 

InitParameters is available via the Silverlight object (defaults to ID=Xaml1 in the default.aspx)

 

<html xmlns="http://www.w3.org/1999/xhtml" style="height:100%;">

<head id="Head1" runat="server">

    <title>UnityContrib.Demo.Silverlight</title>

</head>

<body style="height:100%;margin:0;">

    <form id="form1" runat="server" style="height:100%;">

        <asp:ScriptManager ID="ScriptManager1"
                           runat="server"></asp:ScriptManager>

        <div  style="height:100%;">

            <asp:Silverlight ID="Xaml1"
                 runat="server"
                 Source="~/ClientBin/UnityContrib.Demo.Silverlight.xap"
                
 MinimumVersion="2.0.31005.0" Width="100%" Height="100%" />

        </div>

    </form>

</body>

</html>

The Application_Startup is passed in this value during application startup and assigned to the Bootstrappers.InitParams property:

    public partial class App : Application

    {

        private void Application_Startup(object sender, StartupEventArgs e)

        {

            //this.RootVisual = new Page();

            // Replace default page instantiation with bootstrapper

            Bootstrapper bootstrapper = new Bootstrapper();

            bootstrapper.InitParams = e.InitParams;

            bootstrapper.Run();

        }

When the bootStrapper.Run() command is executed, the BootStrapper's CreateShell() command is executed - it is overridden as shown so that we can load our shell (note that IConfigInfo is registered to use the ConfigInfo class - it processes the InitParameters for us):

protected override DependencyObject CreateShell()

{

    // Singletons

    Container

        .RegisterType<IAppBase, AppBase>

            (new ContainerControlledLifetimeManager())

        .RegisterType<IConfigInfo, ConfigInfo>

            (new ContainerControlledLifetimeManager()) ;

 

    Container.RegisterInstance<IDictionary<string,string>>

        ("InitParameters", InitParams);

 

    Shell shell = this.Container.Resolve<Shell>();

 

#if SILVERLIGHT

    Application.Current.RootVisual = shell;

#else

    shell.Show();

#endif

    return shell;

}

Once an instance of the parameters is registered with the Unity Container it will be available anywhere in the application via Dependency Injection.  We'll show all of the code that was required in the module to generate the following output:

PresentationModel:  (two properties)

public class UploadPresentationModel : ModelBase, IUploadPresentationModel

{

    private string _serverURL;

    public string ServerURL

    {

        get { return _serverURL; }

        set

        {

            _serverURL = value;

            OnPropertyChanged("ServerURL");

        }

    }

 

    private string _serverPath;

    public string ServerPath

    {

        get { return _serverPath; }

        set

        {

            _serverPath = value;

            OnPropertyChanged("ServerPath");

        }

    }

}

VIEW (binds to the ServerURL and ServerPath on it's model):

<UserControl x:Class="Module.Upload.Views.Main.MainView"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Width="400" Height="300">

 

    <Grid x:Name="LayoutRoot">

      <Grid.Background>

        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

          <GradientStop Color="#FFF8F5F5"/>

          <GradientStop Color="#FF1C6960" Offset="1"/>

        </LinearGradientBrush>

      </Grid.Background>

        <Grid.RowDefinitions>

            <RowDefinition Height="25"/>

            <RowDefinition/>

            <RowDefinition Height="25"/>

        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>

            <ColumnDefinition />

        </Grid.ColumnDefinitions>

 

        <TextBlock Text="{Binding ServerURL}" Margin="5"/>

        <TextBlock Text="{Binding ServerPath}" Grid.Row="1"/>

    </Grid>

</UserControl>

PRESENTER (uses dependency injection, i.e., IConfigInfo, to obtain configuration info):

public class MainViewPresenter : PresenterBase<IMainView>

{

    IAppBase app;

    IUploadPresentationModel uploadModel;

 

    public MainViewPresenter(

                IConfigInfo configInfo,

                IMainView view,

                IModelBase model,

                IAppBase app)

        // Assign the view and model instances (created by

        // dependency injection) and update base View and Model

        : base(view,model)

    {

        try

        {

            this.app = app;

 

            // Cast the model to this presenter's Model so we

            // can update the applicable properties

            uploadModel = (IUploadPresentationModel) model;

 

            // Update model to reflect current information

            uploadModel.ServerURL = configInfo.WebServerURL;

            uploadModel.ServerPath = configInfo.WebServerPath;

 

        }

        catch (Exception ex)

        {

            throw ex;

        }

    }

 

}

 

Finally - the ConfigInfo class that processes the InitParameters string in its constructor by obtaining an instance of Unity Container via dependency injection (constructor injection).  I will use this so that it can obtain the InitParameters value:

public class ConfigInfo : AppBase, IConfigInfo

{

    private IDictionary<string, string> constructorParam;

    public IDictionary<string, string> InitParam { get; set; }

 

    public ConfigInfo(IUnityContainer container)

    {

        try

        {

            // Instantiate our public Parameter collection

            InitParam = new Dictionary<string, string>();

 

            // Retrieve parameters (saved in Bootstrapper) and place

            // in temporary constructorParam variable

            constructorParam = container

                .Resolve<IDictionary<string, string>>("InitParameters");

 

            // Retrieve from constructorParam the InitParameters value

            // it will be a KeyNameValuePair format.  Split and assign

            // to InitParam public property

            string paraString = constructorParam["InitParameters"];

            string[] paraList = paraString.Split(';');

            foreach (string para in paraList)

            {

                string[] keyValue = para.Split('=');

                InitParam.Add(new

                    KeyValuePair<string, string>(keyValue[0], keyValue[1]));

            }

        }

        catch (Exception ex)

        {

            Error = ex;

        }

    }

 

    /// <summary>

    /// Centralize the retrieval of parameters for error trapping

    /// </summary>

    /// <param name="key"></param>

    /// <returns></returns>

    private string GetParameter(string key)

    {

        try

        {

            return InitParam[key];

        }

        catch (Exception ex)

        {

            Error = ex;

            return string.Empty;

        }

    }

 

    /// <summary>

    /// Web Server URL

    /// </summary>

    public string WebServerURL

    {

        get { return GetParameter("ServerURL"); }

    }

 

    /// <summary>

    /// Web Server Path

    /// </summary>

    public string WebServerPath

    {

        get { return GetParameter("ServerPath"); }

    }

}

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


 

Notice

Blog videos and references to CodePlex projects are no longer valid