处理事务是构建许多业务逻辑的一个重要方面。但在面向服务的世界中使用事务却很麻烦。分布式事务假设参与各方之间存在高级别的信任,因此一般不适合跨服务边界的事务。但仍然存在一些情况,将事务和服务绑定起来可以起到很好的作用,因此 Indigo 包含了对这一重要的应用程序设计特性的支持。
.NET Framework 2.0 中的事务
Indigo 中的事务支持构建在 .NET Framework 2.0 提供的机制上。这一即将发布的版本中包含 System.Transactions,这是一种新的命名空间,完全专注于控制事务性行为。开发人员将最常将 System.Transactions 与某个“执行上下文”配合使用,这是 .NET Framework 2.0 中的一种新结构。执行上下文允许指定适用于包含在一个定义范围内的所有代码的通用信息,如事务。以下是应用程序如何使用该方法将一组操作组合成一个事务的示例:
using System.Transactions; using (TransactionScope ts = new TransactionScope(Required)) { // 执行操作,例如更新不同的 DBMS ts.Complete(); } |
位于 using 块内的所有操作将成为一个事务的一部分,因为它们共享其所定义的事务执行上下文。本例中的最后一行,调用 TransactionScope 的 Complete 方法,将导致退出该块时请求提交该事务。此方法还提供了内置的错误处理,出现异常时会终止事务。
如本例那样,为新 TransactionScope 指定 Required,意味着此代码将总是作为事务的一部分运行:若其调用方的事务存在,则加入之;若不存在,则创建一个新的。如同在企业服务中一样,还可以指定其他选项,包括 RequiresNew、Supported 和 NotSupported。
与企业服务及其前任 MTS 和 COM+ 不同,Systems.Transactions 完全专注于控制事务性行为。例如,事务与对象的内部状态之间不需要存在连接。企业服务要求一个对象在其结束事务时被停用,但 Systems.Transactions 则没有这种需要。由于 Indigo 建立在 Systems.Transaction 上,因此 Indigo 应用程序也是独立管理事务和对象状态的。
Indigo 中的事务
Indigo 应用程序可以显式使用 System.Transactions,也可以隐式使用依赖于 System.Transactions 的属性来控制事务。一种选择是,对位于标记有 ServiceContract 属性的类中的方法,使用前面所述的 TransactionScope 将其工作包装到一个事务中。例如,该方法可以包含一个 using 语句,建立一个事务范围,然后在该事务内更新两个独立的数据库。
服务的方法还可以使用属性来控制事务性行为。除了显式使用 System.Transactions 外,服务还可以使用前面所述的 OperationBehavior 属性。下面是一个示例:
using System.ServiceModel; [ServiceContract] class XactOperations { [OperationContract] public int Add(int value1, int value2) { return value1 + value2; } [OperationContract] [OperationBehavior(RequireTransaction=true, AutoCompleteTransaction=true)] int Update(int value1, int value2) { // 将 value1 和 value2 插入到 // 两个不同的数据库中 } } |
本例中的第一个方法 Add 没有使用事务,因此其简单操作将和以前一样发生。但是第二个方法 Update 前置有 OperationBehavior 属性,同时 RequireTransaction 属性被设置为 true。因此,该方法中完成的所有工作将发生在一个事务内,就像其位于前面所示的 using 块事务范围内一样。同时由于还指定了 AutoCompleteTransaction 属性,因此如果不出现异常,事务将自动提交。
如果调用此方法的客户端不是运行在事务内,则 Update 方法将在其自己的事务内运行,没有其他选择。但这里假定客户端在调用 Update 时已经是某个现有事务的一部分。Update 方法所完成的工作是否会加入客户端的事务,或其是否仍运行在自己独立的事务中?答案取决于此服务能否接受由客户端传递的“事务上下文”,这是通过 OperationContract 属性的 TransactionFlowAllowed 属性控制的一个选项。如果服务中的一个方法未附加 TransactionFlowAllowed 属性,如上例所示,该方法内所完成的工作将永远不会加入现有事务中。而如果此属性存在,则方法将能够加入其客户端的事务中。
值得强调的还有,基于 Indigo 的应用程序可以参与包含运行于非 Indigo 平台上的应用程序的事务。例如,一个 Indigo 应用程序可以启动一个事务,更新本地 SQL Server 数据库中的记录,然后调用在一个 J2EE 应用程序服务器上实现的 Web 服务,更新另一个数据库中的记录。如果该服务是事务型的,且其运行的平台支持 WS-AtomicTransaction 规范,则两个数据库的更新可以是同一事务的一部分。与安全性和可靠消息传输相似,Indigo 事务工作在 Web 服务导致的异质环境中。
队列
使用绑定(如 WsHttpBinding),Indigo 应用程序可以与基于 Indigo 或任何其他实现了 WS-ReliableMessaging 的 Web 服务平台上的另一个应用程序进行可靠通信。但尽管此规范定义的技术确保了 SOAP 消息的可靠端对端传送,它却不能实现消息队列。使用队列,应用程序只需将消息发送到队列,而不是直接发送到另一个应用程序。当接收应用程序准备好时,它就可以从队列读取消息并进行处理。启用这种交互很有用,例如,当消息的发送方和接收方可能不是同时运行的时候。
因此,Indigo 提供了对消息队列的支持。这种支持建立在 MSMQ 之上,这意味着与 Indigo 的大多数其他特性(如可靠消息传输、安全性和事务等)不同,Indigo 队列并不支持跨供应商边界直接进行互操作(尽管可以使用 MSMQ-MQSeries 桥)。
要使用 Indigo 队列,开发人员需要创建一个标准的 Indigo 服务类,照常使用 ServiceContract 进行标记。但位于此类的服务合同中的操作具有一些限制。特别是,它们必须全部标记为单向,即不返回任何响应。这并不奇怪,因为调用排队的操作是将消息发送到一个队列中,而不是其最终接收方,因此等待立即响应没有任何意义。与其他任何服务类一样,队列 Indigo 应用程序也需要公开终结点。这些终结点使用了一些绑定,例如:NetMsmqBinding,允许与其他队列 Indigo 应用程序进行通信;或 MsmqIntegrationBinding,允许一个队列 Indigo 应用程序与不使用 Indigo 的标准 MSMQ 应用程序进行互操作。Indigo 队列还支持队列环境的其他传统特性,如“死信”队列和有毒消息的处理等。
队列对绝大多数分布式应用程序都是正确之选。Indigo 对这种通信方式的支持是开发人员无需了解完全独立的队列技术即可构建队列应用程序。
六、共存和移植Indigo 代表在可靠、安全和事务型服务时代创建分布式应用程序的一种新型方法。然而,需要理解的一个关键在于,安装 Indigo 不会破坏任何现有的应用程序。运行于 ASMX、.NET Remoting 以及 Indigo 包含其功能的其他技术上的当前代码,均可以继续运行,因而不需要移植到 Indigo。但对于那些拥有对当前 Microsoft 技术的投资的机构,仍然存在一个明显的问题:采用 Indigo 之前的技术编写的现有代码会发生什么情况?
对于因 Indigo 的出现而前途深受影响的每一项当前技术,开发人员需要理解以下两件事:基于此技术的应用程序是否将与基于 Indigo 的应用程序进行互操作,将应用程序从此技术移植到 Indigo 环境需要完成的工作量有多大?以下是对每项技术如何解决这些问题的简短描述:
• | ASP.NET Web 服务 (ASMX):采用 ASMX 建立的 Web 服务会与 Indigo 应用程序进行互操作。由于 ASP.NET Web 服务和 Indigo 两者均支持标准 SOAP,因此这不应该有什么奇怪之处。将现有 ASP.NET Web 服务代码移植到 Indigo 需要进行一些机械性工作,但仍然简单直接。两种技术的基本结构十分相似,因此大体上只有属性和配置文件需要改变。但更高级的特性(如 SOAP 扩展等)将无法直接移植到 Indigo。相反,需要使用 Indigo 提供的扩展选项对它们进行重写。 |
• | .NET Remoting:基于 .NET Remoting 的应用程序不会与基于 Indigo 的应用程序进行互操作,它们的传输协议不兼容。将现有 .NET Remoting 代码移植到 Indigo 需要进行一些工作,但仍然是可能实现的。但是如果一个人建立了自定义的 .NET Remoting 扩展(如通道和接收),将会发现该代码无法映射到新环境。Indigo 中存在相似的扩展,但实现的接口与 .NET Remoting 中实现的接口不匹配。 |
• | 企业服务:为了使现有的企业服务应用程序能够与 Indigo 客户端(或其他基于 Web 服务的软件)进行互操作,开发人员可以精确指定该应用程序中的哪些接口应当公开。使用 Indigo 提供的一个工具,可以自动为那些接口创建服务合同,并通过 Indigo 公开。对于那些不基于 .NET Framework 的企业服务应用程序的现有客户端(以及其他纯粹基于 COM 的客户端),提供了一个 Indigo 名字对象,以允许直接访问 Web 服务。将现有的企业服务应用程序移植为直接在 Indigo 上运行所需的工作与移植 ASMX 应用程序所需的工作类似。尽管不是全部,但大部分工作都是对属性和命名空间的直接机械的修改。 |
• | Web 服务增强 (WSE):WSE 是 Microsoft 为实现需要 WS-* 规范所提供的部分或全部功能的 Web 服务应用程序而采用的一种战术性解决方案。基于 WSE 1.0 和 WSE 2.0 的应用程序不会与基于 Indigo 的应用程序进行互操作。但基于将在 Indigo 发布之前交付的 WSE 3.0 的应用程序将与 Indigo 应用程序进行互操作。对于可移植性,情况与已经介绍的技术类似:将现有代码从 WSE 移植到 Indigo 需要进行一定的工作,但对于使用最后 WSE 版本编写的应用程序这一工作将大大减小。 |
• | MSMQ:由于 Indigo 的队列功能基于 MSMQ,因此基于 Indigo 的队列应用程序可以与直接基于 MSMQ 的队列应用程序进行互操作。将应用程序从初始 .NET Framework 提供的 System.Messaging 命名空间进行移植需要一些工作,因为这种早期接口与 Indigo 所提供的接口不同。一旦 Indigo 交付,开发人员就应使用它而不是 System.Messaging 来创建大多数基于 MSMQ 的队列应用程序。 |
在 Indigo 面世之前,对不需要队列的分布式 .NET 应用程序而言,最佳技术选择大概就是 ASMX。它使用简单,同时提供了移植到 Indigo 的最平滑的途径。企业服务对需要其提供的特性(如分布式事务)的应用程序也很重要,但 MSMQ 仍然是队列应用程序的正确选择。而 .NET Remoting 则应主要用于同一进程中的两个应用程序域之间的通信。对其他大部分情况下的直接应用程序对应用程序通信,ASMX 是一种较好的选择。
引入新软件总是会对已经存在的东西有影响。通过提供构建面向服务应用程序的通用基础,Indigo 为开发人员提供了一种更简单、更统一的平台。尽管这种改变会引起一些痛苦,但 Indigo 创建者们的目标是使这种转换尽可能平滑和简单。
七、结论Indigo 代表了在开发人员创建软件的方式方面的一项重大进步。随着面向服务的应用程序越来越普遍,Indigo 将成为 Windows 软件开发人员的主流技术。其他 Microsoft 产品也将转而利用 Indigo 所带来的优点。例如 BizTalk Server,将在 BizTalk Server 2006 发布后的某个时候加入对 Indigo 作为一种通信选项的支持。由于 Indigo 为面向服务的软件提供了一种标准基础,因此它将成为大部分 Windows 通信的基础。
这一技术的影响势必不会小。任何人要在 Windows 上构建分布式应用程序,特别是那些必须与其他平台上的应用程序进行互操作的应用程序,都应当给予密切关注。Indigo 将极大地改变他们的世界。