Bootstrapper

The bootstrapper is responsible for the initialization of an application built using the Composite Application Library. By using a bootstrapper, you have more control of how the Composite Application Library components are wired up to your application. For example, if you have an existing application that you are adding the Composite Application Library to, you can initialize the bootstrapping process after the application is already running.

In a traditional Windows Presentation Foundation (WPF) application, a startup Uniform Resource Identifier (URI) is specified in the App.xaml file that launches the main window. In an application created with the Composite Application Library, it is the bootstrapper's responsibility to create the shell or the main window. This is because the shell relies on services, such as the Region Manager, that need to be registered before the shell can be displayed. Additionally, the shell may rely on other services that are injected into its constructor. For more information about the shell, see the Shell and View technical concept.

The Composite Application Library includes a default abstract UnityBootstrapper class that handles this initialization using the Unity container. Many of the methods on the UnityBootstrapper class are virtual methods. You should override these methods as appropriate in your own custom bootstrapper implementation. If you are using a container other than Unity, you should write your own container-specific bootstrapper.

Figure 1 illustrates the stages of the bootstrapping process.

Ff921139.d1a92ca9-e11c-4497-8645-3de0c484ce37(en-us,PandP.20).png

Figure 1

Bootstrapping process

Configuring the Container

Containers play a key role in an application created with the Composite Application Library. Both the Composite Application Library and the applications built on top of it depend on a container for injecting required dependencies. During the container configuration phase, several core services are registered, as shown in the following code from the UnityBootstrapper.

Note

An example of this is when a module registers module-level services in its Initialize method.

protected virtual void ConfigureContainer()
{
    …
    if (useDefaultConfiguration)
 {
    RegisterTypeIfMissing(typeof(IServiceLocator), typeof(UnityServiceLocatorAdapter), true);
    RegisterTypeIfMissing(typeof(IModuleInitializer), typeof(ModuleInitializer), true);
    RegisterTypeIfMissing(typeof(IModuleManager), typeof(ModuleManager), true);
    RegisterTypeIfMissing(typeof(RegionAdapterMappings), typeof(RegionAdapterMappings), true);
    RegisterTypeIfMissing(typeof(IRegionManager), typeof(RegionManager), true);
    RegisterTypeIfMissing(typeof(IEventAggregator), typeof(EventAggregator), true);
    RegisterTypeIfMissing(typeof(IRegionViewRegistry), typeof(RegionViewRegistry), true);
    RegisterTypeIfMissing(typeof(IRegionBehaviorFactory), typeof(RegionBehaviorFactory), true);
    }
}

The bootstrapper will determine whether a service has already been registered—it will not register it twice. This allows you to override the default registration through configuration. You can also turn off registering any services by default and disable services that you do not want to use, such as the event aggregator.

Note

If you turn off the default registration, you will need to manually register required services.

Configuring the RegionAdapter Mappings

During this phase, the default region adapter mappings are registered. These mappings are used by the region manager to associate the correct adapters for XAML-defined regions. By default, an ItemsControlRegionAdapter, a ContentControlRegionAdapter, and a SelectorRegionAdapter are registered. For more information about these adapters, see the UI Composition technical concept.

You can also override the ConfigureRegionAdapterMappings method to add your own custom region adapter mappings, as shown in the following code from the UnityBootstrapper.

protected virtual RegionAdapterMappings ConfigureRegionAdapterMappings()
{
    RegionAdapterMappings regionAdapterMappings = Container.TryResolve<RegionAdapterMappings>();
    if (regionAdapterMappings != null)
    {
#if SILVERLIGHT
        regionAdapterMappings.RegisterMapping(typeof(TabControl), this.Container.Resolve<TabControlRegionAdapter>());
#endif
        regionAdapterMappings.RegisterMapping(typeof(Selector), this.Container.Resolve<SelectorRegionAdapter>());
        regionAdapterMappings.RegisterMapping(typeof(ItemsControl), this.Container.Resolve<ItemsControlRegionAdapter>());
        regionAdapterMappings.RegisterMapping(typeof(ContentControl), this.Container.Resolve<ContentControlRegionAdapter>());
    }
    return regionAdapterMappings;
}

Note

Conditional compiling is used to register the TabControlRegionAdapter only for Silverlight. This is because when you add an item in a TabControl control in WPF, this item is wrapped inside a TabItem type. This is not applicable for Silverlight, where you must manually wrap the item into the TabItem; because of that, the TabControlRegionAdapter adapter was modified to both adapt a region to the TabControl control and to automatically add this wrapping.

Creating the Shell

During this phase, the shell will be displayed if it exists. Having the creation of the shell in the bootstrapper allows greater testability of the application because the shell can be mocked in a unit test.

If you are adding the Composite Application Library to an existing application, there may not be a shell. In these instances, you should override the CreateShell method to return null. For more information about the shell, see the Shell and View technical concept. The following code from the file StockTraderRIBootstrapper.cs shows the CreateShell method used in the Stock Trader Reference Implementation (Stock Trader RI) for WPF.

protected override DependencyObject CreateShell()
{
    ShellPresenter presenter = Container.Resolve<ShellPresenter>();
    IShellView view = presenter.View;
    view.ShowView();
    return view as DependencyObject;
}

Initializing the Modules

During this phase, module loading occurs. First, the module manager service is resolved from the container. After that, the Run method of the module manager service is invoked. This method validates the module catalog and initializes the available modules. The IntializeModules method of the UnityBootstrapper class is shown in the following code.

protected virtual void InitializeModules()
{
    IModuleManager manager;

    try
    {
        manager = this.Container.Resolve<IModuleManager>();
    }
    catch (ResolutionFailedException ex)
    {
        if (ex.Message.Contains("IModuleCatalog"))
        {
            throw new InvalidOperationException(Resources.NullModuleCatalogException);
        }

        throw;
    }

    manager.Run();
}

Note

It is mandatory to provide a module catalog instance; if you do not, a run-time exception is thrown.

You can populate the module catalog in several ways. In a Silverlight application, you can populate the module catalog from code or from a XAML file. In a WPF application, you can also populate the module catalog from a configuration file or a directory in addition to from code or a XAML file.

Regardless of the method used for populating the catalog, you should override the GetModuleCatalog method and create a module catalog instance, which implements the IModuleCatalog interface, as shown in the following code from the Stock Trader RI that populates the catalog from code.

protected override IModuleCatalog GetModuleCatalog()
{
    var catalog = new ModuleCatalog();
    catalog.AddModule(typeof(MarketModule))
        .AddModule(typeof(PositionModule), "MarketModule")
        .AddModule(typeof(WatchModule), "MarketModule")
        .AddModule(typeof(NewsModule));

    return catalog;
}

For more information about modules, see the Module technical concept.

More Information

The following topics contain procedures that customize the bootstrapper class:

For more information about other Composite Application Guidance technical concepts, see the following topics:

Home page on MSDN | Community site