Christian Thilmany 和 Jim Keane
本文将介绍以下内容:
• | CAB 和 Smart Client Software Factory 概述 |
• | 集成式桌面的体系结构 |
• | 构建和部署智能客户端 |
• | 使用模块集成传统应用程序 |
本文涉及以下技术:
• | Visual Studio 2005、CAB、Smart Client Software Factory |
代码下载位置:
SmartClient2006_09.exe (12394KB)
![]() |
CAB 工作原理 |
![]() |
构建简单的 CAB 应用程序 |
![]() |
Smart Client Software Factory 简介 |
![]() |
基本的智能客户端服务 |
![]() |
集成式桌面的功能层 |
![]() |
集成传统 Web 应用程序 |
![]() |
对未来的展望 |
我们已将大部分注意力集中在为信息工作者提供业务智能 (BI) 工具上面,以帮助他们作出更明智的决策。其中的大多数企业 BI 解决方案都是通过各种资源,尤其是通过使用某种形式的服务器端信息集成来提供信息。无论是用于汇总数据的报告系统、类似于 Microsoft® SharePoint® 的协作工具,还是用于提供业务流程管理的自定义企业应用程序集成 (EAI) 解决方案,此信息发挥的实际作用才是重点。无需过多考虑如何使用此信息。
对于大多数活动来说,信息工作者在制定决策时需要参考以下几个应用程序:用于查看门户站点的 Web 浏览器、用于访问 EAI 解决方案的自定义应用程序以及用于读取数据汇总的报表查看器。随着时间的推移,通过学习如何跨应用程序边界手动收集和整理数据,工作人员在工作方面是越来越精通。这通常要通过启动 Microsoft Outlook®、Word、Excel®、Internet Explorer® 以及由公司提供的各种自定义应用程序等一系列过程来实现。这种转椅集成形式会产生不良后果:对新用户的培训时间过长、系统不能以正确的形式为正确的人员提供正确的信息、引入了数据错误问题,等等。那么,提供一个由部署模型包围的安全集成和托管载体,从而使这种形式的应用程序集成变得更方便,是不是会更有效呢?
多数开发人员认为面向服务的体系结构 (SOA) 是提供信息的方式,而不是使用信息的方法。但您如何处理所有的自动化孤岛呢?由此引入了集成式桌面这一观点。
作为解决方案体系结构,我们旨在简化不断扩展的业务应用程序领域并丰富用户的经验,但是,其中最难以达到的一个目标就是跨过在桌面上运行的多个应用程序无缝集成解决方案。诸如 DDE、OLE、COM、mailslot 及类似技术已全部用于解决本地应用程序集成问题。但得到的却是经过高度耦合、容易遭到破坏的桌面应用程序,而维护和部署这些应用程序却要花费高昂的代价。
集成式桌面是侧重于桌面的已连接系统体系结构的最新部分。集成式桌面是一个松散耦合的托管体系结构,也是在桌面上运行的复合 UI,它由后端的松散耦合体系结构予以支持。它大大减少了必须由用户处理的应用程序的数目,并将一切置于单片“玻璃”下。构建集成式桌面应用程序所需的全部技术已事先存在于 .NET Framework 中。但是,时至今日所面临的主要挑战仍是如何将它们无缝集成在一起。
集成式桌面策略的潜在方向是启动服务。虽然体系结构并非一定需要服务结构,但对于构建组合企业桌面的策略而言,服务结构却是必要的。集成式桌面应用程序的松散耦合本质就是对启用服务后端的自然适用。保持松散耦合体系结构的属性可顺利完成部署,但这些种类的体系结构在部署时常常会遇到干扰。
对于 Microsoft,实现集成式桌面的基础层是新一代 Composite UI Application Block (CAB) 和 Smart Client Software Factory。对于精心制作个人桌面框架和自定义应用程序的解决方案架构师而言,将这两个工具结合起来使用将会提供强大的功能。(继续之前,请先熟悉一下提要栏“基本术语”中出现的术语。)
CAB 是用于构建复杂的智能客户端应用程序的模式和概念的实现。简单来说,它提供 Windows® Forms 探测功能,以帮助构建企业桌面应用程序。
由于仅介绍 CAB 就能占据整篇文章的篇幅,而且其中有几个组件还超出了本文所探讨的范围。因此,我们将侧重于 CAB 的主要组件,但建议您下载该部分内容并做深入的研究。 从访问 CAB 社区站点开始。
CAB 旨在支持多种应用程序方案,如在线事务处理 (OLTP) 前端、客户端门户以及信息工作者应用程序。由于 CAB 是模块化设计且接触面积较小,因此,它不但适用于大型集成式桌面,甚至还适用于简单的智能客户端。
利用 CAB,可通过正确解耦界面的各组成部分来共享单个智能客户端界面的开发任务。最终,CAB 改进了重复使用,并能够轻松实现内部应用程序工作流之类的概念。为了能够重复使用,通过使用 CAB 框架构建的复合 UI 被分为多个工作部件。驱动程序是应用程序的外壳,它相当于托管可执行程序及用于加载复合 UI 部件的引导程序。由外壳加载和显示的 UI 元素为用户提供“接触点”,如菜单和其他导航组件。外壳与应用程序部件自行松散耦合,因此,它为 UI 设计提供了一种灵活的方法。虽然外壳和 CAB 服务握着方向盘,但必须由您为引擎提供将由外壳托管的应用程序。
除了为托管可重用的部件提供框架之外,CAB 还为诸如加载模块、通信消息、保持状态等任务提供了一套智能客户端核心服务。可通过代码或应用程序的 .config 文件来添加这些服务。这些核心服务包括:
模块加载程序和模块枚举服务是基于提供商的服务,用于对列在配置目录中的模块的读取和加载操作进行控制。
事件代理服务用于在部件间以及由复合 UI 托管的子应用程序间传递消息。
身份验证服务是基于提供商的服务,它负责询问用户的凭据、访问证书以及联系后端数据提供商。
状态持久性服务是基于提供商的存储服务,它用于保存工作项状态,以便共享上下文数据,以及暂停工作项并在稍后重新激活。
要为 CAB 应用程序构建引擎,通常需要首先创建一个 CAB 模块。模块将为您的个人功能集提供一个可部署入口点(有时称为托管的应用程序)。模块包含在各自的 DLL 文件中并在运行时从外壳加载。对于哪些模块可用以及加载哪些模块,这是完全可以进行配置的,这由可扩展程序目录来实现。如果您熟悉 Microsoft Enterprise Library,您会在 CAB 中识别出同一提供程序模型。在 Visual Studio® 中,无需直接在外壳项目中引用模块,而且模块从未直接绑定到可执行程序。而是在运行时由模块加载程序加载这些模块。
在模块程序集内部,可借助 CAB 和 Smart Client Software Factory 类型(如 Presenter、SmartPart 和 State)提供实现该功能集所必需的工作项、视图、控制器和数据。尤其是这三项形成了基于 CAB 应用程序的 Model-View-Presenter/Model-View-Controller (MVP/MVC) 模式。当应用程序逻缉需要时,注入服务。这允许开发人员以动态方式创建新的对象实例或返回已在容器中创建的对象。对于 CAB 来说,该容器是工作项,而且也是模块开发人员最先创建的内容之一。可通过使用 AddNew,将 CAB 组件(如客户端服务和工作区)显式添加到该容器中:
_rootWorkItem.WorkItems.AddNew<WorkItemA>();
也可通过配置或以声明的方式来实现这一操作:
[CreateNew] public ShipNewOrderViewPresenter Presenter { set { _presenter = value; _presenter.View = this; } }
在容器(工作项)范围内,也可根据需要,以声明的方式将这些组件解除引用。这就提供了一种松散耦合方式,以获得对所有包含在内的、由 CAB 管理的项的访问权限(注入),如下所示:
[ServiceDependency] public WorkItem WorkItem { set { _workItem = value; } }
CAB 的一个关键组件是对象生成器(也供新版本的 Enterprise Library 使用)。只要实现此依赖性注入,对象生成器就能启用大量有用的功能。它能够在适当的时候创建一个新的具体类实例或返回现有的类实例;它能够在某个类提供多个实例时,选择合适的构造函数;它能够响应属性和方法中所声明的属性 (attribute),这些属性 (attribute) 会影响新对象的创建和命名;它还能够提供拆除工具,通过反转操作链,将设置从现有的对象中删除。
对象生成器的实用性很低,并且在多数情况下,您不能直接与其交互。然而,了解“依赖性注入”的概念对于了解如何将服务插入到模块中是非常重要的,而且在调试时这些知识会对您大有帮助。有关“依赖性注入”和 CAB 中所使用的其他模式的详细信息,请参考 CAB 文档。
可按照您希望的方式划分模块。每个模块至少应存在一个工作项,另外的工作项作为该模块的驱动程序。像其他任何应用程序或子应用程序一样,也可按照您的意愿确定工作项的大小。在 CAB 应用程序中,事件的典型顺序与以下类似:
1. |
用户双击用于显示外壳的 EXE。 |
2. |
外壳引导桌面,加载任何已配置的 CAB 服务,显示其 UI 元素,然后加载所有已配置的模块。 |
3. |
当被加载后,每个模块都会将一个工作项添加到其父工作项来控制该子应用程序,并让此工作项在所提供的工作区中显示其任一内容。 |
4. |
当被加载后,每个模块都会将一个工作项目添加到其父工作项目来控制该子应用程序,并让此工作项目在所提供的工作区中显示其任一内容。 |
5. |
当用户从菜单中选择一个 UI 元素时,即会引发相关联的命令。 |
6. |
命令处理程序会通过添加一个子工作项目来响应该命令,该工作项目将控制另一个子应用程序并显示其视图。 |
7. |
该工作项目通过智能部件显示其视图。 |
8. |
用户与视图接口进行交互,随后视图接口再传递一个控制器(或表示器)。 |
9. |
控制器更改共享数据(状态)并使用事件代理将数据传回主机。 |
10. |
事件代理将该相关信息(上下文)发送到其他模块或部件。 |
CAB 模块可以是独立的整体,也可以是由外壳所托管的一个大型模块集的一部分。多模块智能客户端是 CAB 真正体现其灵活性和设计的亮点所在。此灵活性主要体现在,您根本不必在加载模块程序集的外壳项目中直接引用模块程序集,因为它们将在运行时由 CAB 加载。此外,单个模块中的各个部件可以相互通信,也可以与外部模块(均包含在其各自的程序集中)中运行的各部件进行通信。
现在,让我们构建一个单模块应用程序。首先,我将粗略说明如何创建一个简单的智能客户端。(我将在后文中讨论更复杂的集成式桌面。)
多数集成式桌面都具有一个可见的启动窗体,因此您通常都从一个“Windows 窗体”外壳开始操作。首先,从 FormShellApplication 继承您的类并将其实例化,然后从您的应用程序的 Main 方法调用其 Run 方法。这将初始化 CAB 应用程序,从而加载我们先前讨论的任何已配置服务。下一步涉及到覆盖 FormShellApplication 提供的方法(例如 AfterShellCreated)以填充菜单和显示任何可见视图。(智能部件是可选项,它们只是用 SmartPartAttribute 装饰的用户控件。)
要在实现 AfterShellCreated 时初始化用户界面,您需要将 CAB 所引用的内容注册为扩展站点。这会提供一个 UI 元素管理器,以便任何模块在以后任何时候都可以添加来自任何模块的子 UI 元素(例如,菜单项或工具栏项)。最后,在外壳对通常也在此初始化期间添加的 UI 元素命令进行加载或响应时,您开始显示您的视图。由于各命令绑定了命令处理程序,因此您的代码在运行时可以对任何普通 UI 元素引发的任何命令作出响应;这与添加通常的事件处理程序相似,只不过方式更为抽象一些。
可通过使用 SmartPartPlaceHolder 类或 CAB 中称为工作区的区域来显示视图。它们只是用于以给定排列方式显示视图的布局容器。如果您曾使用过 Java 抽象窗口工具包 (AWT),您就应熟悉此概念。
最后,要创建外壳,请注册一个接口并显示一个智能部件。提要栏中的“创建简单的智能客户端:分步指南”详细介绍了如何构建一个非常简单但模块化的智能客户端。要展现 CAB 的真正功能,您应使用模块将您的各部件封装到各自的程序集中。这为您提供了设计时抽象以及类似于 COM 提供的运行时抽象,但消除了所有复杂性。
使用各模块,您可以托管通过功能集自身的程序集部署的独立功能集。这意味着各组织可以在不影响整个集成式桌面的情况下对各个模块进行版本处理、部署和功能增强。模块程序集文件(不直接在 EXE 中引用)在运行时通过模块加载程序和枚举服务进行加载。CAB 的配置文件目录和应用程序配置文件使您可以指定要将哪些模块加载、部署和绑定到外壳中。提要栏中的“创建模块和模块初始化程序”将逐步向您介绍创建模块及其初始化程序的过程。我所罗列出的步骤清楚描述了如何创建一个简单的 CAB 应用程序。但是请注意,我们此处论及的只是问题的表面。
随 CAB 一起安装的“Bank Teller”快速入门示例是一个现成的单模块 CAB 应用程序。它将向您介绍我在此处所概述的所有关键组件。
当然,当构建真正的企业集成式桌面时,会涉及到更多内容,而不仅仅是复合的 UI 块这么简单。您需要解决大量复杂问题,例如,如何在模块间共享信息、如何将非 CAB 应用程序集成到桌面中、如何处理安全问题以及如何控制布局。
在创建企业就绪型应用程序时,除了 CAB 提供的核心服务之外,您还需要其他类的基础服务。这些服务包括帮助您在部署、安全性和置备等方面管理桌面的工具。您可能还需要日志记录、工作流、配置和缓存处理之类的服务,以确保所有模块在这样松散耦合的环境中正常运行。
Smart Client Software Factory 可以通过提供指南和引用实现来助您一臂之力。Smart Client Software Factory 不仅仅是一个工具包,它还提供了智能客户端基本核心服务的使用入门集,以帮助您着手建立企业就绪型集成式桌面。
所有服务均可视为可选服务和可扩展服务。Smart Client Software Factory 构建于 CAB 和 Enterprise Library 之上,并利用了现有应用程序块。图 1 例示了借助 Smart Client Software Factory 构建的智能客户端服务的体系结构。
图 1 智能客户端服务
因为多数公司都需要一组常用服务,因此 Microsoft 已将一个相关资产集合内置于 Smart Client Software Factory 中。它们由两个引用实现来凸显,这两个引用实现可将典型经验映射到 Smart Client Software Factory 内所包含的服务。“引用实现 1”模拟了“贷款评估桌面”并利用了离线工作能力、最终用户通知和其他类似功能。“引用实现 2”模拟了“银行职员桌面”(Bank Teller 示例的一个多模块版本)以演示安全服务、部署服务和主题服务。
指南包所提供的帮助对构建企业应用程序非常有价值。它们使用相对较新的 Guidance Automation Toolkit (GAT)(该工具包是对 Visual Studio 2005 的扩展)构建而成。在使用 GAT 时,团队开发人员可以提供启动工具包(或 SDK),这样其他开发人员就可以在将来添加模块和其他 ID 部件。Smart Client Software Factory 包括一个必不可少的元素,即用于智能客户端开发的 Visual Studio Guidance Package。这是由指导 ID 开发人员经历整个 CAB 开发生命周期的工具、模式、源代码和说明性指导组成的一个集成式集合。若想了解详细信息以及下载 GAT,请访问 msdn.microsoft.com/vstudio/teamsystem/Workshop/gat/default.aspx。
集成式桌面构建于 Smart Client Software Factory 和 CAB 之上。它应采用一个可重用集合的形式,这个集合由 CAB 扩展、Smart Client Software Factory 实现、普通基础服务以及可整体或部分添加到任何现有复合 UI 应用程序中的库组成。这就构成了“集成式桌面框架”,其中包含一些基本服务。
上下文服务 这是创建集成式桌面的最重要元素之一。它也很可能是最容易被理解错误的元素之一。当使用由若干模块组成的 CAB 应用程序时,您通常会采用某种形式的信息共享。例如,您的 CAB 应用程序可能包括一个外壳、一个用于显示客户信息的模块、一个用于显示汇总数据的标题模块、一个搜索模块以及其他任务特定的模块。其中每一个模块都可以单独开发、部署和维护。如果您想探究如何实现这些任务,可以借助提供了相关“方法”的 CAB。但您还需要确定“内容”,也就是将在这些模块之间共享的信息。这可能仅指客户 ID。事件代理会将“上下文已更改”这样的事件进行全局通信,并且所有模块都会在相应时间显示相应信息。您将广播客户 ID 这样的事实说明它是要共享的信息,并且这形成了“上下文”的前提。
上下文服务只用于广播和检索这些共享信息,在某种程度上,这与企业桌面所提出的策略一致。您应采用一组基本的上下文类型及其相应的架构合约才能在您的桌面中提供其他任何服务。这类似于 SOA 中所使用的“合约至上”的设计实践。您并不是要遵守在 Web 服务端点所定义的合约,而是要在桌面自身的各部件之间定义这些相同的合约。实际上,在构建集成桌面应用程序时,也存在 EAI 或 SOA 项目中存在的相同难题。
部署服务 这些服务通过确保各个模块可以在运行时部署到桌面来提供集成式桌面应用程序及其部件。一个选择是将部署服务构建于 ClickOnce API 之上。这些服务应该对要下载到桌面的特定可选模块提供服务器端控制。当外壳启动时,身份验证服务将为部署服务提供证据来证明:已为用户启用特定模块,这样,如果这些模块已不存在,则必须将其下载到桌面。模块将被下载,并由模块加载程序进行加载,然后在需要时显示给用户。CAB 使您可以向配置文件目录添加用户角色。部署服务的实现程序可以轻松地扩展通常的模块加载程序服务以利用此功能,因为 CAB 在模块加载程序扩展中将只对在当前附加到运行主体的已知角色条件下被授权运行的模块调用加载。
安全服务 与上下文服务不同,安全服务非常易于理解。您可以将其构建于所提供的在 CAB 中已有的身份验证服务之上。这为使用自定义身份验证服务提供了一个起点,并提供了一种向集成式桌面应用程序统一添加身份验证逻辑的方法。使用 CAB 和 Smart Client Software Factory 提供的服务及指南,您可以将各角色添加到各个模块中,以指明这些模块与特定角色相关联。这使您可以根据登录者的角色控制要加载哪些模块,并可以启用其他功能(例如您的部署服务)来控制实际要将哪些模块部署到桌面。
集成服务 如果受管的 Windows 窗体应用程序是要集成到智能客户端中的唯一候选程序,则部署单个企业桌面就没有太大用处。通常需要集成大量的预编写(传统)应用程序,以便它们在保持自治性的同时仍可作为桌面体验的一部分。其中包括不是用 .NET 创建的 Web 应用程序、ASP.NET Web 应用程序、COM 应用程序,甚至包括绿屏。
Smart Client Software Factory 中的集成服务提供了将这些服务中的某些服务内置于您的集成式桌面中的指南。本文将特别介绍一种类型的传统桌面应用程序集成 - Web 应用程序。我们将向您介绍 CAB 和 Smart Client Software Factory(及其指南包)如何帮助您构建一个可以采用任何 Web 应用程序并可以轻松将其托管的 Web 模块。
一个集成式桌面由三层组成:基础层、平台层和应用程序层。在开发 ID 解决方案时,了解这些层以及它们将影响体系结构的哪些等级是至关重要的。图 2 例示了这些层与集成式桌面体系结构中各个级别之间的关系。
图 2 集成式桌面体系结构
基础层 该层包含了 CAB 提供的所有核心客户端服务,以及可以由任何模块或智能部件使用的安全性和部署之类的服务。这些服务代表了桌面的联合水平组件。CAB 和 Smart Client Software Factory 均提供了基础层的主要部分。在构建“集成式桌面框架”时,首先需要着手处理的就是该层及其相应的客户端服务。
平台层 该层针对的是提供特定于平台或技术的元素(例如由传统服务处理的元素)的服务。它由模块或智能部件开发人员可用来合并部件(要考虑到它们所源于的平台)的组件构成。如果您有多个 Web 应用程序需要集成到桌面,则提供可重用的客户端 Web 应用程序服务来作为“集成式桌面框架”的一部分将有助于托管这些应用程序。例如,您可能想要使用已经在生产环境中运行的现有购物车应用程序。来自平台层的服务可以用于在桌面托管此应用程序,使其像其他任何受管模块一样工作。Smart Client Software Factory 提供了一组传统服务来作为该层的一部分。
应用程序层 仅包含应用程序和可重用的客户端业务功能,此应用程序层提供了特定于业务的客户端服务。该层由您通常需要进行交互的模块组成,例如搜索模块、客户信息模块和购物车模块。
在 CAB 应用程序中托管现有 Web 应用程序所需要的不仅仅是向智能部件添加一个浏览器控件。客户端集成的要点是所有应用程序(或模块)均已完全集成。这意味着它们可以双向通信和共享信息。直到 CAB 可用,此功能才可行,但解决方案只是说明性的,离可重复使用还差得很远。
但正如上面提到的,现在可以创建 Web 模块来托管任何 Web 应用程序。而且您可以做到这些,无需任何其他模块了解其中的差异。现有模块从未需要改变它们共享信息的方式。
现在我们将逐步介绍构建简单 Web 模块(如图 3 中所示的模块)的过程,这要依赖于由 Smart Client Software Factory 团队提供的指南。我们使用 CAB 服务以及由 Smart Client Software Factory 提供的新的指南包。
图 3 由 Web 模块托管的 Web 应用程序
您需要做的第一件事是新建一个 Web 应用程序或扩展现有的应用程序。本示例概述了创建新 ASP.NET Web 应用程序的步骤。您也可以将其用作修改现有 Web 应用程序的模板。我们使用的过程稍微有点侵略性:您必须将 JScript® 添加到应用程序,而且在设计时通过添加代码利用对象模型与 Web 应用程序通信。
在创建样例 Web 页面(该页面将用作典型 Web 应用程序)后,创建一个 Web 模块。但在这样做之前,必须下载以下必备条件:
• | Guidance Automation Extensions (GAX) |
• | Composite UI Application 指南包(确保在当前解决方案中启用此功能) |
• | Composite UI Application Block |
• | 包含到 CAB 库和 Smart Client Software Factory 的适当引用的简单外壳应用程序 |
• | 包含所有可在某些其他模块和应用程序库中重复使用的公用代码的库项目 |
作为 Smart Client Software Factory 的一部分,诸如 Microsoft.Practices.SmartClient.Web.WebPresenter 和 Microsoft.Practices.SmartClient.Web.WebView 之类的类提供基本探测功能,以便使用 CAB 的事件代理自动映射由 Web 页面触发的事件。从而使任意 Web 模块能够利用内置于 CAB 中的默认通信机制,并能够使所有事件自动流入和流出 Web 页面。Microsoft.Practices.SmartClient.Web.WebView 继承自浏览器控件,可在 Web 模块中重复使用。
请注意,指南包是可选的,并且仅自动提供您的项目中的一些模板代码,如 Smart Client Software Factory 提供的服务。作为替代方法,您也可以从本文下载样例 Web 页面和 Web 模块。
步骤 1:创建 Web 页面 我们将从创建 Web 页面着手,该页面将用作我们的传统 Web 应用程序。
1. |
新建一个 Web 项目或向现有 Web 项目中添加一个新页面。 |
2. |
或者,向可能包含 Web 应用程序所使用的常量的任何公用库中添加引用。 |
3. |
添加一个 HTML 按钮,其“Text”(文本)属性值为“触发上下文已更改的事件(来自 JavaScript)”。 |
4. |
添加一个 ASP.NET 按钮,其“Text”(文本)属性值为“触发上下文已更改的事件(来自 ASP.NET 服务器)”。 |
5. |
添加一个 HTML 文本框,其 id 为“txtCustomerName”。 |
6. |
在页面的 Page_Load 方法中添加以下代码(仅在使用 ASP.NET 服务器控件时才是必需的): ClientScript.RegisterOnSubmitStatement(cstype, Common.Events. ContextChanged, BuildRaiseEvent(Common.Events.ContextChanged)); |
7. |
添加以下 private 方法(也是仅在使用 ASP.NET 服务器控件时才是必需的): private string BuildRaiseEvent(string topic) { StringBuilder sb = new StringBuilder(); sb.Append("window.external.FireEvent(\""); sb.Append(topic); sb.Append("\",0);"); return sb.ToString(); } |
8. |
双击第一个按钮,在 onclick 事件中添加以下代码: window.external.FireEvent("ContextChangedEvent","Param1"); 此代码将触发 Web 页面中的事件,并经由 Smart Client Software Factory 转为 Web 浏览器代码,然后使用事件代理进入智能客户端。 |
9. |
在上一步的 onclick 事件处理程序之后添加以下代码: function EventBroker_Subscribe() { window.external.SubscribeEvent("ContextChangedEvent"); window.external.SubscribeEvent("CustomerContextChangedEvent"); } function EventBroker_ContextChangedEvent() { window.alert("上下文已更改事件:来自 Web 应用程序的问候"); } 通过 Subscribe 事件处理程序,智能客户端可将何时设置事件订阅告诉给 Web 页面(通常在 Web 页面将其自己载入浏览器控件后)。接下来,Web 页面触发并返回到主机,然后调用 SubscribeEvent(Web 页面要订阅的事件)。这样,只要触发该事件,CAB 中的所有全局事件就会从智能客户端流动到 Web 页面。这在 JScript 的 EventBroker_XXX 事件处理程序中捕捉。 |
10. |
添加以下 JScript 函数: function EventBroker_CustomerContextChangedEvent(eventData) { document.getElementById('txtCustomerName').value = eventData.Name; } |
这显示如何将事件数据从智能客户端传递到 Web 页面以及如何在 Web 页面中使用这些数据。
步骤 2:创建 Web 模块 要创建 Web 模块,请首先右键单击解决方案,然后选择“Add”(添加)|“CompositeUI”|“Module”(模块)。在“Add New Project”(添加新项目)对话框中,指定您自己的模块名称。现在,单击“OK”(确定),选择“Shell”(外壳)项目,然后单击“Finish”(完成)。
您会发现已创建了许多新项。一个新的 Web 模块项目已添加到解决方案中。必需的引用(包括 CAB 和 Smart Client Software Factory 库引用)已添加到该 Web 模块项目中。已在新项目中创建了 WorkItems 文件夹,并在该项目中创建了 ModuleInit.cs 文件和类。
步骤 3:新建 WorkItem 新建 WorkItem 相当简单。首先右键单击刚创建的模块中的 WorkItems 文件夹,然后选择“Add”(添加)|“CompositeUI”|“WorkItem”。将名称更改为 WebWorkItem.cs。选择“Shell”(外壳)项目并单击“Finish”(完成)按钮。
此时,您将发现已创建了 WebWorkItem.cs 文件和类。此外,还为 CAB 和 Smart Client Software Factory 添加了 using 指令和必需的引用。
在 ModuleInit 类的 Load 中,添加以下代码:
WorkitemCatalog.RegisterWorkItem<WebWorkItem>();
并将以下 using 指令添加到 ModuleInit.cs 文件的顶部:
using WebModule.WorkItems.WebWorkItem;
步骤 4:新建视图 此步骤解决 Web 页面和智能客户端应用程序(在本例中为 Web 模块)之间的数据交换。
1. |
右键单击 WebWorkItem 文件夹。 |
2. |
选择“Add”(添加)|“CompositeUI”|“View…”(视图…) |
3. |
将名称更改为 WebView,然后单击“Finish”(完成)按钮。这将创建 IWebView 接口、WebPresenter 类和 WebView usercontrol。它们用于实现在整个 Smart Client Software Factory 中使用的典型 MVP 模式。 |
4. |
转到 WebWorkItem 类,然后添加以下代码: public void ShowInView(IShellView view) { WebView webView = this.Items.AddNew<WebView>(); view.MainWorkspace.Show(webView); } 这会将 WebView(一个智能部件)添加到工作项“智能部件”集合的项集合中,并在工作项启动时显示该智能部件。 |
5. |
在设计器模式中打开 WebView UserControl。 |
6. |
从 Smart Client Software Factory 添加 Microsoft.Practices.SmartClient.Web.WebView 控件。 |
7. |
将 Microsoft.Practices.SmartClient.Web.WebView 控件的 Url 属性设置为您刚创建的测试 Web 页面。 |
8. |
转到 WebWorkItem.cs 文件并添加以下 using 指令: using Microsoft.Practices.SmartClient.UI.Themes; |
9. |
打开 WebPresenter 类并添加以下代码: [EventSubscription(Common.Events.ContextChanged, Thread=ThreadOption.UserInterface)] public void OnContextChange(object sender, EventArgs e) { System.Windows.Forms.MessageBox.Show( _ "上下文已更改:来自丰富 UI 组件的问候"); } 这由 Web 页面触发,通过 CAB 事件代理转换为 WebView 代码。 |
10. |
添加以下 using 指令: using Microsoft.Practices.CompositeUI.EventBroker; |
11. |
打开 IWebView 接口并添加以下代码: event WebBrowserDocumentCompletedEventHandler DocumentCompleted; |
12. |
打开 WebPresenter 类并添加图 4 中所示的代码。这允许 Smart Client Software Factory 通过绑定订阅响应 Web 页面加载。加载 Web 页面时,触发 CustomerContextChangedForWebPage 事件。将通过事件代理以 CustomerContextChanged(在 JavaScript 中)形式将其通知给 Web 页面。这是在从智能客户端启动 Web 模块时,上下文或信息从智能客户端流动到 Web 页面的作用,它允许任何 Web 应用程序在响应加载时显示来自智能客户端的任何信息。请注意,发送过程中的覆盖操作并非必要,只是在加载特定事件时引发该事件。 |
13. |
添加以下 using 指令: using System.Threading; using System.Security.Principal; using Microsoft.Practices.CompositeUI.Utility; |
14. |
将以下代码添加到 WebView 类(IWebView 实现): public event WebBrowserDocumentCompletedEventHandler DocumentCompleted { add { this.webView1.DocumentCompleted += value; } remove { this.webView1.DocumentCompleted -= value; } } |
步骤 5:在与外壳应用程序相同的目录中构建和测试 Solution Place WebModule.dll,并将该模块添加到 ProfileCatalog.xml,以便 CAB 模块加载程序服务能够加载它。
最后,按照传递消息时所使用的同一模式,使用事件代理将其传递到其他模块。像启动任何其他 Web 模块一样来启动此 Web 模块。现在,所有全局事件都应从智能客户端流动到 Web 模块,然后再流动回智能客户端。
在我的样例中,讨论如何通过文档对象模型 (DOM) 将 JavaScript 的一个小块传送回托管应用程序。这是使得基于 HTML 的操作窗格能够访问 XML 文档的 DOM 时,InfoPath® 所使用的一项技术。
对于现有的基于 Web 的应用程序而言,这种方法相对来说具有一定的侵略性。它需要更改 Web 应用程序,重新编译该应用程序,然后再对其进行重新部署。让我们想像一下存在这样一种攻击性较小的方法:它允许任何智能部件将必要的集成代码注入到 HTML 页面的 DOM 中,在运行时而不是在编译时执行绑定。当然,还需要执行一定的关于安全影响的严格审查。还要必须将其他功能添加到 Smart Client Software Factory 的事件代理中,以便在智能客户端上下文和 HTML 页面元素之间映射技术。
企业就绪模块的未来是值得期待的。想像一下基于 Windows Workflow Foundation 的工作流模块,它会为基于桌面的工作流方案提供一个全新的托管体系结构。工作流会立刻集成到由集成式桌面托管的现有应用程序中,为信息工作者提供另外一个能够做出决策的集成载体以及一个结构化的任务列表外观。那么,是否能够通过一组工作流模块将整个解决方案重构为耦合在一起的服务岛呢?
这一体系结构正在研发中,而且必须不断地将平台的新功能包括在该体系结构中。持久性是企业级解决方案体系结构的真正测试之一。由 Windows Vista™ 引入的新功能无疑会对我们如何考虑解决方案方法带来挑战,而集成式桌面恰好利用了所兴起的新功能。
Christian Thilmany 是一位技术架构师,在体系结构的设计、开发和咨询方面拥有超过 16 年的经验,曾为各种财富 500 强企业提供咨询服务。在 Microsoft,他擅长于集成、门户以及智能客户端模式和技术。
Jim Keane 是一位技术总监,在德克萨斯州奥斯汀市工作。他曾有 20 多年的计算机行业架构师的经历,在小型企业、航空航天、半导体、保险和过程控制系统等领域具有丰富经验。
本文摘自 2006 年 9 月发行的 MSDN 杂志。