深入biztalk中各种端口绑定方式(六) 直接绑定之Self Correlating

1、 Self Correlating

自相关直接绑定是这样的一种绑定:一个Orchestraion实例可以调用另一个Orchestraion,并且把自身的一个接收端口作为参数传递到被调用的Orchestraion,同时可以传递其他的参数到被调用的Orchestraion。被调用Orchestraion在对接收到的参数进行相关的处理后,把消息再通过跟传送过来的接收端口参数同类型的端口(类型相同但是方向相反)发送回调用Orchestraion的这个接收端口。主Orchestraion的这个接收端口的绑定类型就是自相关直接绑定。自相关直接绑定就是在不使用相关集的情况下保证被调用的子Orchestraion处理完消息后能把消息准确的返回到调用它的那个Orchestraion实例,而不会被可能的其他同类正在运行中的Orchestraion实例所接收。

1.1.        测试场景

这里设计一个测试场景,十分简单,不具有实际意义,但是足以说明自相关的工作原理。

在输入文件夹中有这样一个xml消息:

<ns0:Item xmlns:ns0="http://SelfCorrelating.InputSch">

  <name>name_0</name>

  <number>8</number>

  <price />

</ns0:Item>

orchestration接收到这个消息,消息中只有数量,没有价格。主orchestration把它发送到子orchestration,在子流程中计算价格,然后把计算好价格的消息返回到主orchestration。最后主orchestration把子orchestration返回的消息写入到输出目录。

整个项目就使用这一个消息架构。

本测试项目代码下载:/Files/chnking/SelfCorrelatingSamples.rar

1.2.        项目设计

首先,设计上面那个消息的架构。为了在orchestration中访问方便,number字段和price字段设置为可分辨字段。

orchestration设计:


Figure 18.  Self Correlating
直接绑定主orchestration

 

Port_Receive接收端口是specify later以后绑定类型接收端口,用来从指定输入文件夹接收输入消息。

Start Orchestration形状用来启动子Orchestration,启动子Orchestration同时需要传参数到子Orchestration

自相关的启动子Orchestration需要从子Orchestration返回消息,在主Orchestration中要指定一个接收端口跟子Orchestration相关,用来接收从子Orchestration返回的消息。这个接收端口就需是Self Correlating的直接绑定。

Orchestration传送到子Orchestration的参数中必须包括这个输入端口的参数,以便子Orchestration中能生成跟这个端口类型一致的端口类型但是方向相反(为发送)的端口,把消息返回到主Orchestration。一般还要包括需要发送到子Orchestration进行处理的消息作为参数,当然还可以添加任意需要的参数传送到子Orchestration。本例中除了传送端口参数外,只需要发送一个参数,就是接收到的消息作为参数。

Receive_2接收形状为非激活接收形状,它在Start Orchestration形状启动子Orchestration后等待子Orchestration的返回消息。

Port_CallBack设置为Self Correlating的直接绑定的接收端口。

Port_Send发送端口是specify later以后绑定类型发送端口,把子Orchestration返回的消息输出到指定输出文件夹。

Orchestration设计:

orchestration中首先在Orchestration View面板中新建两个Orchestration Parameters,如下图:


Figure 19.  
orchestration中新建Orchestration Parameters

 

ProcessedMsg参数为Message Parameter消息参数,消息类型为项目中的唯一消息架构。

CallBack_SendPort参数为Port Parameter消息参数,端口类型为主orchestration中的那个自相关接收端口的端口类型。新建了端口参数后,在子orchestrationPort Surface面板上会自动出现一个跟主orchestration中的自相关接收端口同类型的端口。

orchestration设计如下图:


Figure 20.  Self Correlating
直接绑定子orchestration

 

orchestration由主orchestration通过Start Orchestration形状启动激活一个新实例,同时接收主orchestration传送过来的两个参数:自相关端口和要处理的消息。

在构造形状中,把输入到消息赋给一个同类型的消息,并计算新消息的价格:

Message_Send = ProcessedMsg;

Message_Send.price = Message_Send.number * 10;

处理好的消息,通过CallBack_Send端口返回到主orchestration

再回过来看主orchestration如何设置参数的传送,在主orchestration中双击Start Orchestration形状:


Figure 21.  Start Orchestration
形状设置参数

 

Parameter Name这列显示在子Orchestration建立的参数名称,Variables In Scope这列设置在主Orchestration把哪个对象传送给相关的参数,只有同类型的对象会在下拉列表中显示供选择。

1.3.        Self Correlating机制分析

使用自相关主要由两个主要部分组成:

l         Start Orchestration形状启动子流程,并把自相关的端口和其他参数传给子流程

l         子流程做了对参数做了相关的处理后,通过传过来的端口参数返回到主流程。

下面详细的分析这两个部分的各自如何实现的。

1.3.1   主流程调用子流程

通过Start Orchestration形状启动子流程,并把自相关的端口和其他参数传给子流程。

这个启动流程的过程并不像一般的调用函数那样主流程直接调用子流程并传送参数,这个过程在biztalk中是必须要经过MessageBox,并由消息的订阅发布路由机制来控制完成。实际上Start Orchestration形状产生的效果就是被启动的字流程订阅Start Orchestration形状发送出去的消息,这个消息中包含了需要传送的参数的内容。因为消息引擎没有参数的概念,一切都是消息的传递。所以把所有需要传送到子流程的参数打包在消息里面发送到子流程,而子流程收到消息后,能够把消息中的参数解出来还原成相关类型的参数。

l         子流程订阅Start Orchestration发出的消息:

查看子流程的订阅信息:


Figure 22.  
子流程订阅Start Orchestration的订阅主体

 

General标签中:

这里订阅的服务是SelfCorrelating.ChildOrchestration, SelfCorrelating, Version=1.0.0.0, Culture=neutral, PublicKeyToken=380d269ec565a18c,表示是子流程是订阅者。

订阅类型是:Activation Subscription,表示启动一个新的子流程实例。


Figure 23.  
子流程订阅Start Orchestration的订阅条件

 

Expression标签中:

Subscription

{

    ORGroup0

    {

BTS.ActivationServiceID == SelfCorrelating.ChildOrchestration, SelfCorrelating, Version=1.0.0.0, Culture=neutral, PublicKeyToken=380d269ec565a18c   

}

}

只有一个条件,消息中BTS.ActivationServiceID属性指向这个子流程。

l         主流程Start Orchestration生成消息过程

Start Orchestration形状的任务实际上就是形成一个包含了所有指定参数的消息,把这个消息发布出去。同时产生一个实例订阅,自相关接收端口订阅子流程返回的消息。

首先,新建一个消息。

给此消息的添加一个升级属性MessageType,这个属性指示这条消息的消息类型,设置为:Microsoft.BizTalk.XLANGs.BTXEngine.ExecMessage,这是用来传送参数的特殊的消息类型那个。

给此消息添加一个升级属性ActivationServiceID,这个属性指示要启动的子流程的完全名称,就是订阅条件中的:SelfCorrelating.ChildOrchestration, SelfCorrelating, Version=1.0.0.0, Culture=neutral, PublicKeyToken=380d269ec565a18c

ExecMessage消息没有正文,每个参数被作为消息中的一个部分,所以要把每个指定要传送到子流程的参数序列化打包成一个消息部分加入到消息中。

 

把参数打包成消息部分的过程:

使用IbaseMessageFactory建立一个消息部分IbaseMessagePart 

IbaseMessagePart  IbaseMessageFactory. CreateMessagePart ()

参数可能是各种类型的对象,端口类型、xml类型、定制的.net类型,一般的数据类型等等,只要是可以序列化的类型都可以作为参数。

参数对象通过BinaryFormatter或者XmlSerializer类的Serialize方法序列化为一个Stream

BinaryFormatter.Serialize(Stream serializationStream, object graph)

XmlSerializer. Serialize (Stream serializationStream, Object graph)

Stream对象赋给消息部分的Data属性,这个参数作为一个消息部分就准备好了,之后把这个消息部分附加到消息中:

IbaseMessage.AddPart(string partName, IBaseMessagePart part, bool bBody);

partName为部分的名称

part为前面步骤准备好的参数消息部分

bBody为表示这个部分是否是消息的正文部分

 

把自相关的端口类型作为一个参数打包为一个消息部分时,Start Orchestration形状对端口要做一些处理,给这个端口的Microsoft.XLANGs.BaseTypes.Address属性赋值,类似这样的值:

"msgbox:ac6c7980-1f5e-4901-bc92-31c9cb23325b#selfCorrelated#SelfCorrelating.PortType_CallBack, SelfCorrelating, Version=1.0.0.0, Culture=neutral, PublicKeyToken=380d269ec565a18c"

Msgbox:表示是直接绑定的端口

ac6c7980-1f5e-4901-bc92-31c9cb23325b:表示是表示主流程这个实例的唯一GUID,这个GUID不是服务实例ID,但是含义类似,一个服务实例有一个唯一的这样的GUID

selfCorrelated:表示是自相关的端口

SelfCorrelating.PortType_CallBack, SelfCorrelating, Version=1.0.0.0, Culture=neutral, PublicKeyToken=380d269ec565a18c:这个是自相关端口类型的完全名称。

 

消息中除了每个参数形成一个部分外,还需要一个特殊的部分,叫做MetaData部分,这部分用了指示每个参数的数据类型,告诉接收消息的服务,根据每个消息的类型进行反序列化已恢复原来的对象。

这个特殊的部分是个Microsoft.BizTalk.XLANGs.BTXEngine.ExecMessage.ParamDataArray类型的对象,是Microsoft.BizTalk.XLANGs.BTXEngine.ExecMessage.ParamDataArray,有几个参数就有几个ParamData类型的对象相对应,ParamData对象中主要的一个属性TypePropName,指示了相应的那个部分的对象类型。

 

本例中有两个参数,加上一个特殊部分,Start Orchestration形状生成的消息就是一个Microsoft.BizTalk.XLANGs.BTXEngine.ExecMessage类型的,没有正文,带有三个部分的消息。

 

1.3.2   子流程返回主流程

子流程根据订阅接收到主流程Start Orchestration形状发布的消息后,根据MetaData部分的支持,分别的把参数部分的参数反序列化为相应的参数对象。

在子流程中做消息处理后,通过端口参数形成的跟主流程自相关端口同类型(方向相反)的发送端口,把消息发布到MessageBox,主流程也是通过订阅接收到子流程返回的消息。

看一下主流程自相关端口形成的订阅,这个订阅是由主流程Start Orchestration形状发布的消息的同时产生的一个实例订阅,看一下订阅情况。


Figure 24.  
子流程返回消息的订阅主体

 

General标签:

订阅的服务是SelfCorrelating.MainOrchestration, SelfCorrelating, Version=1.0.0.0, Culture=neutral, PublicKeyToken=380d269ec565a18c,就是主流程的完全名称。看订阅表中的uidPortID字段,这个字段表示订阅消息的是orchestration中的哪个端口,对照BizTalkMgmtDbbts_orchestration_port表,这个订阅的uidPortID字段指向Port_CallBack端口。

订阅类型是:实例订阅

 


Figure 25.  
子流程返回消息的订阅条件

 

Expression标签:

Subscription

{

    ORGroup0

    {

BTS.Operation == Operation_1 

And

BTS.PartnerPort == selfCorrelated 

And

BTS.PartnerService == 33e96493-f8ff-4a7e-83aa-3179165383e5

And

BTS.MessageType == http://SelfCorrelating.InputSch#Item 

}

}

BTS.Operation:自相关端口用于传送消息的那个Operation

BTS.PartnerPort:从主流程端口参数的Microsoft.XLANGs.BaseTypes.Address属性值中两个#号之间的值。

BTS.PartnerService:从主流程端口参数的Microsoft.XLANGs.BaseTypes.Address属性值中带过来的表示主流程实例的唯一标识,消息只会返回到启动这个子流程的那个主流程。

BTS.MessageType表示返回到主流程的消息类型。

2.4.        运行时主流程和子流程关系

运行时,当主流程的Start Orchestration形状发布的消息后,子流程接收到消息并启动子流程的一个服务实例。主流程服务实例等待子流程消息的返回,正常时子流程很快处理好把消息返回到主流程,子流程完成结束。消息返回到主流程,主流程做后续处理后完成结束。

如果子流程执行时间比较长,消息在一定时间内没有返回到主流程,为了节约资源,biztalk会把主流程的服务实例序列化后保存到数据库(这个过程在biztalk中叫做dehydrate),待子流程的消息返回后再把主流程的服务实例从数据库中反序列化为服务实例对象(这个过程在biztalk中叫做rehydrate)接收消息,继续处理。

如果子流程中出现错误,没有在子流程中捕获并处理的话,异常将会被抛到biztalk引擎,作为未被捕获的异常处理,子流程将会被挂起。主流程跟子流程之间的关系只是消息的发布和订阅的关系,所以子流程的异常并挂起主流程并不知道,主流程将一直保持dehydrate状态。

原文地址:https://www.cnblogs.com/chnking/p/831494.html