PageRenderTime 23ms CodeModel.GetById 11ms app.highlight 7ms RepoModel.GetById 1ms app.codeStats 0ms

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