ASP.NET MVC 2 - Passing Parameters to Silverlight application

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


Tags: , , ,
Categories: Unity


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

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

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.

 


Tags: , , , ,
Categories: Unity | Visual Studio 2010 | WPF


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

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

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.

 


Tags: , , , ,
Categories: Unity


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

CompositeWPF/Prism - Adding modules after BootStrapper


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


Tags: , ,
Categories: CompositeWPF | Unity


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

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

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: , ,
Categories: Unity


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

Integrating IIS WCF and Unity

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


Tags: ,
Categories: Unity


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

Unity - factory pattern and extensibility

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;

}

 


Tags: , ,
Categories: Unity


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

Workflow - separation of concerns

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


 


Tags: ,
Categories: Unity


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

Unity - a Workflow Trojan Horse

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
 


Tags: , ,
Categories: Unity


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

CompositeWPF - using "Module" configuration files for resolving types

By default the Unity configuration is expected to be in the main application's App.Config, however it can be configured to use external files.  Detailed information on how to do this is provided in the Unity Application Block - May 2008 documentation at the following location:

* Developing Applications Using the Unity Application Block
** Entering Configuration Information 

It is also available in examples provided in the Unity Unit Test project, specifically the ConfigurationSectionFixture.cs test fixture; there are plenty of configuration examples and test to show you how to load external configuration files.   An implementation of the above noted documentation (with source) is available below:

Within my ShellApp.Infrastructure (more about it HERE) I created a baseclass that will automatically load a modules configuration data; the config file must have the same name as the module, e.g. my VisioToolModule.cs module has a VisioToolModule.Config in the accompanying source code.

Most of the code was actually borrowed from the Unity Unit test referenced above; I only made minor changes so that the type's name is used (which will be the name of the class that inherits ModuleBase).

namespace ShellApp.Infrastructure.Base
{
    public class ModuleBase : IModule
    {
        protected IUnityContainer Container { get; set; }
        protected IRegionManager RegionManager { get; set; }

        public virtual void Initialize()
        {
            RegisterViewsAndServices();
        }

        protected virtual void RegisterViewsAndServices()
        {
            UnityConfigurationSection section = GetUnitySection();
            section.Containers[GetType().Name].Configure(Container);
        }

        protected UnityConfigurationSection GetUnitySection()
        {
            Configuration config = OpenConfigFile(GetType().Name);
            return (UnityConfigurationSection)config.GetSection("unity");
        }

        protected Configuration OpenConfigFile(string baseName)
        {
            ExeConfigurationFileMap map = new ExeConfigurationFileMap();
            map.ExeConfigFilename = baseName + ".config";
            return ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
        }

    }
}

With the ModuleBase class my module only has to execute a base.Initialize() to take advantage of the external configuration file autoload feature:

namespace ProcessSolutionModule
{
    public class VisioToolModule : ModuleBase
    {
        private ProcessSolutionViewPresenter _presenter;

        public VisioToolModule(IRegionManager regionManager, IUnityContainer container)
        {
            RegionManager = regionManager;
            Container = container;
        }

        public override void Initialize()
        {
            // Required to ensure VisioToolModule.Config is loaded
            base.Initialize();

            // Resolve our presenter
            _presenter = Container.Resolve<ProcessSolutionViewPresenter>();

            // Add view to region
            IRegion mainRegion = RegionManager.Regions[RegionNames.MainRegion];
            mainRegion.Add(_presenter.View);
        }
    }
}

The following is the VisioToolModule.Config external config file:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
  </configSections>

  <unity>
    <containers>
      <container name="VisioToolModule">
        <types>
          <type type="VisioTool.Controllers.IProcessSolutionController, VisioTool"
                mapTo="VisioTool.Controllers.ProcessSolutionController, VisioTool">
          </type>
          <type type="VisioTool.Services.IProcessSolutionService, VisioTool"
                mapTo="VisioTool.Services.ProcessSolutionService, VisioTool">
          </type>
          <type type="VisioTool.Views.IProcessSolutionView, VisioTool"
                mapTo="VisioTool.Views.ProcessSolutionView, VisioTool">
          </type>
        </types>
      </container>
    </containers>
  </unity>
</configuration>

In this drop of ShellApp I made some changes to the BootStrapper (in the Shell.Infrastructure).   The BootStrapper now calls a new AppModuleEnumerator class - it follows:

namespace ShellApp.Infrastructure.Common
{
    public class AppModuleEnumerator
    {
        public static IModuleEnumerator GetModules(Type type)
        {
            string path = new FileInfo(type.Assembly.Location).DirectoryName;
            return new DirectoryLookupModuleEnumerator(path);
        }
    }
}

The above class uses the CWPF's DirectoryLookupModuleEnumerator() to load modules. It is provided the path for the current type's assembly which allows the BootStrapper to simply send GetType() as a parameter to load any modules that the application has a reference to - the BootStrapper updates follow:

using System.Windows;
using Microsoft.Practices.Composite.UnityExtensions;
using Microsoft.Practices.Composite.Modularity;
using Microsoft.Practices.Unity;
using EventBrokerExtension;
using System;
using ShellApp.Infrastructure.Common;

namespace Shell.Infrastructure
{
    public class BootStrapper : UnityBootstrapper
    {
        public delegate DependencyObject ShellCreationDelegate(IUnityContainer container);
        public delegate IModuleEnumerator GetModuleEnumeratorDelegate();

        private Type _moduleType;
        private ShellCreationDelegate _createShell;
        private GetModuleEnumeratorDelegate _getModules;

        /// <summary>
        /// OVERLOADED:
        /// We want to decouple our bootstrapper from the calling
        /// application so we can reuse it.
        /// </summary>
        /// <param name="createShell"></param>
        /// <param name="getModules"></param>
        public BootStrapper(ShellCreationDelegate createShell, GetModuleEnumeratorDelegate getModules)
        {
            _createShell = createShell;
            _getModules = getModules;
        }

        /// <summary>
        /// OVERLOADED:
        /// If "type" is provided as second parameter then the
        /// type's assembly directory will be used to load modules
        /// from via GetModuleEnumeratorDirectory below
        /// </summary>
        /// <param name="createShell"></param>
        /// <param name="type"></param>
        public BootStrapper(ShellCreationDelegate createShell, Type type)
        {
            _createShell = createShell;
            _moduleType = type;
            _getModules = GetModuleEnumeratorDirectory;
        }

        protected override DependencyObject CreateShell()
        {
            Container.AddNewExtension<SimpleEventBrokerExtension>();
            return _createShell(Container);
        }

        protected override IModuleEnumerator GetModuleEnumerator()
        {
            return _getModules();
        }

        protected IModuleEnumerator GetModuleEnumeratorDirectory()
        {
            return AppModuleEnumerator.GetModules(_moduleType);
        }
    }
}
    


The App.xaml.cs file was revised to use the newly overloaded BootStrapper constructor as follows:

namespace ShellApp
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        /// <summary>
        /// Load application
        /// </summary>
        public App()
        {
            // Bootstrapper is in the Shell.Infrastructure
            // project which can be shared by multiple solutions.
            BootStrapper bootStrapper = new BootStrapper(CreateShell, GetType());
            bootStrapper.Run();
        }
        protected DependencyObject CreateShell(IUnityContainer container)
        {
            // Launch our shell
            Shell shell = container.Resolve<Shell>();
            shell.Show();
            return shell;
        } 
    }
}

Source code: ShellApp.zip (2.30 mb)

 


Tags: , , ,
Categories: Unity


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know