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:
compositewpf,
unity,
configuration,
shellapp
Categories:
Unity