silverlight应用:使用 Silverlight 构建业务线企业级应用程序 第 1 部分

使用 Silverlight 构建业务线企业级应用<img src='/icons/77919chengxu.gif' /><img src='/icons/77919dou.gif' />第 1 部分

  本文源代码下载地址:

  http://flashview.ddvip.com/2009_02/AdvCallCenter_slent_part1_v0.01.zip

  目录

  Silverlight 基础:CoreCLR

  Silverlight 运行时

  应用方案

  使用套接字服务器推送通知

  异步 I/O 循环

  Silverlight 中模式对话框

  推送通知实现

  TCP 服务跨域访问

  TCP 服务跨域策略

  整理总结

  最近我为休斯敦家大型公司管理层演示了 Silverlight 商业潜质但反响并不强烈此次演示展现了深度缩放、画中画、高清晰视频和高清晰动画本来应该很容易吸引受众通过调查我了解到虽然图片十分精彩但对于在实际中使用 Silverlight 构建以数据为中心企业级业务线 (LOB) 应用演示指导意义很小因此受众兴趣不大

  目前企业级应用需要跨网络边界(通常要通过 Internet)安全递送 LOB 信息而且还需要使用适应业务环境基于角色 UI 和数据裁剪在客户端运行 Silverlight 并在服务器上运行 Microsoft .NET Framework 3.5 就能出色地构建此类可伸缩且安全 LOB 应用在沙箱中运行轻型 Silverlight 运行时为和后台管理数据服务集成提供了框架库为了使用 Silverlight 构建可靠应用架构师和开发人员需要理解 Silverlight 编程模型及其在实际应用环境中框架功能

  本文主要目是讨论 LOB 方案并从头构建个应用全程解说 Silverlight 开发方方面面我将讨论解决方案是个呼叫中心应用其逻辑体系结构如图 1 所示在本期内容中侧重点是屏幕弹出通知、异步编程模型、Silverlight 对话框和跨域 TCP 策略服务器实现在第 2 部分中我将讨论应用安全性、Web 服务集成、应用分区等

使用 Silverlight 构建业务线企业级应用<img src='/icons/77919chengxu.gif' /><img src='/icons/77919dou.gif' />第 1 部分

  图 1 Silverlight 呼叫中心逻辑体系结构

  Silverlight 基础:CoreCLR

  开始的前让我们先温习下 Silverlight 基础知识我先深入介绍 Silverlight 运行时以便您可以更好地理解 Silverlight 能够提供功能CoreCLR 是 Silverlight 使用虚拟机它类似于为 .NET Framework 2.0 及更高版本提供强大功能 CLR也包含相似类型加载和垃圾收集 (GC) 系统

  CoreCLR 采用非常简单代码访问安全性 (CAS) 模型——它比桌面 CLR 更简单Silverlight 只需要在应用级别强制实施安全策略这是作为独立于平台 Web 客户端它不能依靠任何特殊现行企业或机器策略而且也不应该允许用户更改现有策略但也有些例外情况比如 OpenFileDialog 和 IsolatedStorage(存储配额更改)在这种情况下Silverlight 需要用户明确同意才能打破沙箱默认规则集OpenFileDialog 用于访问文件系统而 IsolatedStorage 作用是访问名义上隔离存储并提高存储配额

  对于桌面应用每个可执行都加载个 CLR 副本并且操作系统进程仅包含个应用每个应用都有个系统域、个共享域、个默认域和多个显式创建 AppDos(请参阅“JIT 和运行:深入 .NET Framework 内核了解 CLR 如何创建运行时对象”)CoreCLR 中也存在相似域模型就 Silverlight 而言几个应用(可能来自区别域)将在同个操作系统进程中运行

  在 Internet Explorer 8.0 中每个选项卡都在其自身独立进程中运行;因此在同个选项卡内托管所有 Silverlight 应用都将在相同 CoreCLR 例子上下文中运行如图 2 所示由于每个应用可能来自区别源域所以出于安全原因考虑每个应用都将被加载到其自身 AppDo可以说 CoreCLR 例子数量和当前托管 Silverlight 应用选项卡数量相等

  和桌面 CLR 类似每个 AppDo 均将获得自已静态变量池每个特定于域池将在 AppDo 启动进程期间

使用 Silverlight 构建业务线企业级应用<img src='/icons/77919chengxu.gif' /><img src='/icons/77919dou.gif' />第 1 部分

  图 2 每个 Silverlight 应用都将在其自身 AppDo 中运行

  Silverlight 应用不能创建其自身自定义应用该功能已保留供内部使用有关 CoreCLR 更详细讨论请参考下面来自 CLR 团队(Team)“CLR 全面透彻解析”专栏:“使用 CoreCLR 编写 Silverlight”和“Silverlight 2 中安全性”

  Silverlight 运行时

  Silverlight 针对多种需要区别程度框架和库支持应用而设计例如简单应用可能只需要播放几个字节音频文件就能帮助读出某个字典网站WebSite上单词发音或者只需要显示个标题栏广告但是企业级 LOB 应用则需要考虑安全性、数据隐私、状态管理、和其他应用和服务集成以及分析支持等等和此同时Silverlight 还需要保持较小运行时以便在较慢链路上通过 Internet 进行部署时不会出现问题

  这些需求彼此间有冲突但 Silverlight 团队(Team)通过将框架划分为图 2 中所示层级来化解矛盾CoreCLR + Silverlight 运行时合称为“插件”所有用户都可以在运行应用的前安装该插件对于大多数以消费者为中心应用来说该插件已足够满足需要如果某个应用需要使用 SDK 库(WCF 集成或 DLR 运行时如 Iron Ruby)或自定义库那它必须将这些组件封装到 XAP 包中以便使 Silverlight 能够了解如何在运行期间解析所需类型(请参阅本期领先技术专栏了解更多有关 XAP 信息)

  Silverlight 运行时(不算 CoreCLR 库如 agcore.dll 和 coreclr.dll)大小约 4MB它包含应用开发人员所需必要库其中包括以下基本库:mscorlib.dll、.dll、.Net.dll、.Xml.dll 和 .Runtime.Serialization.dll支持浏览器插件运行时通常安装在 C:Program FilesMicrosoft Silverlight2.0.30930.0 目录下当计算机下载并安装 Silverlight 时将在 Web 浏览会话中创建该目录

  在同台机器上构建和测试应用开发人员会使用运行时两个副本:个通过插件安装个通过 SDK 安装后者位于 C:Program FilesMicrosoft SDKsSilverlightv2.0Reference Assemblies 目录下Visual Studio 模板将使用此副本作为编译时引用列表部分

  沙箱会阻止 Silverlight 应用和大多数本地资源交互点对任何典型 Web 应用都适用默认情况下Silverlight 应用无法访问文件系统(除独立存储外)、无法建立套接字连接、无法和连接到计算机设备交互也不能安装软件Software组件这显然会对能够在 Silverlight 平台上构建应用类型有所限制但是Silverlight 具备开发数据驱动企业级 LOB 应用所需全部功能这类应用需要和后端业务进程和服务集成

  应用方案

  我将在这里构建 LOB 应用演示了种第 3方呼叫控制体系结构该结构中台中央服务器接入专用交换分机 (PBX) 基础结构以集中控制电话我关心是作为 UI 表层 Silverlight所以对电话集成就带而过我将使用简单呼叫模拟器生成传入呼叫事件该模拟器将把代表呼叫数据包加入呼叫管理器等待队列这将触发本项目核心进程

  我假想方案要求呼叫中心应用以独立于平台方式在 Web 浏览器内部运行但同时还需要能够提供足以媲美桌面应用丰富用户交互Silverlight 是自然而然选择 ActiveX 在非 Windows 客户端环境中并不流行

  让我们看下该应用体系结构您需要实现推送通知、事件集成、业务服务集成、缓存Cache、安全性以及和云服务集成

  推送通知 这是项必需功能系统需要捕获传入呼叫事件并传递由呼叫方输入交互式语音响应 (IVR) 数据以完成“屏幕弹出通知”或使用传入呼叫信息填充 UI 屏幕此外还应该为用户提供接听或拒绝呼叫机会

  事件流 在典型 Web 应用 Web 服务器会执行大量业务流程所以它了解业务事件所有信息但就富 Internet 应用 (RIA) 而言业务流程实现会在 Web 浏览器中运行应用和实现业务 Web 服务服务器的间共享这意味着在 Silverlight 应用中生成业务事件和技术事件需要通过组特定 Web 服务发送到服务器

  本解决方案案例中业务事件举例发生在用户 (rep) 拒绝呼叫 ("rep rejected the call") 或接受呼叫 ("rep accepted the call") 时典型技术事件是“Connection to Call Manager TCP server failed”(连接到 Call Manager TCP 服务器失败)和“Web service exception”(Web 服务异常)

  业务服务集成 和任何其他 LOB 应用此呼叫中心解决方案需要和存储在关系数据库中数据集成我将使用 Web 服务作为集成载体

  缓存Cache 为了获得更好用户体验我将在本地内存和磁盘上缓存Cache信息缓存Cache信息可能包括用于指明用户提示脚本 XML 文件和其他不会经常更改引用数据

  安全应用 安全性是此类应用基本要求安全性包括身份验证、授权、工作和休息期间数据隐私性以及基于用户配置文件数据裁剪

  和云服务集成 和基于云基本服务(如存储服务)集成需要特殊服务器端基础结构这样就能针对责任性和服务级别严密地监控和调节云服务使用

  我将在本文第 2 部分中介绍和业务服务集成、应用安全性、Web 服务跨域策略和应用分区

  使用套接字服务器推送通知

  屏幕弹出是呼叫中心应用将呼叫上下文从电话基础结构传递到代理屏幕基本要求的传递呼叫上下文可能包括呼叫客户讲述(适用 IVR 系统)或键入任何信息

  通知可以采用以下两种方式发送给浏览器中 Silverlight 应用:通过客户端轮询或服务器推送轮询非常容易实现但它可能不会是呼叫中心方案最佳选择在该方案中电话事件和客户端应用的间状态同步需要非常精准正是出于此原因我将使用 Silverlight 套接字实现推送通知

  Silverlight 重要功能的是和 TCP 套接字通信出于安全考虑Silverlight 只允许连接 4502 到 4532 的间服务器端口这是沙箱中实现众多安全策略的个重要沙箱策略是 Silverlight 不能是侦听器因此它不能接受入站套接字连接基于上述原因我将创建侦听端口 4530 套接字服务器并维护连接池其中每个连接代表个活动呼叫中心用户

  Silverlight 套接字运行时还在服务器上强制对所有套接字连接实施跨域可选策略当 Silverlight 应用代码试图打开到许可端口号上某个 IP 端点连接时(该过程对用户代码不透明)运行时将使用端口号 943 建立到具有相同 IP 地址 IP 端点连接此端口号已硬编码到 Silverlight 实现中无法通过应用配置或由应用开发人员更改

  图 1 显示策略服务器在体系结构中位置 Socket.ConnectAsync 时消息流序列如图 3 所示按照设计消息 2、3 和 4 对用户代码完全不透明

使用 Silverlight 构建业务线企业级应用<img src='/icons/77919chengxu.gif' /><img src='/icons/77919dou.gif' />第 1 部分

  图 3 Silverlight 运行时自动为套接字连接请求跨域策略

  我需要在和呼叫管理器服务器相同 IP 地址上建立个策略服务器我可以在单个操作系统进程中建立这两个服务器但为简单起见我将在两个独立控制台中实现它们这些控制台可以轻松地转换为 Windows 服务并能针对故障转移识别群集以提供可靠性和可用性

  异步 I/O 循环

  .NET Framework 3.5 为套接字引入新异步编程 API;它们是以 Async 结尾思路方法我将在服务器上使用思路方法是 Socket.AcceptAsync、Socket.SendAsync 和 Socket.ReceiveAsync异步思路方法通过使用 I/O 完成端口为高吞吐量服务器应用执行了优化并通过可重用 SocketAsyncEventArgs 类有效地接收和发送缓冲区管理

  由于不允许 Silverlight 创建 TCP 侦听器所以其 Socket 类仅支持 ConnectAsync、SendAsync 和 ReceiveAsyncSilverlight 仅支持异步编程模型点不仅适用于套接字 API而且适用于所有网络交互

  由于我将同时在服务器和客户端上使用异步编程模型所以让我们先熟悉些设计模式种重复设计模式是 I/O 循环它适用于所有 Async 操作首先我将介绍典型同步执行套接字 accept 循环如下所示:

_listener.Bind(localEndPo);
_listener.Listen(50);
while (true)
{
  Socket acceptedSocket = _listener.Accept;
  RepConnection repCon =
   RepConnection(acceptedSocket);
  Thread receiveThread = Thread(ReceiveLoop);
  receiveThread.Start(repCon);
}
  同步 accept 非常直观且易于编程和维护但该实现无法真正具备服务器可伸缩性每个客户端连接都有专用线程如果连接很频繁则几个连接就容易导致该实现达到峰值

  为了使 Silverlight 能够在浏览器运行时环境中正常工作它应该尽可能少干预资源前面所示 " accept" 伪代码中所有都会阻塞其执行线程并因此对可伸缩性产生负面影响因此Silverlight 在阻塞方面限制很多实际上它只允许和网络资源进行异步交互异步循环需要调整思维模式您可以假想它是个不可见信箱并且它任何时候都包含至少个请求以便使循环能够工作

  图 4 显示了个 receive 循环(代码下载中包含更完整实现)在该实现中并没有类似于前面同步套接字 accept 伪代码中所示 while (true) 无限循环编程结构习惯使用这种编程结构对于 Silverlight 开发人员来说至关重要为了使 receive 循环能够在已接收并处理完消息后继续接收数据队列中至少应包含个对已连接套接字关联 I/O 完成端口请求典型 async 循环如图 5 所示它适用于 ConnectAsync、ReceiveAsync 和 SendAsync在使用 .NET Framework 3.5 服务器上可以将 AcceptAsync 添加到此列表

使用 Silverlight 构建业务线企业级应用<img src='/icons/77919chengxu.gif' /><img src='/icons/77919dou.gif' />第 1 部分图 4 使用 Silverlight 套接字 Async Send/Receive 循环

public CallNetworkClient
{
  private Socket _;
  private ReceiveBuffer _receiveBuffer;
  public event EventHandler<EventArgs> _disibledevent=>   {
    ;
   }
   _receiveBuffer.Off e.BytesTransferred;
    (_receiveBuffer.IsMessagePresent)
   {
     (OnReceive != null)
    {
      NetworkMessage msg =
            NetworkMessage.Deserialize(_receiveBuffer.Buffer);
      _receiveBuffer.AdjustBuffer;
      _disibledevent=>

  图 5 异步套接字循环模式

  在图 4 中所示 receive 循环中ReceiveAsync 是可重入思路方法 ReceiveAsync(SocketAsyncEventArgs recvArgs) 包装此思路方法将对套接字 I/O 完成端口请求进行排队.NET Framework 3.5 中引入 SocketAsyncEventArgs 在 Silverlight 套接字实现中具有相似作用它可以在多个请求的间重复使用从而避免垃圾收集改动回调例程负责提取消息、触发消息处理事件并将下个 receive 项加入队列以便继续循环

  为了处理接收不完整消息情况ReceiveCallback 会在将另个请求加入队列的前调整缓冲区NetworkMessage 包装在 ReceiveArgs 例子中并被传递给外部事件处理以便处理接收到消息

  将部分消息(如果有)复制到缓冲区开头后每次完成 NetworkMessage 接收后都会重置缓冲区服务器上也使用相似设计但实际实现可从循环缓冲区中受益

  为实现“呼叫接受”方案您需要创建个可扩展消息体系结构该结构应使您能够序列化和反序列化包含任意内容消息而无需为每则新消息重写序列化逻辑

使用 Silverlight 构建业务线企业级应用<img src='/icons/77919chengxu.gif' /><img src='/icons/77919dou.gif' />第 1 部分

  图 6 序列化 NetworkMessage 类型布局

  此消息体系结构非常简单:每个 NetworkMessage 子对象在例子化时使用合适 MessageAction 声明其签名由于源代码级别兼容性NetworkMessage.Serialize 和 Deserialize 实现可以在 Silverlight 和 .NET Framework 3.5(服务器上)上工作序列化消息布局如图 6 所示

  不必在消息开始处插入长度信息您可以使用 "begin" 和 "end" 标记和适宜转义序列将长度信息编码到消息中能够大大简化缓冲区处理

  每个序列化消息前 4个字节都将包含它后面序列化对象字节数Silverlight 支持位于 Silverlight SDK .Xml.dll 内 XmlSerializer代码下载中包含有序列化代码您会注意到它对子类(如 RegisterMessage)或其他消息(包括 UnregisterMessage 和 AcceptMessage)没有任何直接依赖关系系列 XmlInclude 注释将帮助序列化在序列化子类时正确地解析 .NET 类型

  NetworkMessage.Serlialize 和 Deserialize 使用如图 4 中 ReceiveCallback 和 SendAsync 所示在 receive 循环中实际消息处理由 NetworkClient.OnReceive 事件附加事件处理完成我可以在 CallNetworkConnection 内处理消息但如绑定接收处理来处理消息则有助于通过在设计阶段将处理和 CallNetworkConnection 分离提高可扩展性

  图 7 显示了 Silverlight 应用 RootVisual它将启动 CallNetworkClient(如图 4 所示)所有 Silverlight Control控件都连接单个 UI 线程而且只有当代码在该 UI 线程上下文中执行时才能更新 UISilverlight 异步编程模型在线程池工作线程上执行网络访问代码和处理所有 FrameworkElement 派生类(如 Control、Border、Panel 和大多数 UI 元素)都会继承 Dispatcher 属性(来自 DispatcherObject)它可以在 UI 线程上执行代码

  在图 7 中MessageAction.RegisterResponse 会通过匿名委派使用代理呼叫中心转移详细信息更新 UI委派执行后得到更新 UI 如图 8 所示

使用 Silverlight 构建业务线企业级应用<img src='/icons/77919chengxu.gif' /><img src='/icons/77919dou.gif' />第 1 部分图 7 处理传入消息 Silverlight UserControl

Tags:  silverlight是什么 silverlight.2.0 silverlight silverlight应用

延伸阅读

最新评论

发表评论