zoukankan      html  css  js  c++  java
  • 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 的启动流程,还有很多细节后面的文章会接受。

     转载:FLYabroad.NET  孙洪亮

  • 相关阅读:
    自我介绍 x
    第一次作业 x
    第二次作业 x
    第三次作业 x
    [C#] 用一种更优美的方式来替换掉又多又长的switchcase代码段
    通过设置光标形状实现拖拽控件时跟随一张透明图片的效果
    spring 入门笔记(一)
    PAT IO01. 表格输出(5)
    Maven 安装记
    华为机试 求最大三位数
  • 原文地址:https://www.cnblogs.com/jcomet/p/3105835.html
Copyright © 2011-2022 走看看