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

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

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

1 public void Run()
2 {
3     RegisterUnhandledExceptionHandler();
4     Builder builder = CreateBuilder();
5     AddBuilderStrategies(builder);
6     CreateRootWorkItem(builder);

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();

6     if (assembly != null)
7         loader.Load(rootWorkItem, assembly);
8 }

通过 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);

7     OnInitialized();
8 }

同时 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     }

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 的启动流程,还有很多细节后面的文章会接受。

转载于:https://www.cnblogs.com/flyabroad/archive/2008/06/16/1222948.html

SCSF 系列:Smart Client Software Factory 启动过程详解相关推荐

  1. SCSF 系列:Smart Client Software Factory 与 ObjectBuilder

    [FLYabroad]ObjectBuilder 简介,SCSF 对 ObjectBuilder 的使用和扩展,SCSF 与控制反转(IOC). 上一篇:Smart Client Software F ...

  2. SCSF 系列:Smart Client Software Factory 中的 MVP 模式概述

    Smart Client Software Factory 是一个关注 Smart Client (智能客户端)构建的 UI 层框架,提供了对 MVP 模式的 First Class 支持,不了解 M ...

  3. Smart Client Software Factory 初试

    Smart Client Software Factory 初试 介绍 智能客户端的介绍我就不再这里说明了,大家可以通过Google去发现. 智能客户端软件工厂提供给建筑师和开发商能够快速综合智能客户 ...

  4. Smart Client Software Factory安装

    首先要安装 Visual Studio 2010 SDK 不然无法安装 Smart Client Software Factory 2010 然后按顺序安装 GAX 2010 http://visua ...

  5. Spring启动过程详解

    Spring启动过程详解 前言 spring容器启动过程 AnnotationConfigApplicationContext 有参数构造方法 无参数构造 AnnotatedBeanDefinitio ...

  6. Linux开启动过程详解

    Linux开启动过程详解 Linux启动过程 前言: Linux是一种自由和开放源代码的类UNIX操作系统.该操作系统的内核由林纳斯·托瓦兹在1991年10月5日首次发布.在加上用户空间的应用程序之后 ...

  7. centos7 启动流程图_Linux启动过程详解

    Linux启动过程详解 作者:江远航 一.启动流程图如下 图1 Linux启动流程图 BIOS ---> MBR ---> Kernel---> Init 二.Linux启动顺序 一 ...

  8. Delta3d框架学习--程序启动过程详解

    一个Delta3d程序启动过程详解 一.初始化一个dtGame::GameApplication的实例,dtGame::GameApplication* app = new dtGame::GameA ...

  9. 朱老师ARM裸机学习笔记(四):S5PV210启动过程详解

    常用器件特性 内存: SRAM 静态内存 特点就是容量小.价格高,优点是不需要软件初始化直接上电就能用 DRAM 动态内存 特点就是容量大.价格低,缺点就是上电后不能直接使用,需要软件初始化后才可以使 ...

最新文章

  1. win 复制linux文件命令行,windows与Linux间远程拷贝文件(pscp命令)
  2. php鼠标已入移除,angularjs鼠标移入移出实现显示隐藏
  3. python大数据搜索_python语言-用 Python 实现一个大数据搜索引擎
  4. matlab生成二维服从高斯分布的数据
  5. error CS1061:
  6. 计算机网络第4版潘爱民_【每日一题笔试】第 25 天
  7. 动作分析 姿态估计_单人或多人的人体姿态骨架估计算法概述
  8. 算法,求1亿个数的中位数
  9. ruby在类中访问@,类外访问调用方法
  10. Android 自动动画布局更新 使用,在RecyclerView上使用布局动画(Layout animation)
  11. 华为盒子 原生android,手把手教你刷机把华为悦盒刷机为安卓网络机顶
  12. 普元EOS在运算逻辑里面调用HttpServletRequest ,HttpServletResponse
  13. 视频加密软件技术小分享
  14. 【VMware】vmware15 安装win10教程【史上最详细图文教程】
  15. malloc用户态内存分配
  16. 全网最便宜的OpenHarmony开发板和模组Neptune问世(基于联盛德W800的SoC),9.9元带蓝牙和wifi功能还包邮
  17. 美国股票市场上市规则摘要纽约证券交易所
  18. 【毕业设计】基于stm32的示波器设计与实现 - 单片机 嵌入式
  19. 作业要求20190919-2 功能测试
  20. matlab 编程计算θ0的变化对三相短路电流的影响(电力系统暂态分析)

热门文章

  1. 【深度学习】利用深度可分离卷积减小计算量及提升网络性能
  2. Keras【Deep Learning With Python】机器学习和线性回归
  3. python【蓝桥杯vip练习题库】ADV-69质因数(数论)
  4. python【蓝桥杯vip练习题库】BASIC-20 数的读法
  5. python【蓝桥杯vip练习题库】BASIC-27 2n皇后问题(八皇后问题 搜索)
  6. 全卷积神经网路【U-net项目实战】Unet++
  7. Tensorflow【实战Google深度学习框架】—Logistic regression逻辑回归模型实例讲解
  8. PHP 实现一个可用的redis 事务锁, 解决并发问题
  9. linux内核编译 menuconfig详解,Linux内核编译menuconfig介绍
  10. 怎么做网络推广浅析网站如何设置导航栏可以使网站优化更好?