/V2.2/trunk/CAL/Desktop/Composite.UnityExtensions/UnityBootstrapper.cs

# · C# · 308 lines · 177 code · 40 blank · 91 comment · 16 complexity · 7270411f8565eaefbc9ce81584235d51 MD5 · raw file

  1. //===================================================================================
  2. // Microsoft patterns & practices
  3. // Composite Application Guidance for Windows Presentation Foundation and Silverlight
  4. //===================================================================================
  5. // Copyright (c) Microsoft Corporation. All rights reserved.
  6. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
  7. // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
  8. // LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  9. // FITNESS FOR A PARTICULAR PURPOSE.
  10. //===================================================================================
  11. // The example companies, organizations, products, domain names,
  12. // e-mail addresses, logos, people, places, and events depicted
  13. // herein are fictitious. No association with any real company,
  14. // organization, product, domain name, email address, logo, person,
  15. // places, or events is intended or should be inferred.
  16. //===================================================================================
  17. using System;
  18. using System.Globalization;
  19. using System.Windows;
  20. using System.Windows.Controls;
  21. using System.Windows.Controls.Primitives;
  22. using Microsoft.Practices.Composite.Events;
  23. using Microsoft.Practices.Composite.Logging;
  24. using Microsoft.Practices.Composite.Modularity;
  25. using Microsoft.Practices.Composite.Presentation.Regions;
  26. using Microsoft.Practices.Composite.Presentation.Regions.Behaviors;
  27. using Microsoft.Practices.Composite.Regions;
  28. using Microsoft.Practices.Composite.UnityExtensions.Properties;
  29. using Microsoft.Practices.ServiceLocation;
  30. using Microsoft.Practices.Unity;
  31. namespace Microsoft.Practices.Composite.UnityExtensions
  32. {
  33. /// <summary>
  34. /// Base class that provides a basic bootstrapping sequence that
  35. /// registers most of the Composite Application Library assets
  36. /// in a <see cref="IUnityContainer"/>.
  37. /// </summary>
  38. /// <remarks>
  39. /// This class must be overriden to provide application specific configuration.
  40. /// </remarks>
  41. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable")]
  42. public abstract class UnityBootstrapper
  43. {
  44. private readonly ILoggerFacade loggerFacade = new TextLogger();
  45. private bool useDefaultConfiguration = true;
  46. /// <summary>
  47. /// Gets the default <see cref="IUnityContainer"/> for the application.
  48. /// </summary>
  49. /// <value>The default <see cref="IUnityContainer"/> instance.</value>
  50. [CLSCompliant(false)]
  51. public IUnityContainer Container { get; private set; }
  52. /// <summary>
  53. /// Gets the default <see cref="ILoggerFacade"/> for the application.
  54. /// </summary>
  55. /// <value>A <see cref="ILoggerFacade"/> instance.</value>
  56. protected virtual ILoggerFacade LoggerFacade
  57. {
  58. get { return this.loggerFacade; }
  59. }
  60. /// <summary>
  61. /// Runs the bootstrapper process.
  62. /// </summary>
  63. public void Run()
  64. {
  65. this.Run(true);
  66. }
  67. /// <summary>
  68. /// Run the bootstrapper process.
  69. /// </summary>
  70. /// <param name="runWithDefaultConfiguration">If <see langword="true"/>, registers default Composite Application Library services in the container. This is the default behavior.</param>
  71. public void Run(bool runWithDefaultConfiguration)
  72. {
  73. this.useDefaultConfiguration = runWithDefaultConfiguration;
  74. ILoggerFacade logger = this.LoggerFacade;
  75. if (logger == null)
  76. {
  77. throw new InvalidOperationException(Resources.NullLoggerFacadeException);
  78. }
  79. logger.Log("Creating Unity container", Category.Debug, Priority.Low);
  80. this.Container = this.CreateContainer();
  81. if (this.Container == null)
  82. {
  83. throw new InvalidOperationException(Resources.NullUnityContainerException);
  84. }
  85. logger.Log("Configuring container", Category.Debug, Priority.Low);
  86. this.Container.AddNewExtension<UnityBootstrapperExtension>();
  87. this.ConfigureContainer();
  88. logger.Log("Configuring region adapters", Category.Debug, Priority.Low);
  89. this.ConfigureRegionAdapterMappings();
  90. this.ConfigureDefaultRegionBehaviors();
  91. this.RegisterFrameworkExceptionTypes();
  92. logger.Log("Creating shell", Category.Debug, Priority.Low);
  93. DependencyObject shell = this.CreateShell();
  94. if (shell != null)
  95. {
  96. RegionManager.SetRegionManager(shell, this.Container.Resolve<IRegionManager>());
  97. RegionManager.UpdateRegions();
  98. }
  99. logger.Log("Initializing modules", Category.Debug, Priority.Low);
  100. this.InitializeModules();
  101. logger.Log("Bootstrapper sequence completed", Category.Debug, Priority.Low);
  102. }
  103. /// <summary>
  104. /// Registers in the <see cref="IUnityContainer"/> the <see cref="Type"/> of the Exceptions
  105. /// that are not considered root exceptions by the <see cref="ExceptionExtensions"/>.
  106. /// </summary>
  107. protected virtual void RegisterFrameworkExceptionTypes()
  108. {
  109. ExceptionExtensions.RegisterFrameworkExceptionType(
  110. typeof(Microsoft.Practices.ServiceLocation.ActivationException));
  111. ExceptionExtensions.RegisterFrameworkExceptionType(
  112. typeof(Microsoft.Practices.Unity.ResolutionFailedException));
  113. ExceptionExtensions.RegisterFrameworkExceptionType(
  114. typeof(Microsoft.Practices.ObjectBuilder2.BuildFailedException));
  115. }
  116. /// <summary>
  117. /// Configures the <see cref="IUnityContainer"/>. May be overwritten in a derived class to add specific
  118. /// type mappings required by the application.
  119. /// </summary>
  120. protected virtual void ConfigureContainer()
  121. {
  122. Container.RegisterInstance<ILoggerFacade>(LoggerFacade);
  123. // We register the container with an ExternallyControlledLifetimeManager to avoid
  124. // recursive calls if Container.Dispose() is called.
  125. //Container.RegisterInstance<IUnityContainer>(Container);
  126. IModuleCatalog catalog = GetModuleCatalog();
  127. if (catalog != null)
  128. {
  129. this.Container.RegisterInstance(catalog);
  130. }
  131. if (useDefaultConfiguration)
  132. {
  133. RegisterTypeIfMissing(typeof(IServiceLocator), typeof(UnityServiceLocatorAdapter), true);
  134. RegisterTypeIfMissing(typeof(IModuleInitializer), typeof(ModuleInitializer), true);
  135. RegisterTypeIfMissing(typeof(IModuleManager), typeof(ModuleManager), true);
  136. RegisterTypeIfMissing(typeof(RegionAdapterMappings), typeof(RegionAdapterMappings), true);
  137. RegisterTypeIfMissing(typeof(IRegionManager), typeof(RegionManager), true);
  138. RegisterTypeIfMissing(typeof(IEventAggregator), typeof(EventAggregator), true);
  139. RegisterTypeIfMissing(typeof(IRegionViewRegistry), typeof(RegionViewRegistry), true);
  140. RegisterTypeIfMissing(typeof(IRegionBehaviorFactory), typeof(RegionBehaviorFactory), true);
  141. ServiceLocator.SetLocatorProvider(() => this.Container.Resolve<IServiceLocator>());
  142. }
  143. }
  144. /// <summary>
  145. /// Configures the default region adapter mappings to use in the application, in order
  146. /// to adapt UI controls defined in XAML to use a region and register it automatically.
  147. /// May be overwritten in a derived class to add specific mappings required by the application.
  148. /// </summary>
  149. /// <returns>The <see cref="RegionAdapterMappings"/> instance containing all the mappings.</returns>
  150. protected virtual RegionAdapterMappings ConfigureRegionAdapterMappings()
  151. {
  152. RegionAdapterMappings regionAdapterMappings = Container.TryResolve<RegionAdapterMappings>();
  153. if (regionAdapterMappings != null)
  154. {
  155. #if SILVERLIGHT
  156. regionAdapterMappings.RegisterMapping(typeof(TabControl), this.Container.Resolve<TabControlRegionAdapter>());
  157. #endif
  158. regionAdapterMappings.RegisterMapping(typeof(Selector), this.Container.Resolve<SelectorRegionAdapter>());
  159. regionAdapterMappings.RegisterMapping(typeof(ItemsControl), this.Container.Resolve<ItemsControlRegionAdapter>());
  160. regionAdapterMappings.RegisterMapping(typeof(ContentControl), this.Container.Resolve<ContentControlRegionAdapter>());
  161. }
  162. return regionAdapterMappings;
  163. }
  164. /// <summary>
  165. /// Configures the <see cref="IRegionBehaviorFactory"/>. This will be the list of default
  166. /// behaviors that will be added to a region.
  167. /// </summary>
  168. protected virtual IRegionBehaviorFactory ConfigureDefaultRegionBehaviors()
  169. {
  170. var defaultRegionBehaviorTypesDictionary = Container.TryResolve<IRegionBehaviorFactory>();
  171. if (defaultRegionBehaviorTypesDictionary != null)
  172. {
  173. defaultRegionBehaviorTypesDictionary.AddIfMissing(AutoPopulateRegionBehavior.BehaviorKey,
  174. typeof(AutoPopulateRegionBehavior));
  175. defaultRegionBehaviorTypesDictionary.AddIfMissing(BindRegionContextToDependencyObjectBehavior.BehaviorKey,
  176. typeof(BindRegionContextToDependencyObjectBehavior));
  177. defaultRegionBehaviorTypesDictionary.AddIfMissing(RegionActiveAwareBehavior.BehaviorKey,
  178. typeof(RegionActiveAwareBehavior));
  179. defaultRegionBehaviorTypesDictionary.AddIfMissing(SyncRegionContextWithHostBehavior.BehaviorKey,
  180. typeof(SyncRegionContextWithHostBehavior));
  181. defaultRegionBehaviorTypesDictionary.AddIfMissing(RegionManagerRegistrationBehavior.BehaviorKey,
  182. typeof(RegionManagerRegistrationBehavior));
  183. }
  184. return defaultRegionBehaviorTypesDictionary;
  185. }
  186. /// <summary>
  187. /// Initializes the modules. May be overwritten in a derived class to use a custom Modules Catalog
  188. /// </summary>
  189. protected virtual void InitializeModules()
  190. {
  191. IModuleManager manager;
  192. try
  193. {
  194. manager = this.Container.Resolve<IModuleManager>();
  195. }
  196. catch (ResolutionFailedException ex)
  197. {
  198. if (ex.Message.Contains("IModuleCatalog"))
  199. {
  200. throw new InvalidOperationException(Resources.NullModuleCatalogException);
  201. }
  202. throw;
  203. }
  204. manager.Run();
  205. }
  206. /// <summary>
  207. /// Returns the module catalog that will be used to initialize the modules.
  208. /// </summary>
  209. /// <remarks>
  210. /// When using the default initialization behavior, this method must be overwritten by a derived class.
  211. /// </remarks>
  212. /// <returns>An instance of <see cref="IModuleCatalog"/> that will be used to initialize the modules.</returns>
  213. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
  214. protected virtual IModuleCatalog GetModuleCatalog()
  215. {
  216. return null;
  217. }
  218. /// <summary>
  219. /// Creates the <see cref="IUnityContainer"/> that will be used as the default container.
  220. /// </summary>
  221. /// <returns>A new instance of <see cref="IUnityContainer"/>.</returns>
  222. [CLSCompliant(false)]
  223. protected virtual IUnityContainer CreateContainer()
  224. {
  225. return new UnityContainer();
  226. }
  227. /// <summary>
  228. /// Registers a type in the container only if that type was not already registered.
  229. /// </summary>
  230. /// <param name="fromType">The interface type to register.</param>
  231. /// <param name="toType">The type implementing the interface.</param>
  232. /// <param name="registerAsSingleton">Registers the type as a singleton.</param>
  233. protected void RegisterTypeIfMissing(Type fromType, Type toType, bool registerAsSingleton)
  234. {
  235. ILoggerFacade logger = LoggerFacade;
  236. if (Container.IsTypeRegistered(fromType))
  237. {
  238. logger.Log(
  239. String.Format(CultureInfo.CurrentCulture,
  240. Resources.TypeMappingAlreadyRegistered,
  241. fromType.Name), Category.Debug, Priority.Low);
  242. }
  243. else
  244. {
  245. if (registerAsSingleton)
  246. {
  247. Container.RegisterType(fromType, toType, new ContainerControlledLifetimeManager());
  248. }
  249. else
  250. {
  251. Container.RegisterType(fromType, toType);
  252. }
  253. }
  254. }
  255. /// <summary>
  256. /// Creates the shell or main window of the application.
  257. /// </summary>
  258. /// <returns>The shell of the application.</returns>
  259. /// <remarks>
  260. /// If the returned instance is a <see cref="DependencyObject"/>, the
  261. /// <see cref="UnityBootstrapper"/> will attach the default <seealso cref="IRegionManager"/> of
  262. /// the application in its <see cref="RegionManager.RegionManagerProperty"/> attached property
  263. /// in order to be able to add regions by using the <seealso cref="RegionManager.RegionNameProperty"/>
  264. /// attached property from XAML.
  265. /// </remarks>
  266. protected abstract DependencyObject CreateShell();
  267. }
  268. }