摘要:本文主要介绍BizTalk如何同SQL Server Xml数据类型结合实现消息访问与存储,并说明这种实现方式为设计基于消息的系统架构带来的诸多优点。环境要求:BizTalk Server 2006 R2,SQL Server 2005/2008,Visual Studio 2005,C#。
本页内容
概述
微软在推出SQL Server 2005/2008数据库管理系统后,增加了许多新功能,尤其在Sql和Xml的结合上得到显著加强,新增加的Xml数据类型支持Xml文档或文档片段存 储,同时SQL Server还提供了XQuery语言子集对Xml进行查询操作,为技术人员带来更多的设计灵活性。BizTalk Server作为微软的EAI/B2B平台产品,提供企业服务总线(ESB)能力,整个平台架构以Xml为核心,灵活的扩展架构和同其他系统快速集成能力 是其一大特点。本文将探讨BizTalk如何使用SQL Xml数据类型来访问和存储Xml消息,最后说明这种实现方式为设计基于消息的系统架构带来的诸多优点。
准备工作
在开始代码实现之前,我们需要做一些准备工作,包括Xml报文设计和SQL数据库设计。我们先来设计一个简单的xml测试报文,下面显示报文内容。
<Message>
    <Id>MVP32143</Id>
    <Name>Zhengzuo</Name>
    <Description>C#,BizTalk Server,SQL Server.</Description>
</Message>
上述报文结构比较简单,根元素不带目标命名空间,因此我们也不打算为报文编写Xml Schema,如果需要提取报文里面的具体内容,可以在BizTalk业务流程中编写XPath查询实现。
接下去我们通过T-SQL在SQL Server中建立一个测试数据库,同时建立MessageTable数据表。MessageTable数据表包含两个列:
Column Name
Data Type
comment
Id
uniqueidentifier
非业务主键
Data
Xml
用来存放报文内容
Xml数据类型没有指定强类型架构,使得Data列可以包含任何Xml文档或文档片段。下面的T-SQL语句为MessageTable写入一条测试数据以备消息访问使用。
INSERT INTO dbo . MessageTable
(
    Id ,
    Data
)
VALUES
(
    NEWID (),
    '<Message>
    <Id>MVP32143</Id>
    <Name>Zhengzuo</Name>
    <Description>C#,BizTalk Server,SQL Server.</Description>
    </Message>'
)
消息访问
BizTalk访 问SQL Server中的Xml类型数据比较简单,对于SQL数据库的查询操作实际通过SQL Adapter来进行,在BizTalk项目开发过程中,可以通过安装在Visual Studio 2005里面的SQL适配器向导把T-SQL查询语句或存储过程导出到Xml Schema。我们通过Visual Studio 2005建立名为BizTalkUseSqlXmlType的BizTalk项目,接下去对于BizTalk相关的程序代码都将在该项目中编写。
比起直接编写T-SQL语句来返回Xml数据块, 笔者更喜欢使用SQL存储过程,这样模块耦合性低而执行效率可能会高一些,而且代码更容易维护。下面的存储过程返回一条Xml数据,由于出于演示目的因此 通过TOP 1提取1条数据后,并没有添加DELETE操作来删除该条记录。
CREATE PROCEDURE [dbo] . [BTS_GetXmlMessage]
AS
BEGIN
    SET NOCOUNT ON ;
    SELECT TOP 1 Data FROM dbo . MessageTable AS SqlData
    FOR XML AUTO , ELEMENTS ;
END
接下去我们在BizTalkUseSqlXmlType项目中通过“SQL传输架构生成向导”来生成该存储过程对应的Xml Schema,不幸的是在向导执行过程中会出现“无法执行SQL语句。请确保提供的语法正确。”的错误提示,但是通过SQL Management Studio执行BTS_GetXmlMessage存储过程可以正常返回下面的Xml数据。
< SqlMessage >
 < Data >
    < Message >
      < Id >MVP32143 </ Id >
      < Name >Zhengzuo </ Name >
      < Description >C#,BizTalk Server,SQL Server. </ Description >
    </ Message >
 </ Data >
</ SqlMessage >
不难发现问题应该出在Xml数据查询上,目前的BizTalk开发工具好像还无法很好的支持通过T-SQL导出 Xml数据类型到架构,还有对某些T-SQL的FOR XML语法也支持不够,比如FOR XML RAW和FOR XML PATH等。
针对这个问题,我们可以在BizTalk项目中手 动建立同BTS_GetXmlMessage存储过程返回的Xml结构匹配的Xml Schema来解决,对于建立的架构只需额外添加文档根元素和目标命名空间即可,根据上面查询返回的Xml消息建立Schema如下,设置架构类型名称为 SqlSelectMessage。
<?xml version="1.0" encoding="utf-16"?>
<xs:schema xmlns:b="http://schemas.microsoft.com/BizTalk/2003" xmlns="http://BizTalkUseSqlXmlType.SqlSelectMessage" targetNamespace="http://BizTalkUseSqlXmlType.SqlSelectMessage" xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xs:element name="Root">
    <xs:complexType>
      <xs:sequence>
        <xs:element minOccurs="0" name="SqlMessage">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="Data">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element name="Message">
                      <xs:complexType>
                        <xs:sequence>
                          <xs:element name="Id" type="xs:string" />
                          <xs:element name="Name" type="xs:string" />
                          <xs:element name="Description" type="xs:string" />
                        </xs:sequence>
                      </xs:complexType>
                    </xs:element>
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
 </xs:element>
</xs:schema>
注意:根据上述架构定义,BizTalkUseSqlXmlType项目在BizTalk Server中部署时架构中的根元素名称和目标命名空间需要同物理接收位置的SQL Adapter中的参数设置相对应。
消息存储
SQL Server 2005提供了对Xml数据类型的支持,在BizTalk程序设计中,我们可能需要把处理中的Xml消息持久化到Xml数据类型字段的应用需求,那么先来编写Xml数据写入到MessageTable表的存储过程。
CREATE PROCEDURE [dbo] . [BTS_InsertXmlMessage]  
@XmlData nvarchar ( max )
AS
BEGIN
    SET NOCOUNT ON ;
    INSERT INTO dbo . MessageTable ( Id , Data ) VALUES ( NEWID (), @XmlData );
END
存储过程中的@XmlData参数实际包含了Xml消息内容,字段类型设置为nvarchar(max),通过SQL适配器向导为BTS_InsertXmlMessage存储过程生成Xml Schema,定义类型名称为SqlInsertMessage。
<?xml version="1.0"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://BizTalkUseSqlXmlType.InsertMessage" version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xs:annotation>
    <xs:appinfo>
      <msbtssql:sqlScript value="exec [BTS_InsertXmlMessage] @XmlData=NULL" xmlns:msbtssql="http://schemas.microsoft.com/BizTalk/2003" />
    </xs:appinfo>
 </xs:annotation>
 <xs:element name="SqlRequest">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="BTS_InsertXmlMessage">
          <xs:complexType>
            <xs:attribute name="XmlData" type="xs:string" />
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
 </xs:element>
 <xs:element name="SqlResponse">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="Success" type="xs:anyType" />
      </xs:sequence>
    </xs:complexType>
 </xs:element>
</xs:schema>
我们继续在 BizTalkUseSqlXmlType项目中添加SqlInsertOrchestration业务流程来接收最初的消息并转换成 SqlInsertMessage类型消息最后通过SQL Adapter存入到MessageTable表中。下图显示了消息写入SQL Server的业务流程设计方案。
 

原始消息(OriginalMessage)从 Port_Receive接收端口进入业务流程,通过消息构造模块生成SqlMessage消息,最终通过Port_Send端口发送消息到SQL Adapter,SQL Adapter调用BTS_InsertXmlMessage存储过程写入消息数据到MessageTable表。OriginalMessage消息类 型设置为System.Xml.XmlDocument类型,以便用来接收所有Xml类型的消息,而SqlMessage消息类型设置为 BizTalkUseSqlXmlType.SqlInsertMessage.SqlRequest架构,同BTS_InsertXmlMessage 存储过程关联。
业务流程定义了三个变量来辅助 SqlMessage消息的创建。Variable_MessageData变量为System.String类型,用来引用 OriginalMessage消息的Xml文本内容。Variable_XmlString变量为System.String类型,用来引用生成 SqlMessage消息的Xml文本内容。Variable_XmlDoc变量为System.Xml.XmlDocument类型,通过加载 Variable_XmlString最终生成SqlMessage消息。
我们来看一下业务流程中赋值表达式内容的初期版本代码。
Variable_MessageData = OriginalMessage.DocumentElement.OuterXml;
Variable_XmlString = "<ns0:SqlRequest xmlns:ns0=/"http://BizTalkUseSqlXmlType.InsertMessage/">"
+"<ns0:BTS_InsertXmlMessage XmlData=/""
+Variable_MessageData
+"/" />"
+"</ns0:SqlRequest>";
Variable_XmlDoc.LoadXml(Variable_XmlString);
SqlMessage = Variable_XmlDoc;
很明显,上面的代码在执行到“Variable_XmlDoc.LoadXml(Variable_XmlString);” 语句就会出现异常,因为Variable_XmlString 直接拼接Variable_MessageData后会生成一个非法的xml字符串。为避免这种错误,笔者对SqlInsertMessage架构进行属 性升级,使得XmlData属性变成可分辨字段,修改后的赋值表达式代码如下。
Variable_MessageData = OriginalMessage.DocumentElement.OuterXml;
Variable_XmlString = "<ns0:SqlRequest xmlns:ns0=/"http://BizTalkUseSqlXmlType.InsertMessage/">"
+"<ns0:BTS_InsertXmlMessage XmlData=/"/" />"
+"</ns0:SqlRequest>";
Variable_XmlDoc.LoadXml(Variable_XmlString);
SqlMessage = Variable_XmlDoc;
SqlMessage.BTS_InsertXmlMessage.XmlData = Variable_MessageData;
对BizTalkUseSqlXmlType项目进行成功编译后,部署BizTalk项目到BizTalk Server环境中,在接收位置配置FILE Adapter接收最初制定的测试报文。
<?xml version="1.0" encoding="utf-8" ?>
<Message>   
 <Id>MVP32143</Id>
 <Name>Zhengzuo</Name>
 <Description>C#,BizTalk Server,SQL Server.</Description>
</Message>
通过调试器对BizTalk Server业务流程处理该消息的过程进行跟踪,在业务流程执行过程中,我们发现生成的SqlMessage消息内容如下所示。
<ns0:SqlRequest xmlns:ns0="http://BizTalkUseSqlXmlType.InsertMessage">
 <ns0:BTS_InsertXmlMessage XmlData="&lt;Message&gt;    &#xD;&#xA; &lt;Id&gt;MVP32143&lt;/Id&gt;&#xD;&#xA; &lt;Name&gt;Zhengzuo&lt;/Name&gt;&#xD;&#xA; &lt;Description&gt;C#,BizTalk Server,SQL Server.&lt;/Description&gt;&#xD;&#xA;&lt;/Message&gt;" />
</ns0:SqlRequest>
业务流程执行完成后,查询 MessageTable表,数据已经正确写入,不过读者可能会产生疑问,XmlData属性包含的值被经过了处理并且正确的写入到了 MessageTable表中,那么我们继续打开SQL Server Profiler对BTS_InsertXmlMessage存储过程进行跟踪,下面是SQL Server Profiler显示的跟踪消息。
exec sp_executesql N'exec [BTS_InsertXmlMessage] @XmlData=@P1',N'@P1 nvarchar(131)',N'<Message>   
 <Id>MVP32143</Id>
 <Name>Zhengzuo</Name>
 <Description>C#,BizTalk Server,SQL Server.</Description>
</Message>'
看来BizTalk对这种行为进行了处理,使得Xml数据被转换并正常写入数据库。我们不妨执行下面的T-SQL看看会发生什么。
EXEC dbo . BTS_InsertXmlMessage '&lt;Message&gt;    &#xD;&#xA; &lt;Id&gt;MVP32143&lt;/Id&gt;&#xD;&#xA; &lt;Name&gt;Zhengzuo&lt;/Name&gt;&#xD;&#xA; &lt;Description&gt;C#,BizTalk Server,SQL Server.&lt;/Description&gt;&#xD;&#xA;&lt;/Message&gt;'
结果在MessageTable中插入了带“&lt;”,“&gt;”的未转换文本。查询MessageTable表可以看到两条完全不一样数据。
之前,笔者第一感觉是需要写一些C#代码或做一些 特殊的处理才能把报文数据保存到SQL数据库的Xml数据类型字段中,比如在BizTalk中对报文内容进行Base64编码,然后在SQL Server中对报文内容进行解码,或者进行字符串替换之类的操作,看来这项工作不需要在这里进行了。
 

系统架构设计
通过对Xml消息存储的实现,笔者认为对基于消息 的系统架构设计带来诸多优点,在BizTalk同SQL Server等数据库管理系统集成应用的场景中,BizTalk Server的处理不涉及业务数据的操作,只负责消息入库,从而可以有效降低BizTalk Server和SQL Server之间建立的分布式事务资源的消耗。另外,BizTalk处理子系统可以在多台服务器上运行,而消息处理队列表可以在多台数据库服务器上建立, 这样可更容易实现分布式处理架构。
在系统开发方面,这样的处理模式可对各个系统之间 的功能职责做进一步划分,BizTalk不需要关心消息内包含的具体业务数据,只需负责把Xml消息存入SQL Server数据处理队列表。SQL Server集成服务或其他应用系统访问数据队列表,通过SQL和XQuery语言分析Xml消息内的业务数据,并可以按需提取业务数据写入到业务数据表 或进行其他应用处理。这样,BizTalk开发人员和SQL Server开发人员可以各司其职,分工合作完成相关程序模块。
在系统测试和部署方面,这样的架构模式使得系统测试和部署工作变得更加容易,BizTalk子系统和数据库子系统可以独立测试,两者唯一的耦合点就是消息队列数据表。另外,两者可以独立部署,互不影响。
结束语
本文主要介绍了如何应用SQL Xml实现BizTalk消息的访问和存储,并基于这种处理方式对基于消息的系统架构设计影响进行探讨。
Logo

开源、云原生的融合云平台

更多推荐