SCSF 系列:Smart Client Software Factory 启动过程详解
应网友要求,结合参考实现(BankBranchWorkbench)写一篇关于 SCSF 内部工作原理的文章,需要读者有 SCSF 基础。基本概念和基本理念后面相关文章介绍。
SCSF 自动为我们建立了 Shell 项目。该项目的 ShellApplication 是SCSF 应用的入口程序,该类继承自 SmartClientApplication<TWorkItem, TShell> ,TWorkItem 是要指定的 root workitem ,TShell 是主窗体。
该类的 Main 方法通过 new ShellApplication().Run(); 启动应用。Run() 在父类 CabApplication 中实现,定义了 SCSF 的启动流程:
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.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 的状态):
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 的具体应用):
2 {
3 IAuthenticationService auth = rootWorkItem.Services.Get<IAuthenticationService>(true);
4 auth.Authenticate();
5 }
6. 处理 Shell 程序集(可执行的 Shell Assembly)
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 的子类) 重写了该方法:
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 :
<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 扩展(以后介绍),并触发创建完成事件:
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() 方法:
2 {
3 OnRunStarted();
4 }
OnRunStarted 方法触发 RunStarted 事件(public event EventHandler RunStarted)
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 :
2 {
3 Application.Run(Shell);
4 }
很简单,这时主窗体就显示出来了,以后的整个操作就是通过用户交互来触发了。
以上只是简单的介绍了一下 SCSF 的启动流程,还有很多细节后面的文章会接受。
转载于:https://www.cnblogs.com/flyabroad/archive/2008/06/16/1222948.html
SCSF 系列:Smart Client Software Factory 启动过程详解相关推荐
- SCSF 系列:Smart Client Software Factory 与 ObjectBuilder
[FLYabroad]ObjectBuilder 简介,SCSF 对 ObjectBuilder 的使用和扩展,SCSF 与控制反转(IOC). 上一篇:Smart Client Software F ...
- SCSF 系列:Smart Client Software Factory 中的 MVP 模式概述
Smart Client Software Factory 是一个关注 Smart Client (智能客户端)构建的 UI 层框架,提供了对 MVP 模式的 First Class 支持,不了解 M ...
- Smart Client Software Factory 初试
Smart Client Software Factory 初试 介绍 智能客户端的介绍我就不再这里说明了,大家可以通过Google去发现. 智能客户端软件工厂提供给建筑师和开发商能够快速综合智能客户 ...
- Smart Client Software Factory安装
首先要安装 Visual Studio 2010 SDK 不然无法安装 Smart Client Software Factory 2010 然后按顺序安装 GAX 2010 http://visua ...
- Spring启动过程详解
Spring启动过程详解 前言 spring容器启动过程 AnnotationConfigApplicationContext 有参数构造方法 无参数构造 AnnotatedBeanDefinitio ...
- Linux开启动过程详解
Linux开启动过程详解 Linux启动过程 前言: Linux是一种自由和开放源代码的类UNIX操作系统.该操作系统的内核由林纳斯·托瓦兹在1991年10月5日首次发布.在加上用户空间的应用程序之后 ...
- centos7 启动流程图_Linux启动过程详解
Linux启动过程详解 作者:江远航 一.启动流程图如下 图1 Linux启动流程图 BIOS ---> MBR ---> Kernel---> Init 二.Linux启动顺序 一 ...
- Delta3d框架学习--程序启动过程详解
一个Delta3d程序启动过程详解 一.初始化一个dtGame::GameApplication的实例,dtGame::GameApplication* app = new dtGame::GameA ...
- 朱老师ARM裸机学习笔记(四):S5PV210启动过程详解
常用器件特性 内存: SRAM 静态内存 特点就是容量小.价格高,优点是不需要软件初始化直接上电就能用 DRAM 动态内存 特点就是容量大.价格低,缺点就是上电后不能直接使用,需要软件初始化后才可以使 ...
最新文章
- win 复制linux文件命令行,windows与Linux间远程拷贝文件(pscp命令)
- php鼠标已入移除,angularjs鼠标移入移出实现显示隐藏
- python大数据搜索_python语言-用 Python 实现一个大数据搜索引擎
- matlab生成二维服从高斯分布的数据
- error CS1061:
- 计算机网络第4版潘爱民_【每日一题笔试】第 25 天
- 动作分析 姿态估计_单人或多人的人体姿态骨架估计算法概述
- 算法,求1亿个数的中位数
- ruby在类中访问@,类外访问调用方法
- Android 自动动画布局更新 使用,在RecyclerView上使用布局动画(Layout animation)
- 华为盒子 原生android,手把手教你刷机把华为悦盒刷机为安卓网络机顶
- 普元EOS在运算逻辑里面调用HttpServletRequest ,HttpServletResponse
- 视频加密软件技术小分享
- 【VMware】vmware15 安装win10教程【史上最详细图文教程】
- malloc用户态内存分配
- 全网最便宜的OpenHarmony开发板和模组Neptune问世(基于联盛德W800的SoC),9.9元带蓝牙和wifi功能还包邮
- 美国股票市场上市规则摘要纽约证券交易所
- 【毕业设计】基于stm32的示波器设计与实现 - 单片机 嵌入式
- 作业要求20190919-2 功能测试
- matlab 编程计算θ0的变化对三相短路电流的影响(电力系统暂态分析)
热门文章
- 【深度学习】利用深度可分离卷积减小计算量及提升网络性能
- Keras【Deep Learning With Python】机器学习和线性回归
- python【蓝桥杯vip练习题库】ADV-69质因数(数论)
- python【蓝桥杯vip练习题库】BASIC-20 数的读法
- python【蓝桥杯vip练习题库】BASIC-27 2n皇后问题(八皇后问题 搜索)
- 全卷积神经网路【U-net项目实战】Unet++
- Tensorflow【实战Google深度学习框架】—Logistic regression逻辑回归模型实例讲解
- PHP 实现一个可用的redis 事务锁, 解决并发问题
- linux内核编译 menuconfig详解,Linux内核编译menuconfig介绍
- 怎么做网络推广浅析网站如何设置导航栏可以使网站优化更好?