有很长一段时间,我的工作内容几乎都是 Web 应用程序。当我要构建一个智能客户端应用 程序时,起初我觉得非常困惑,不知该如何构建这样的应用程序。怎么处理数据访问?智能客 户端应用程序与服务器之间如何通信?
而且,我那时已经投入很多,拥有一些能够显著减少开发时间和成本的工具,而我真的希望 可以继续使用这些工具。我花了一段时间来深入考虑各种细节问题,在这期间,我一直在想如 何让 Web 应用程序更简单些呢,当然我需要先知道如何处理这样的应用程序。
智能客户端应用程序有利有弊。从有利的一面看,智能客户端反应灵敏,能够改进与用户的 交互性。如果您将处理移到客户端计算机,还能减轻服务器的负载,而且即使与后端系统断开 连接,用户也能照常工作。
另一方面,智能客户端又有一些固有的问题,包括通过 Intranet 或 Internet 访问数据时 需要解决速度、安全性和带宽限制等问题。您还要负责在前端与后端系统之间实现数据同步、 处理分布式的更改跟踪,以及处理在偶尔连接的环境中使用时出现的问题。
本文中讨论的智能客户端应用程序可以使用 Windows Presentation Foundation (WPF) 或 Silverlight 构建。由于 Silverlight 具备一部分 WPF 功能,因此我在此处介绍的技巧和方 法同时适用于这两种工具。
在本文中,我将使用 NHibernate 进行数据访问,使用 Rhino 服务总线实现与服务器之间 的可靠通信,从而开始规划和构建智能客户端应用程序的过程。我要构建的应用程序名为 Alexandra,是一个在线借阅图书馆的前端系统。该应用程序本身分成两大部分。第一部分是运 行了一组服务的应用程序服务器(大部分的业务逻辑都在此服务器上),使用 NHibernate 访 问数据库。第二部分是智能客户端 UI,让用户轻松使用上述那些服务。
NHibernate 是一个对象关系映射 (O/RM) 框架,旨在让用户轻松使用关系数据库,就像使 用内存中的数据一样。Rhino 服务总线是构建在 Microsoft .NET Framework 上的开源服务总 线,其主要目的是让部署、开发和使用变得轻松自如。
职责的分配
构建借阅图书馆的第一步是正确分配前端系统和后端系统各自的职责。一种途径是让应用程 序主要负责 UI,以便大部分的处理都在客户端计算机上进行。在这种情况下,后端服务器几乎 就是一个数据存储库。
从本质上说,这就是传统的客户端/服务器应用程序,后端系统只是作为数据存储的代理。 如果后端系统只是一个数据存储库,这不失为一种有效的设计选择。例如,这种体系结构可能 很适合个人图书目录,因为这种应用程序的作用就是为用户管理数据,服务器端不需要对数据 进行操作。
对于这样的应用程序,我建议您使用 WCF RIA 服务或 WCF 数据服务。如果您希望后端服务 器向外界提供一个 CRUD 接口,则使用 WCF RIA 服务或 WCF 数据服务能让您显著减少构建应 用程序所需的时间。尽管这两种技术都允许您将自己的业务逻辑添加到 CRUD 接口中,但是任 何通过添加逻辑来实现重要应用程序功能的尝试最终都可能导致不可收拾的混乱局面。
我在本文中不会探讨如何构建这样的应用程序,不过 Brad Adams 在他的博客 blogs.msdn.com/brada/archive/2009/08/06/business-apps-example-for-silverlight-3- rtm-and-net-ria-services-july-update-part-nhibernate.aspx 中详细介绍了使用 NHibernate 和 WCF RIA 服务构建这种应用程序的操作步骤。
与上述完全不同的方法是,您可以选择在后端实现应用程序的大部分功能,而前端只是负责 显示。这种方法初看起来似乎是合理的,因为通常您就是这样编写基于 Web 的应用程序的,但 这也意味着您不能在客户端运行真正的应用程序。状态管理将会变得更困难。从本质上说,您 仍是在编写 Web 应用程序,其所有复杂问题都不可避免。您将无法把处理转移到客户端计算机 ,也不能处理连接中断的问题。
更糟的是,从用户角度而言,这种方法意味着您展示的 UI 很迟钝,因为所有操作都需要先 传递到服务器再返回。
我敢肯定,我在本例中采用的方法居于上述二者之间,这件事不会让您感到惊讶。我要在客 户端计算机上运行以充分利用由此带来的各种机会,但同时,应用程序的大部分功能将作为服 务在后端运行,如图 1 所示。
图 1 应用程序的体系结构
该示例解决方案包括三个项目,您可以从 github.com/ayende/alexandria 下载。 Alexandria.Backend 是包含后端代码的控制台应用程序。Alexandria.Client 包含前端代码, Alexandria.Messages 包含在前两者之间共享的消息定义。若要运行该示例, Alexandria.Backend 和 Alexandria.Client 都需要运行。
将后端托管在控制台应用程序中的一个好处就是,您可以方便地模拟连接断开时的情景:只 需先关闭后端控制台应用程序,之后再重新打开。