Export (0) Print
Expand All

Modularity QuickStarts for WPF

The following QuickStarts are included in this topic:

  • Modularity (Configuration) QuickStart. This QuickStart demonstrates how to dynamically load modules using a configuration-based module enumerator. This module enumerator determines what modules should be loaded by reading a configuration section in the application's configuration file.
  • Modularity (DirectoryLookup) QuickStart. This QuickStart demonstrates how to dynamically load modules using a directory lookup module enumerator. This module enumerator discovers modules by inspecting assemblies in a particular folder.

Scenario

Ff921068.note(en-us,PandP.20).gifNote:
The scenario is the same for both Modularity QuickStarts.

The QuickStarts are composed of four modules: ModuleA, ModuleB, ModuleC, and ModuleD. These modules are dynamically loaded; this means that the shell does not contain a direct reference to the modules' assemblies; because of this, modules have to be discovered and loaded at run time.

Modules can have dependencies between them. In the QuickStarts, ModuleA depends on ModuleD, and ModuleD depends on ModuleB. Therefore, ModuleD needs to be loaded before ModuleA, and ModuleB needs to be loaded before ModuleD.

A module can also be loaded on demand. This means that the module does not need to be loaded when the application starts; instead, it can be loaded when a particular event during the application life occurs. In the Modularity QuickStarts, ModuleC is loaded on demand when the user clicks a button in a view exposed by ModuleB.

Figure 1 illustrates the main window for the QuickStarts (both QuickStarts share the same user interface).

Ff921068.ea5e7b58-db1b-420b-828a-a253abcbedd5(en-us,PandP.20).png

Figure 1

Modularity QuickStarts' user interface

Building and Running the QuickStarts

The QuickStarts ship as source code, which means you must compile them before running them. These QuickStarts do not have any prerequisites.

To build and run the Modularity (Configuration) QuickStart

  1. In Visual Studio, open the solution file \Quickstarts\Modularity\ConfigurationModularity\ConfigurationModularity.sln.
  2. Right-click the ConfigurationModularity project, and then click Set as StartUp Project.
  3. On the Build menu, click Rebuild Solution.
  4. Press F5 to run the QuickStart.

To build and run the Modularity (DirectoryLookup) QuickStart

  1. In Visual Studio, open the solution file Quickstarts\Modularity\DirectoryLookupModularity\DirectoryLookupModularity.sln.
  2. Right-click the DirectoryLookupModularity project, and then click Set as StartUp Project.
  3. On the Build menu, click Rebuild Solution.
  4. Press F5 to run the QuickStart.

Walkthrough

Perform the following steps in any of the Modularity QuickStarts for WPF to explore the scenario.

To explore the scenario

  1. In Visual Studio, open one of the provided solution files:
    • \Quickstarts\Modularity\ConfigurationModularity\ConfigurationModularity.sln. This is the solution file for the Modularity (Configuration) QuickStart.
    • Quickstarts\Modularity\DirectoryLookupModularity\DirectoryLookupModularity.sln. This is the solution file for the Modularity (DirectoryLookup) QuickStart.
    Ff921068.note(en-us,PandP.20).gifNote:
    The walkthrough for both QuickStarts is equivalent; the QuickStarts take the same inputs and produce the same output. The only difference between them is the module definition mechanism that is used to generate the module catalog.

  2. On the Build menu, click Rebuild Solution.
  3. Press F5 to run the application. The main window shows a stack of views, each of which is loaded by a different module, as illustrated in Figure 2. Note that ModuleB's view includes a button to load the ModuleC.

    Ff921068.66803d15-018b-4669-9841-3efd0c779a55(en-us,PandP.20).png

    Figure 2

    QuickStart main window

    The order in which views appear in the window reflects the modules load order. The load order is determined by the dependencies between modules.

  4. Click the Load Module C button to load ModuleC. When ModuleC loads, it adds a view to the window, as shown in Figure 3.

    Ff921068.52ff5bb8-1d2b-47ab-aa07-e11310f4a6c6(en-us,PandP.20).png

    Figure 3

    When the Load Module C button is clicked, ModuleC loads

Implementation Details

The QuickStarts highlight the key components in dynamic modularity. The following sections describe the key artifacts of each QuickStart.

Modularity (Configuration) QuickStart for WPF

The Modularity (Configuration) QuickStart for WPF leverages the usage of the configuration module loading mechanism. This mechanism discovers modules by reading the application's configuration file.

Module Catalog Setup

The Bootstrapper class inherits from the UnityBootstrapper abstract class. The UnityBootstrapper class has methods that create and configure the Unity container, configure the region adapters, create the shell and initialize the modules.

Ff921068.note(en-us,PandP.20).gifNote:
Module retrieval and module initialization is automatically handled by the bootstrapper's InitializeModules base method. When customization is needed, the InitializeModules method can be overridden to adjust it to your needs.

The GetModuleCatalog template method of the UnityBootstrapper class has to be overridden to return a module catalog; the module catalog stores metadata about the modules that compose the application. These modules will be loaded and initialized.

In the GetModuleCatalog method, create an instance of the ConfigurationModuleCatalog class and return it.

The ConfigurationModuleCatalog catalog will be automatically populated with modules based on the configuration stored in the App.config file.

The following code shows the overridden method GetModuleCatalog where the ConfigurationModuleCatalog instance is set up.

protected override IModuleCatalog GetModuleCatalog()
{
    ModuleCatalog catalog = new ConfigurationModuleCatalog();
    return catalog;
}

Modules Configuration

When using the configuration module loading mechanism, modules are configured in the application's configuration file. The following code shows the application's configuration file (located at ConfigurationModularity\App.config).

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="modules" type="Microsoft.Practices.Composite.Modularity.ModulesConfigurationSection, Microsoft.Practices.Composite.Desktop"/>
  </configSections>
  <modules>
    <module assemblyFile="Modules/ModuleD.dll" moduleType="ModuleD.ModuleD, ModuleD" moduleName="ModuleD">
      <dependencies>
        <dependency moduleName="ModuleB"/>
      </dependencies>
    </module>
    <module assemblyFile="Modules/ModuleB.dll" moduleType="ModuleB.ModuleB, ModuleB" moduleName="ModuleB"/>
    <module assemblyFile="Modules/ModuleA.dll" moduleType="ModuleA.ModuleA, ModuleA" moduleName="ModuleA">
      <dependencies>
        <dependency moduleName="ModuleD"/>
      </dependencies>
    </module>
    <module assemblyFile="Modules/ModuleC.dll" moduleType="ModuleC.ModuleC, ModuleC" moduleName="ModuleC" InitializeMode="OnDemand"/>
  </modules>
</configuration>

In the preceding code, four modules are configured in the modules section: ModuleA, ModuleB, ModuleC, and ModuleD. Note that modules ModuleD and ModuleA define dependencies on ModuleB and ModuleD, respectively, using the dependencies node.

This QuickStart has post-build events configured on each module project to automatically store the modules' assemblies in a folder after a successful build. A common folder for modules is recommended to simplify the application deployment. To see the post-build events configuration, right-click a module project, and then click Properties. In the Properties dialog box, click the Build Events tab. The following code shows the post-build event command in the Post-build event command line text box.

xcopy "$(TargetDir)*.*" "$(SolutionDir)ConfigurationModularity\bin\$(ConfigurationName)\Modules\" /Y

Loading Modules on Demand

This QuickStart demonstrates how to load a module on demand. A module is loaded on demand in reaction to an event during the application life cycle, instead of being loaded on application startup. In this QuickStart, the module ModuleC is configured to be loaded on demand.

The following code shows the module XML element for ModuleC in the application's configuration file (located at ConfigurationModularity\App.config). In this case, the startupLoaded attribute is set to false. This indicates the module should not be loaded on startup.

<module assemblyFile="Modules/ModuleC.dll" moduleType="ModuleC.ModuleC" moduleName="ModuleC" InitializeMode="OnDemand"/>

To load a module on demand, get an instance of the ModuleManager class, and then load the module by invoking the LoadModule method on that module manager service instance, passing the module name as a parameter.

The following code shows the DefaultViewB view implementation (located at ModuleB\DefaultViewB.xaml.cs), which exposes a button to load the ModuleC module on demand. The OnLoadModuleCClick method in the following code is the event handler for the click event of the button; it is in charge of loading the ModuleC module.

public partial class DefaultViewB : UserControl
{
    private readonly IModuleManager moduleManager;

    public DefaultViewB(IModuleManager moduleManager)
    {
        this.moduleManager = moduleManager;
        InitializeComponent();
    }

    private void OnLoadModuleCClick(object sender, RoutedEventArgs e)
    {
        moduleManager.LoadModule("ModuleC");
    }
}
Ff921068.note(en-us,PandP.20).gifNote:
Because the view only contains a reference to the IModuleManager interface to load modules, the preceding code is valid for both Modularity QuickStarts for WPF.

Modularity (DirectoryLookup) QuickStart for WPF

The Dynamic Modularity (DirectoryLookup) QuickStart for WPF leverages the usage of the directory lookup module loading mechanism. This mechanism discovers modules by inspecting module assemblies in a folder.

Module Catalog Setup

The Bootstrapper class inherits from the UnityBootstrapper abstract class. The UnityBootstrapper class has methods that create and configure the Unity container, configure the region adapters, create the shell, and initialize the modules.

Ff921068.note(en-us,PandP.20).gifNote:
Module retrieval and module initialization is automatically handled by the bootstrapper's InitializeModules base method. When customization is needed, the InitializeModules method can be overridden to adjust it to your needs.

The GetModuleCatalog template method of the UnityBootstrapper class has to be overridden to specify the module catalog that will be used to load and initialize modules.

The module catalog will be generated based on all the assemblies located in a particular folder. To do this, create a new instance of the DirectoryModuleCatalog catalog; and sets the ModulePath property of the instance to the folder path where all the module assemblies will be stored. The provided folder must be the same as the one configured in the post-build event of each module project. For more information, see the section "Module Configuration" later in this topic.

The DirectoryModuleCatalog catalog is responsible for discovering modules in a particular folder and auto-populating itself with them. By returning the instance, the base class will register it with the Unity container.

The following code shows the overridden method GetModuleCatalog method. This method is invoked when the application starts; it also demonstrates how the DirectoryModuleCatalog class is set up to look for modules in the \Modules folder.

protected override IModuleCatalog GetModuleCatalog()
{
    return new DirectoryModuleCatalog() {ModulePath = @".\Modules"};
} 

Modules Configuration

Because this QuickStart uses the directory lookup mechanism, modules classes—classes that implement the IModule interface—have the Module attribute applied. The following code shows the class signature for ModuleA's module class.

[Module(ModuleName = "ModuleA")]
[ModuleDependency("ModuleD")]
public class ModuleA : IModule
{
    ...
}

As described in the section "Module Catalog Setup" earlier in this topic, the directory lookup enumerator is configured to look for modules in the Modules folder. To automatically have the modules' assemblies in this folder after a successful build, module projects have a post-build event configured. To see the post-build events configuration, right-click a module project, and then click Properties. In the Properties dialog box, click the Build Events tab. The following code shows the post-build event command in the Post-build event command line text box.

xcopy "$(TargetDir)*.*" "$(SolutionDir)DirectoryLookupModularity\bin\$(ConfigurationName)\Modules\" /Y

Loading Modules on Demand

This QuickStart demonstrates how to load a module on demand. A module is loaded on demand in reaction to an event during the application life cycle, instead of being loaded on application startup. In this QuickStart, the module ModuleC is configured to be loaded on demand.

The following code shows the module class for ModuleC (located at ModuleC\ModuleC.cs). In this case, the Module attribute has the property OnDemand set to true. This indicates the module should not be loaded on startup.

[Module(ModuleName = "ModuleC", OnDemand = true)]
public class ModuleC : IModule
{
    ...
}

The following code shows the DefaultViewB view implementation (located at ModuleB\DefaultViewB.xaml.cs), which exposes a button to load the ModuleC module on demand. The OnLoadModuleCClick method in the following code is the event handler for the click event of the button; it is in charge of loading the ModuleC module.

public partial class DefaultViewB : UserControl
{
    private readonly IModuleManager moduleManager;

    public DefaultViewB(IModuleManager moduleManager)
    {
        this.moduleManager = moduleManager;
        InitializeComponent();
    }

    private void OnLoadModuleCClick(object sender, RoutedEventArgs e)
    {
        this.moduleManager.LoadModule("ModuleC");
    }
}
Ff921068.note(en-us,PandP.20).gifNote:
Because the view contains only a reference to the IModuleManager interface to load modules, the preceding code is valid for both Modularity QuickStarts for WPF.

Acceptance Tests

The Modularity QuickStarts for WPF include a separate solution that includes acceptance tests for both QuickStarts. Acceptance tests describe how an application should perform when you follow a series of steps; you can use the acceptance tests to explore the functional behavior of the applications in a variety of scenarios.

The acceptance tests were developed using the testing framework White. To run these tests, you need to have White installed. For more information about White, including download information, see White on CodePlex.

Ff921068.note(en-us,PandP.20).gifNote:
The acceptance tests have been developed and verified with the White 0.1.5.0 release. Although other releases of White might work, it is recommended to use this release to avoid any issues when running the tests.

To run the Modularity QuickStarts for WPF acceptance tests

  1. Place the assemblies required by White in the folder Source\Lib\White. The files are the following:
    • Bricks.dll
    • Bricks.RuntimeFramework.dll
    • Castle.Core.dll
    • Castle.DynamicProxy2.dll
    • Core.dll
    • log4net.config
    • log4net.dll
    • nunit.framework.dll
    • White.NUnit.dll
    • Xstream.Core.dll
  2. In Visual Studio, open the solution file Quickstarts\Modularity\Modularity.Tests.AcceptanceTest\ Modularity.Tests.AcceptanceTest.sln.
  3. Press F5.

Outcome

You should see the QuickStarts windows and the tests automatically interact with the user interface. At the end of the test pass, you should see that all tests have passed.

More Information

To learn about other QuickStarts included with the Composite Application Guidance, see the following topics:


Home page on MSDN | Community site

Show:
© 2014 Microsoft