BizTalk SQL Adapter
处理多部分消息BUG及修正
作者:郑佐
日期:2007-11-8
摘要
前段时间,在实施BizTalk Server应用项目的时候碰到一个多部分消息的问题,采用了好几种方式来尝试解决,最终失败。后来联系上海微软的BizTalk技术支持工程师,确认是BizTalk Adapter for SQL Server处理多部分消息的一个Bug,幸好已经有补丁可用,问题得到解决。如果有朋友碰到类似问题,不妨参考本文进行处理。
应用环境
系统:Windows Server 2003 企业版
BizTalk
版本:BizTalk Server 2006 企业版
数据库版本:SQL Server 2005 企业版
测试程序
笔者通过测试程序来模拟问题的重现。
先来建立数据库存储过程和Xml消息架构。然后制定业务流程,成功部署后进行物理端口绑定。
数据库使用通用的Northwind数据库,以下是存储过程示例:
CREATE
PROCEDURE [dbo].[AddOrder1]
(
@CustomerID NCHAR(5),
@OrderDate DATETIME
)
AS
DECLARE
@OrderID INT;
INSERT
INTO Orders
(
CustomerID ,
OrderDate
)
VALUES
(
@CustomerID ,
@OrderDate
)
SET
@OrderID = SCOPE_IDENTITY();
SELECT
@OrderID AS OrderID FROM Orders
WHERE
OrderID = @OrderID
FOR
XML AUTO,ELEMENTS
该存储过程的功能是向Orders表中插入一条订单数据,同时返还生成的订单OrderID。
通过存储过程导出的Xml架构如下:
<?xml version="1.0" encoding="utf-16"?>
<xs:schema xmlns:b="http://schemas.microsoft.com/BizTalk/2003" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://SqlAdaptertest" version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:annotation>
<xs:appinfo>
<msbtssql:sqlScript value="exec [AddOrder1] @CustomerID=NULL, @OrderDate=NULL" xmlns:msbtssql="http://schemas.microsoft.com/BizTalk/2003" />
</xs:appinfo>
</xs:annotation>
<xs:element name="Message">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="AddOrder1">
<xs:complexType>
<xs:attribute name="CustomerID" type="xs:string" />
<xs:attribute name="OrderDate" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Result">
<xs:complexType>
<xs:sequence>
<xs:element name="Success" type="xs:anyType" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
可以发现,笔者对AddOrder1元素的maxOccurs属性进行了修改 ,使其支持多个记录进行插入。
<xs:element maxOccurs="unbounded" name="AddOrder1">
不过这个修改也变成了“问题所在”。
订单报文Xml架构如下:
<?xml version="1.0" encoding="utf-16"?>
<xs:schema xmlns:b="http://schemas.microsoft.com/BizTalk/2003" xmlns="http://Content_Route.SchemaOrder" targetNamespace="http://Content_Route.SchemaOrder" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Root">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="Order">
<xs:complexType>
<xs:attribute name="CustomerID" type="xs:string" />
<xs:attribute name="OrderDate" type="xs:dateTime" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
对两个Schema建立映射:
笔者在业务流程中定义了一个双向逻辑端口。设置通信模式为“请求-响应”。端口通信方向为设置为 “我将发送请求并接收响应”。设置送达通知为“已传输”。
业务流程如下:
部署BizTalk项目,在BizTalk Server 2006管理控制台“应用程序”节点下面选择已部署成功的应用程序,为业务流程添加“静态要求响应发送端口”。在传输类型中选择“SQL”。在“SQL传输属性”对话框中设置“连接字符串”、“文档目标命名空间”和“响应文档根元素名称”。文档目标命名空间和响应文档根元素名称同通过存储过程导出的XSD架构对应,设置发送管道为“XMLTransmit”,设置接收管道为“XMLReceive”。绑定其他物理端口。
启动BizTalk应用程序。
通过xml架构生成一个测试报文:
<ns0:Root xmlns:ns0="http://Content_Route.SchemaOrder">
<Order CustomerID="ALFKI" OrderDate="1999-05-31T13:20:00" />
<Order CustomerID="ALFKI" OrderDate="1999-05-31T14:20:00" />
</ns0:Root>
把测试报文放入接收位置。
查询Northwind数据库Orders表,有两条记录插入。在BizTalk Server管理控制台中查询发现有消息挂起。
消息部分内容如下:
BodyPart1:
<Result xmlns="http://SqlAdaptertest"><Orders><OrderID>11088</OrderID></Orders></Result>
BodyPart2:
<?xml version="1.0" encoding="utf-16" ?><Result xmlns="http://SqlAdaptertest"><Orders><OrderID>11089</OrderID></Orders></Result>
可以看到以上多部分消息内容包含了生成的OrderID。
查看系统日志,看到下面错误:
事件类型: 错误
事件来源: XLANG/s
事件种类: 无
事件 ID: 10036
日期: 2007-11-1
事件: 14:15:10
用户: N/A
计算机: NB-ZZ
描述:
未捕获的异常(请参阅下面的“内部异常”)已经挂起服务“NBEport.Manifest.Process(9948a1f5-e2d4-736a-cc11-edcc76b22338)”的一个实例。
在管理性地恢复或终止该服务实例前,它将保持挂起状态。
如果恢复了该服务实例,它将从上次持续的状态继续,这可能再次引发同样的异常。
实例 ID: 9d8ac1ea-f1f9-41f4-bbe4-90b32deff504
形状名称:
形状 ID:
引发异常的位置: 段 -1,进程 -1
内部异常: 多部分消息“H2KManifestSQLResult”的正文部分为“BodyPart2”,应为“BodyPart1”。
异常类型: WrongBodyPartException
源: Microsoft.XLANGs.BizTalk.Engine
目标站点: Void ReadMessageState(Microsoft.XLANGs.Core.Envelope, Microsoft.XLANGs.BaseTypes.XLANGMessage)
下面是一个堆栈跟踪,用于标识发生异常的位置
在 Microsoft.BizTalk.XLANGs.BTXEngine.BTXXlangStore.ReadMessageState(Envelope env, XLANGMessage msg)
在 Microsoft.BizTalk.XLANGs.BTXEngine.BTXPortBase.ReceiveMessage(Int32 iOperation, Envelope env, XLANGMessage msg, Correlation[] initCorrelations, Context cxt, Segment s)
在 NBEport.Manifest.Process.segment2(StopConditions stopOn)
在 Microsoft.XLANGs.Core.SegmentScheduler.RunASegment(Segment s, StopConditions stopCond, Exception& exp)
解决思路
笔者第一想到的是编写自定义管道组件,对经过自定义管道的多部分消息进行处理,合并多部分消息到单个消息中,可惜就算让消息只包含一部分还是失败。通过“业务流程调试器”发现消息无法让“接收”形状进行处理。
只能试试定义一个XmlDocument类型的消息绑定到“接收”形状,不过验证了我的直觉是对的,多部分消息应该无法在一个XmlDocument中包含。
接着结合上面两种方式进行尝试,还是失败。调整管道使用非Xml管道组件结果一样。
最后,还是向微软BizTalk工程师咨询,用掉我一个远程技术支持事件。解决方案让人郁闷,原来是BizTalk Server SQL适配器的一个Bug。下面的KB有详细记录。
FIX: Error message when you use the BizTalk Adapter for SQL Server to process multipart messages: "Uncaught exception"
http://support.microsoft.com/?id=918316
不过该补丁在外部找不到下载的地方,由微软内部提供,估计以后可能会出BizTalk Server 2006 SP1之类的补丁集合。更新Microsoft.biztalk.adapter.sql.dll组件后,重新启动BizTalk服务,问题解决。