Facebook Twitter LinkedIn E-mail
magnify
Home Posts tagged "Biztalk"

使用Biztalk Server预定义宏修改输出文件名

BizTalk Server预先定义了一些宏(Macro)可以用来定义文件输出时的文件格式,缺省使用%MessageID%.xml

20130304001

Biztalk Adapter (File 或 FTP) 在写文件时使用Message的ID(一般为GUID)替换%MessageID% 作为最终的文件名。

除%MessageID%之外,Biztalk还提供了如下的宏可以用来定义输出的文件名:

宏名 替换值
%datetime% UTC时间格式为 YYYY-MM-DDThhmmss (比如, 1997-07-12T103508).
%datetime_bts2000% UTC时间格式为YYYYMMDDhhmmsss, 其中 sss 为秒和微秒 (比如, 199707121035234 means 1997/07/12, 10:35:23 和 400 微秒).
%datetime.tz% 本地时间加时区格式为 YYYY-MM-DDThhmmssTZD, (比如, 1997-07-12T103508+800).
%DestinationParty% 目标Party的名称. 它的值来自属性BTS.DestinationParty.
%DestinationPartyID% 目标Party的ID (GUID). 其值来自BTS.DestinationPartyID.
%DestinationPartyQualifier% 目标Party的修饰符. 其值来自property BTS.DestinationPartyQualifier.
%MessageID% Message的GUID,其值来自 propertyBTS.MessageID.
%SourceFileName% 文件Adapter读取的源文件的文件名,包括扩展名,但不含路径名,比如 foo.xml  Adapter将源文件名存放到属性 FILE.ReceivedFileName 中, 如果无法设置该属性,该宏不会被替换 (比如, C:\Drop\%SourceFileName%).
%SourceParty% 源Party的名称
%SourcePartyID% 源PartyID (GUID). 其值来自 BTS.SourcePartyID.
%SourcePartyQualifier% 源Party的修饰符.
%time% UTC 时间 格式hhmmss.
%time.tz% 本地时间加时区,格式 hhmmssTZD (比如 124525+530).
 

灵活使用Script Functoid 增强BizTalk Mapping功能

我们知道Biztalk为 定义Schema之间的映射提供了多种多样的Functoid,可以符合大部分映射的需求,尽管如此还是有些情况Biztalk自带的Functoid 不能完成所需要的映射,一个方法是通过扩展Functoid来实现,另外一个可以通过Script Function通过C#代码帮助实现一些简单的转换功能,下面通过一个简单的例子来说明,我们知道 Iteration 可以把记录的序号映射到目标Schema中:

20130128001

上面的映射可以把InvoiceLine 的序号映射到目标Schema 的 InvoiceLine 的第7个字段(本例是使用的Flat File Schema,实际可以使用任意类型的Schema),映射之后 InvoiceLine 的 InvoiceLine_Child7 的值为 1,2,3,4

但如果目标Schema对该字段具有格式要求,比如长度必须为4,从0001-9999,不足四位的以0补足。此时我们就可以借助Script Functoid 来实现。在Iteration和目标元素之间添加一个scripts Functoid (如上图)。

双击Scripts 打开其属性窗口:

20130128002可以看到我们只使用了一个输入参数,为Iteration的输出。如果有多个输入,这里则显示多个输入。

然后选择Scripts Functoid Configuration 来编写脚本

20130128003

可以使用不同的脚本语言来编写脚本,这里我们使用C#来编写脚本,函数名称一般为MyConcat ,输入的参数个数由前面所说的输入参数个数决定,本例我们只需一个参数,因此可以使用C#编写如下脚本:

public string MyConcat(string param1)
{
	return param1.PadLeft(4,'0');
}

最后生成的文本文件(Flat File) 的序号格式为0001-9999.
20130128004

 

Biztalk使用WCF Adapter调用Web Service

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.