第二章 初始化Prism应用程序
本章将讨论为了使一个Prism应用程序的启动和运行哪些是必须的。Prism的应用程序在启动过程中需要注册和配置,这被称为引导应用程序。
什么是Bootstrapper?
bootstrapper是一个类,通过Prism类库负责一个应用程序建立的初始化。通过使用bootstrapper,对于如何将Prism库组件连接到您的应用程序,你会有更多的控制。
Prism类库包括一个默认的抽象bootstrapper基类,可以专门用于任何容器。许多关于bootstrapper类的方法都是虚拟方法。您可以重写这些方法,使其适合执行您自己自定义的bootstrapper。
Basic stages of the bootstrapping process
Prism库提供了一些额外的基类,派生于Bootstrapper,,具有默认的实现,适合大多数应用程序。对于你程序的Bootstrapper,留给你唯一要做的就是创建和初始化Shell。
依赖注入
用Prism构建的应用程序依赖于容器提供的依赖注入。本库提供工作在Unity(Unity Application Block)或MEF(Managed Extensibility Framework)两种框架下的容器,它允许你使用其他依赖注入容器。启动引导过程的一部分就是配置此容器并向容器注册类型。
Prism库包括Unitybootstrapper和Mefbootstrapper两个类,它实现了大部分的功能,这些功能对于使用Unity或MEF作为你的应用程序中的依赖注入容器是必需的。除了在上图中所示的启动过程,每个引导程序还会增加一些特定于容器的步骤。
创建Shell
在传统的Windows Presentation Foundation(WPF)的应用程序中,启动程序的URL是在app.xaml文件中定义的。在Silverlight应用程序中,是由app.xaml代码中的RootVisual属性所指定的。
在用Prism库创建的应用程序中,Bootstrapper的责任就是创建Shell或主窗口。这是因为壳依赖一些服务,如Region Manager,需要在Shell被显示前进行注册。
关键决策
当你决定在你的应用程序中使用Prism后,还有一些额外需要作出的决定:
- 对于你的依赖注入容器,你需要决定是否使用MEF,Unity,或其他容器。这将确定你应该使用谁提供的bootstrapper类和你是否需要为另一个容器创建一个bootstrapper。
- 你应该考虑在你的应用程序中的一些特定应用服务,这将需要在容器中注册。
- 确定是否内置日志记录服务来满足您的需要或如果有必要,创建另一个日志记录服务。
- 确定模块将怎样被应用程序发现:通过显式代码声明,通过目录扫描模块代码属性,配置,或XAML…
在余下的章节中会提供更多详细参考
核心方案
创建一个启动序列是建立你的Prism应用的一个重要部分。本节介绍了如何创建一个引导程序和自定义它去创建Shell,配置依赖注入容器,注册应用程序级的服务,以及如何加载和初始化模块。
为你的应用创建一个启动程序(Bootstrapper)
如果你选择使用Unity或MEF作为你的依赖注入容器,那么为你的应用创建一个简单的引导程序是很容易的。你需要创建一个新的派生类,无论派生于MefBootstrapper或UnityBootstrapper。然后,执行CreateShell方法。或者,你可以为Shell的特定初始化重写Initializeshell方法。
实现CreateShell方法
该Createshell方法允许开发人员为Prism应用程序指定一个的顶层窗口。Shell通常就是主窗口或主页。通过返回应用程序的Shell类来实现这个方法。在一个Prism的应用程序中,您可以创建Shell对象,或从容器中指定,这取决于你应用程序的需要。
在下面的代码示例中通过使用Servicelocator指定Shell对象。
1 protected override DependencyObject CreateShell()2 { 3 return ServiceLocator.Current.GetInstance(); 4 }
Note:你会经常看到Servicelocator被用来实例化而不是特定的依赖注入容器。该Servicelocator是通过调用容器实现,对于容器与其他代码解耦这是一个很好的选择。你也可以直接参考与使用容器而不是Servicelocator。
实现InitializeShell方法
你创建Shell后,您可能需要运行初始化步骤以确保Shell可以显示。这取决于你正在写一个WPF还是Silverlight应用,实现的Initializeshell方法会有所不同。对于Silverlight应用,你将Shell作为应用程序的Visual Root,如下所示。
protected override void InitializeShell(){ Application.Current.RootVisual = Shell;}
对于WPF应用程序,您将创建的Shell应用程序对象,并将它设置为应用程序的主窗口,如图所示(来自the Modularity QuickStarts for WPF)。
protected override void InitializeShell(){ Application.Current.MainWindow = Shell; Application.Current.MainWindow.Show();}
对Initializeshell的基本实现不做任何事情。对此才是安全的。
创建和配置模块列表
如果你正在创建一个模块应用程序,你需要创建和配置模块列表。Prism采用IModulecatalog的实例来跟踪哪些模块对应用程序是可用的,哪些模块可能需要下载,以及放在哪。
Bootstrapper提供了一个Modulecatalog受保护的属性来表示该目录以及虚Createmodulecatalog方法的基实现。在基类的实现中返回一个新的Modulecatalog;然而,可以重写该方法提供一个不同的IModulecatalog实例,如下代码,这是在Modularity wiyh MEF for Silverlight QuickStart代码中的Quickstartbootstrapper。
protected override IModuleCatalog CreateModuleCatalog(){ // When using MEF, the existing Prism ModuleCatalog is still // the place to configure modules via configuration files. return ModuleCatalog.CreateFromXaml(new Uri( "/ModularityWithMef.Silverlight;component/ModulesCatalog.xaml", UriKind.Relative)); }
在这Unitybootstrapper和Mefbootstrapper两个类中,Run方法调用Createmodulecatalog方法,然后用返回的值设置类的Modulecatalog属性。如果你重写此方法,调用基类的实现是没有必要的,因为你那将会取代提供的功能。有关模块的更多信息,请参见第4章,“模块化应用的发展。”
创建和配置容器
容器在Prism库创建的应用程序中发挥关键作用。无论是Prism库还是用它来建立的应用程序都依赖一个用于属性和服务注入的容器。在容器配置阶段,一些核心服务被注册。除了这些核心服务,由于涉及到组织,你可能需要一些特定应用服务来提供额外的功能。
核心服务
下列表格列出了在Prism库中的核心非应用的特定服务
服务接口 | 描述 |
IModuleManager | 定义了用于服务的接口,用来检索和初始化应用程序模块。 |
IModuleCatalog | 包含在应用程序中有关模块的元数据。Prism库提供了几个不同的列表。 |
IModuleInitializer | 初始化模块 |
IRegionManager | 注册和回收Regions,这是布局的视觉容器。 |
IEventAggregator | 发布者和订阅者之间的一系列松耦合事件。 |
ILoggerFacade | 一个日志机制的封装,所以你可以选择你自己的日志机制。The Stock Trader Reference Implementation (Stock Trader RI) 通过EnterpriseLibraryLoggerAdapter类,使用Enterprise Library Logging Application Block,作为一个你如何使用你自己的日志例子。日志记录服务是通过引导程序的Run方法在容器中注册的,该方法利用由CreateLogger方法返回的值。在容器中注册另一个记录器将不会有作用;而是应该重写引导程序的CreateLogger方法。 |
IServiceLocator | 允许Prism库访问容器。如果你想自定义或扩展库,这可能是有用的。 |
应用特定服务
下列表格列出了被使用在Stock Trader RI中的应用特定服务,这个可以作为一个例子用来理解你的应用程序中可能提供的服务类型
在Stock Trader RI中的服务 | 描述 |
IMarketFeedService | 提供实时行情数据。PositionSummaryPresentationModel根据从服务接收而来的通知更新位置屏幕。 |
IMarketHistoryService | 提供市场历史数据,这些数据用于为所选基金显示趋势线。 |
IAccountPositionService | 在投资组合中提供资金的列表。 |
IOrdersService | 持续提交买/卖单。 |
INewsFeedService | 为选择的基金提供一种新闻项目列表。 |
IWatchListService | 当新的观察项目被添加到观察名单中时处理。 |
在Prism中有两个引导程序的派生类是有效的,Unitybootstrapper和Mefbootstrapper。创建和配置不同的容器,涉及类似的概念却有不同的实现。
创建和配置在UnityBootstrapper中的容器
UnityBootstrapper类的CreateContainer方法简单地创建并返回一个UnityContainer新的实例。在大多数情况下,您不需要更改此功能;然而,该方法是虚方法,从而具有灵活性。
当容器被创建之后,它可能需要配置你的应用程序。在UnityBootstrapper中的ConfigureContainer方法在默认情况下注册了一系列核心Prism服务,如下所示
Note:例子内容:当一个模块在它的初始化方法中注册了模块及服务
UnityBootstrapper.cs
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); } }
引导程序的RegisterTypeifMissing方法确定服务是否已经被注册---不能被注册两次。通过配置,允许你重写默认注册。你也可以关闭默认注册任何服务;要做到这一点,使用重载Bootstrapper.Run方法传递false。你也可以覆盖ConfigureContainer方法和禁用你不想使用的服务,如事件聚合。
Note:如果你关闭默认注册,你必须手动注册必要的服务。
为了拓展ConfigureContainer的默认行为,只需将你的应用程序的bootstrapper重载并且有选择的调用基类实现,如下面来自QuickStartBootstrapper from the Modularity for WPF (with Unity) QuickStart.的代码所示。这个实现调用了基类的实现,注册ModuleTracker类型作为IModuleTracker的具体实现,并注册callbackLogger作为CallbackLogger的单一实例。
protected override void ConfigureContainer(){ base.ConfigureContainer(); this.RegisterTypeIfMissing(typeof(IModuleTracker), typeof(ModuleTracker), true); this.Container.RegisterInstance(this.callbackLogger); }
创建和配置在MefBootstrapper中的容器
MefBootstrapper类的CreateContainer方法做了以下几件事。首先,它创建了一个AssemblyCatalog和CatalogExportProvider。CatalogExportProvider允许MefExtensions组件为一些Prism类型提供默认出口,还允许你重写默认类型注册。然后CreateContainer创建并返回一个使用CatalogExportProvider的CompositionContainer的新实例。在大多数情况下,您不需要更改此功能;然而,该方法是虚方法,从而有更多灵活性。
Note:在Silverlight,由于安全限制,回收使用一个类型的组件是不可能。然反,Prism使用另一种方法,就是使用Assembly.GetCallingAssembly方法。
在容器被创建之后,你需要为你的应用程序来配置它。在MefBootstrapper中的ConfigureContainer实现在默认情况下,注册了一系列核心Prism服务,如下面的代码示例所示。如果你重写此方法,仔细考虑你是否应该调用基类的实现去注册核心Prism服务,或者你在你的实现中提供这些服务。
protected virtual void ConfigureContainer(){ this.RegisterBootstrapperProvidedTypes(); } protected virtual void RegisterBootstrapperProvidedTypes() { this.Container.ComposeExportedValue(this.Logger); this.Container.ComposeExportedValue (this.ModuleCatalog); this.Container.ComposeExportedValue (new MefServiceLocatorAdapter(this.Container)); this.Container.ComposeExportedValue (this.AggregateCatalog); }
Note:在MefBootstrapper中,Prism的核心服务作为单例被添加到容器中,所以,他们可以通过容器被置于应用程序各处。
除了提供CreateContainer和ConfigureContainer方法,MefBootstrapper还提供了两种方法来创建和配置由MEF使用的AggregateCatalog。CreateAggregateCatalog方法简单的创建并返回一个AggregateCatalog对象。就像在MefBootstrapper中的其他方法,CreateAggregateCatalog是虚方法,如果必要的话,可以重写。
ConfigureAggregateCatalog方法允许你向AggregateCatalog命令式的添加类型注册。例如,来自 the Modularity with MEF for Silverlight QuickStart的QuickStartBootstrapper明确地向AggregateCatalog添加了ModuleA和ModuleC,如下所示。
protected override void ConfigureAggregateCatalog(){ base.ConfigureAggregateCatalog(); // Add this assembly to export ModuleTracker this.AggregateCatalog.Catalogs.Add( new AssemblyCatalog(typeof(QuickStartBootstrapper).Assembly)); // Module A is referenced in in the project and directly in code. this.AggregateCatalog.Catalogs.Add( new AssemblyCatalog(typeof(ModuleA.ModuleA).Assembly)); // Module C is referenced in in the project and directly in code. this.AggregateCatalog.Catalogs.Add( new AssemblyCatalog(typeof(ModuleC.ModuleC).Assembly)); }