FLYabroad 技术移民 - FLYabroadVisa.com

SCSF 系列:Smart Client Software Factory 启动过程详解

应网友要求,结合参考实现(BankBranchWorkbench)写一篇关于 SCSF 内部工作原理的文章,需要读者有 SCSF 基础。基本概念和基本理念后面相关文章介绍。

SCSF 自动为我们建立了 Shell 项目。该项目的 ShellApplication 是SCSF 应用的入口程序,该类继承自 SmartClientApplication<TWorkItem, TShell> ,TWorkItem 是要指定的 root workitem ,TShell 是主窗体。

ShellApplication

该类的 Main 方法通过 new ShellApplication().Run(); 启动应用。Run() 在父类 CabApplication 中实现,定义了 SCSF 的启动流程:

1 public void Run()
2 {
3     RegisterUnhandledExceptionHandler();
4     Builder builder = CreateBuilder();
5     AddBuilderStrategies(builder);
6     CreateRootWorkItem(builder);
7 
8     IVisualizer visualizer = CreateVisualizer();
9     if (visualizer != null)
10         visualizer.Initialize(rootWorkItem, builder);
11 
12     AddRequiredServices();
13     AddConfiguredServices();
14     AddServices();
15     AuthenticateUser();
16     ProcessShellAssembly();
17     rootWorkItem.BuildUp();
18     LoadModules();
19     rootWorkItem.FinishInitialization();
20 
21     rootWorkItem.Run();
22     Start();
23 
24     rootWorkItem.Dispose();
25     if (visualizer != null)
26         visualizer.Dispose();
27 }
28 

其中核心流程有:

1. 首先创建 Builder builder = CreateBuilder(); 

CreaterBuilder()方法注册了 RootWorkItemInitializationStrategy ,EventBrokerStrategy,CommandStrategy,ObjectBuiltNotificationStrategy 总共四个策略,同时还添加了三个 Policy :SingletonPolicy,BuilderTraceSourcePolicy,ObjectBuiltNotificationPolicy 。

CreaterBuilder() 一般使用 builder.Strategies.AddNew 方法利用 ObjectBuilder 构建策略对象 (例如:builder.Strategies.AddNew<EventBrokerStrategy>(BuilderStage.Initialization))。

2. 子类可以通过重写 protected virtual void AddBuilderStrategies(Builder builder) 来给 ObjectBuilder 添加其他构建策略(在构建对象或者销毁对象时执行的操作)。

3. 初始化 RootWorkItem

这些准备工作做完后,第一件事是创建 RootWorkItem 。RootWorkItem 是通过 CreateRootWorkItem(builder) 完成的,以前面创建的 builder 作为参数:protected internal void InitializeRootWorkItem(Builder builder)。

InitializeRootWorkItem 中首先初始化 RootWorkItem 相关的 Builder 和 Locator (这两个都是 ObjectBuilder 的组件,用与对象创建和依赖注入):

this.builder = builder;
this.locator = new Locator();

其次对 rootWorkItem 进行初始化,主要执行以下三个方法:

InitializeFields():设置或初始化 ObjectBuilder 相关的对象: Builder,Locator,ObjectBuiltNotificationPolicy,还有 workItem 的状态。

InitializeState():通过 Guid 生成本 workItem 实例的 ID (ID = Guid.NewGuid().ToString(););

InitializeCollectionFacades():初始化管理 SCSF 核心组件的对象管理集合: ServiceCollection,commandCollection,workItemCollection,workspaceCollection,itemsCollection,smartPartCollection,eventTopicCollection,uiExtensionSiteCollection 。

RootWorkItem 构建完成后有一个可选的过程是创建 IVisualizer (用于在运行时查看 WorkItem 的状态):

1 IVisualizer visualizer = CreateVisualizer();
2 if (visualizer != null)
3     visualizer.Initialize(rootWorkItem, builder);

4. 添加服务:

AddRequiredServices() 方法添加的服务有:TraceSourceCatalogService,WorkItemExtensionService,WorkItemTypeCatalogService,SimpleWorkItemActivationService,WindowsPrincipalAuthenticationService,ModuleLoaderService,FileCatalogModuleEnumerator,DataProtectionCryptographyService,CommandAdapterMapService,UIElementAdapterFactoryCatalog 。

AddConfiguredServices() 添加在配置文件中配置的服务,也就是运行我们通过配置的方式决定在 SCSF 框架启动时加载额外服务(Services)。

AddServices() 在 CabApplication 中是一个空的虚拟方法,允许我们创建 CabApplication 的子类来重写该方法以添加需要的 Services 。

5. 验证用户

通过获取在启动过程中注册的 IAuthenticationService 服务来进行用户验证(ObjectBuilder 的具体应用):

1 private void AuthenticateUser()
2 {
3     IAuthenticationService auth = rootWorkItem.Services.Get<IAuthenticationService>(true);
4     auth.Authenticate();
5 }

6. 处理 Shell 程序集(可执行的 Shell Assembly)

1 private void ProcessShellAssembly()
2 {
3     IModuleLoaderService loader = rootWorkItem.Services.Get<IModuleLoaderService>(true);
4     Assembly assembly = Assembly.GetEntryAssembly();
5 
6     if (assembly != null)
7         loader.Load(rootWorkItem, assembly);
8 }
9 

通过 ObjectBuilder 获取已注册的 IModuleLoaderService (默认的是 Microsoft.Practices.CompositeUI.Services.ModuleLoaderService),调用 ModuleLoaderService 的 Load 方法来通过SCSF Attribute(反射和特性)结合 ObjectBuilder 来加载 SCSF 核心组件,包括 Services、 Command 、 SmartParts、UIElement、workspace、Event Broker、State 等,这些属性(Attribute)主要有:ServiceAttribute,ServiceDependencyAttribute,SmartPartAttribute,CommandHandlerAttribute,EventPublicationAttribute,EventSubscriptionAttribute,ModuleDependencyAttribute,StateChangedAttribute,RootWorkItemExtensionAttribute,OptionalDependencyAttribute,TraceSourceAttribute,ComponentDependencyAttribute,WorkItemExtensionAttribute ,以后有时间会专门介绍这些属性的使用。

7. 构建 RootWorkItem (rootWorkItem.BuildUp())

RootWorkItem 通过 builder.BuildUp(locator, type, temporaryID, this, policies) 方法使用 ObjectBuilder 进行构建,前面介绍过 CabApplication 在 CreaterBuilder() 中注册了构建策略 RootWorkItemInitializationStrategy: builder.Strategies.Add(new RootWorkItemInitializationStrategy(this.OnRootWorkItemInitialized), BuilderStage.Initialization),该语句表明在创建 RootWorkItem 时 ObjectBuilder 会执行该策略并调用本类(CabApplication 或者重载的子类)的 OnRootWorkItemInitialized 方法:protected virtual void OnRootWorkItemInitialized()。CabShellApplication (CabApplication 的子类) 重写了该方法:

1 protected sealed override void OnRootWorkItemInitialized()
2 {
3     BeforeShellCreated();
4     shell = RootWorkItem.Items.AddNew<TShell>();
5     AfterShellCreated();
6 }

其中 RootWorkItem.Items.AddNew<TShell>() 语句创建了新的 TShell 主窗体对象(通过 ObjectBuilder 构建)并加入到 RootWorkItem 的 Items 集合中。

8. 通过配置加载模块(LoadModules())

RootWorkItem 构建完成后,SCSF 会根据 IModuleEnumerator 服务来枚举可以加载的模块(确定需要加载哪些模块),SCSF 中提供了两个 IModuleEnumerator 服务:FileCatalogModuleEnumerator(在配置文件中指明要加载哪些模块,默认的配置文件是 ProfileCatalog.xml )和 ReflectionModuleEnumerator(利用反射和 ModuleAttribute 来确定需要加载哪些模块)。同时 SCSF 的Package Guidance 为我们提供了一个 XmlStreamDependentModuleEnumerator ,用于从 Xml Stream 中确定需要加载哪些模块,这个可以用在通过 Web Service 将服务器上的配置发送到客户端的情况。

典型的配置文件示例 ProfileCatalog.xml :

<SolutionProfile xmlns="http://schemas.microsoft.com/pag/cab-profile/2.0%22>
  <Section Name="
Infrastructure">
   
<Modules>
       
<ModuleInfo AssemblyFile="GlobalBank.Support.Module.dll" /> 
       
<ModuleInfo AssemblyFile="GlobalBank.Infrastructure.Module.dll" />
   
</Modules>
 
</Section>
 
<Section Name="BranchSystems">
   
<Dependencies>
     
<Dependency Name="Infrastructure" />
   
</Dependencies>
   
<Modules>
     
<ModuleInfo AssemblyFile="GlobalBank.BranchSystems.Layout.dll" Name="BranchSystems.Layout"/>
     
<ModuleInfo AssemblyFile="GlobalBank.BranchSystems.Module.dll">
       
<Dependencies>
         
<Dependency Name="BranchSystems.Layout" />
       
</Dependencies>
       
<Roles>
         
<Role Allow="Greeter"/>
         
<Role Allow="Officer"/>
         
<Role Allow="BranchManager"/>
       
</Roles>
     
</ModuleInfo>
   
</Modules>
 
</Section>
 
<Section Name="LinesOfBusiness">
   
<Dependencies>
     
<Dependency Name="Infrastructure" />
     
<Dependency Name="BranchSystems" />
   
</Dependencies>
   
<Modules>
     
<ModuleInfo AssemblyFile="GlobalBank.BasicAccounts.Module.dll">
       
<Roles>
         
<Role Allow="Officer"/>
         
<Role Allow="BranchManager"/>
       
</Roles>
     
</ModuleInfo>
     
<ModuleInfo AssemblyFile="GlobalBank.CreditCardAccounts.Module.dll">
       
<Roles>
         
<Role Allow="Officer"/>
         
<Role Allow="BranchManager"/>
       
</Roles>
     
</ModuleInfo>
   
</Modules>
 
</Section>
</SolutionProfile> 


确定要加载那些模块后,就会执行上面 “6. 处理 Shell 程序集”中的过程,利用注册的 IModuleLoaderService 加载模块。SCSF 规定每个 Module 程序集都有一个继承自 ModuleInit 的子类,IModuleLoaderService  会在加载完该 Module 后自动调用其 void Load() 方法,这里是 SCSF 为我们通过的接入点,我们应该在 void Load() 方法中初始化本模块。具体应该初始化什么以后介绍。 

9. 完成对 RootWorkItem 的创建(rootWorkItem.FinishInitialization())
主要是处理 workItem 扩展(以后介绍),并触发创建完成事件:

1 protected internal void FinishInitialization()
2 {
3     IWorkItemExtensionService extensionsService = Services.Get<IWorkItemExtensionService>();
4     if (extensionsService != null)
5         extensionsService.InitializeExtensions(this);
6 
7     OnInitialized();
8 }
9 

同时 WorkItem 的 public void InitializeWorkItem() 是一个注入方法,有[InjectionMethod]属性标记,该方法执行时除了执行上面 rootworkItem中的初始化过程外,还会调用 InitializeServices 方法,该方法在 CabApplication 中是空方法,CabApplication 子类可以重写 protected virtual void InitializeServices() 方法,用于在 WorkItem 初始化时加载其他需要的服务。

10. 执行 rootWorkItem 的 run 方法 rootWorkItem.Run();

WorkItem 的 Run 方法直接调用 protected virtual void OnRunStarted() 方法:

1 public void Run()
2 {
3     OnRunStarted();
4 }

OnRunStarted 方法触发 RunStarted 事件(public event EventHandler RunStarted)

1 protected virtual void OnRunStarted()
2 {
3     if (this.RunStarted != null)
4     {
5         this.RunStarted(this, EventArgs.Empty);
6     }
7 
8     if (traceSource != null)
9         traceSource.TraceInformation(String.Format(
10             CultureInfo.CurrentCulture,
11                   Properties.Resources.TraceWorkItemRunStarted, ID));
12 }
13 

因此我们可以通过注册 RunStarted 事件或者在 WorkItem 子类中重写 OnRunStarted() 虚方法以便在 SCSF 启动过程中执行自己的操作,这是 SCSF 的又一扩展点。

11. 启动应用 Start()

CabApplication 中的 Start 是一个抽象方法:protected abstract void Start();

子类 FormShellApplication(public abstract class FormShellApplication<TWorkItem, TShell> : WindowsFormsApplication<TWorkItem, TShell>) 重写了Start :

1 protected override void Start()
2 {
3     Application.Run(Shell);
4 }

很简单,这时主窗体就显示出来了,以后的整个操作就是通过用户交互来触发了。

以上只是简单的介绍了一下 SCSF 的启动流程,还有很多细节后面的文章会接受。

posted on 2008-06-16 11:39  FLYabroad  阅读(6805)  评论(7编辑  收藏  举报

导航

FLYabroad 签证工作室 - FLYabroadVisa.com