Biztalk WCF Adapter 提供了Biztalk与其它支持WCF或是Web Service通信支持。这里介绍使用Messaging (非Orachestration)调用Web Service碰到的问题及解决方法。
为Biztalk 应用添加一个WCF Adapter的步骤一般如下:
1. 使用visual studio 创建一个Biztalk Project ,然后Add ->Add Generated Items
选中Consume WCF Service
一般如果Web Service在线的话,使用第一个选项自动获取MEX endoint ,输入Web Service 的URL,Visual Studio 会自动生成该Web Service所需的Schema及Binding文件:
2. 使用biztalk admin console 将生成的binding import 到对应的Biztalk应用中
查看对应的Send Port对应,比如:
这时再配置好对应的Receive Port,就可以来测试这个WCF Adapter了。
上面的Web Service提供了多个方法可以调用,对应到Soap Action Header 对应会有如下定义:
<BTSActionMapping>
< Operation Name=”Operation1″ Action=”Action1″>
< Operation Name=”OperationN” Action=”ActionN”>
< /BTSActionMapping>
Biztalk WCF Adapter 在收到XML消息时,需要根据消息Context 中定义的BTS.Operation 内容然后对照BTSActionMapping 选择合适的方法调用Web Service。
对于Web Service提供的方法多于一个时,Biztalk会报告 InvalidOperationException异常:
The adapter failed to transmit message going to send port “WcfSendPort_EpisysWS_EpisysWSHttpSoap12Endpoint” with URL “http://192.168.247.128:8080/WebServicesFramework/services/EpisysWS.EpisysWSHttpSoap12Endpoint/”. It will be retransmitted after the retry interval specified for this Send Port. Details:”System.InvalidOperationException: An action mapping was defined but BTS.Operation was not found in the message context.
at Microsoft.BizTalk.Adapter.Wcf.Runtime.WcfClient`2.LookupAction(IBaseMessageContext messageContext)
at Microsoft.BizTalk.Adapter.Wcf.Runtime.WcfClient`2.SendRequestMessage(IBaseMessage bizTalkMessage, IRequestChannel channel)
at Microsoft.BizTalk.Adapter.Wcf.Runtime.WcfClient`2.SendMessage(IBaseMessage bizTalkMessage)”.
这是因为对于在接受到的XML文件的Context域没有定义Operation ,Biztalk Adapter无法知道收到的消息需要调用Web Service的那个方法。
一个简单的方法是,修改SOAP Action Header 只含一个方法,此时可以不要BTSActionMapping,只要该方法的Action 部分,如: urn:deleteStore. 如果要调用多个方法,可以为每个方法创建一个WCF Adapter,每个Adapter的Action对应该方法的Action部分。 但此时可能又会碰到另一个问题:对于同一类Adapter,Biztalk 只允许一个URL,此次可以通过在URL后加?1 ?2 等来规避。
另外一种方法是通过创建一个Custom pipeline ,为XML消息添加Operation 值。
关键代码如下:
public IBaseMessage Execute(IPipelineContext pContext, IBaseMessage pInMsg) { Stream originalStream = pInMsg.BodyPart.GetOriginalDataStream(); string messageType = OperationPromotionHelper.ReadMessageType(originalStream); originalStream.Seek(0, SeekOrigin.Begin); if(messageType!=null) { try { pInMsg.Context.Promote("Operation", "http://schemas.microsoft.com/BizTalk/2003/system-properties", messageType); } catch (Exception ex) { } } return pInMsg; } ... public static string ReadMessageType(Stream messageStream) { if (messageStream == null) { throw new ArgumentNullException("messageStream"); } XmlReader xmlReader = new XmlTextReader(messageStream); xmlReader.Read(); if(xmlReader.IsStartElement()) { return xmlReader.LocalName; } return string.Empty; }
因为我们这个Web Service的BTSActionMapping 定义的Operation和XML的根元素同名,所以使用messageType 作为Operation (BTS.Operation)的值。
然后为Receive Pipeline使用这个自定义的Pipeline即可。
最后打开Tracking看看XML消息的Content部分:
可以看到消息成功Promot Operation ,并把它的值定义为message 的类型,对应于Soap Action head 中的 Operation.