BizTalk ESB Toolkit Dynamic Routing from within Orchestration

biztalkesb-toolkit-2.0

I'm trying to perform dynamic itinerary routing from within an orchestration by invoking a receive pipeline, much like the provided ItinerarySelectReceiveXml reveive port, to resolve the itinerary for a given message and send it to a direct bound port for ESB routing. The setup is similar to the ComposedMessageProcessor BizTalk sample.

My receive pipeline is exactly like ItinerarySelectReceiveXml, as far as I can see, except on the ESB Itinerary Select pipeline component (in the ResolveParty stage) I've hardcoded the connection string and ItineraryFactName (e.g. BRI:\policy=MyResolveItineraryRule;useMsg=true;recognizeMessageFormat=true; and Resolver.Itinerary) so that I don't have to do tricks with loopback adapters and incur extra messagebox visits.

The code to invoke the receive pipeline from an expression shape is like this:

// The first message I want to route is just a node on my incoming message

strXPath = "/*[local-name()='BeginConversationMessage' and namespace-uri()='http://MyCompany.BeginConversationMessage.v001']/*[local-name()='BeginConversationMessage' and namespace-uri()='http://MyCompany.BeginConversationMessage.v001']";
BeginConversationMessage = xpath(InboundMsg, strXPath);
RcvPipeOutput = Microsoft.XLANGs.Pipeline.XLANGPipelineManager.ExecuteReceivePipeline(typeof(MyCompany.Itinerary_GenericSelector), BeginConversationMessage);

This goes fairly well, I can see that the correct Itinerary for the message type is being resolved using SQL Profiler, and I know the itinerary is good because I use it for this message type with a generic itinerary on-ramp.

But I'm getting an exception from the Microsoft.Practices.ESB.PipelineComponents.Dispatcher which I have right after the Microsoft.Practices.ESB.Itinerary.PipelineComponents.ItinerarySelector (in the resolve party stage)

The docs state that the ESB Itinerary Selector Pipeline Component should set the Microsoft BizTalk Server segment of the itinerary using the following properties: correlationToken, reqRespTransmitPipelineID, interchangeId, receiveInstanceId, epmRRCorrelationToken.

The exception looks like this:

Value cannot be null.
Parameter name: interchangeId

Source: Microsoft.Practices.ESB.PipelineComponents.Dispatcher

Method: Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(Microsoft.BizTalk.Component.Interop.IPipelineContext, Microsoft.BizTalk.Message.Interop.IBaseMessage)

Error Source: Microsoft.Practices.ESB.Itinerary.OM.V1

Error TargetSite: System.Object[] GetItineraryDataForBAM(Microsoft.Practices.ESB.Itinerary.OM.V1.Itinerary, Microsoft.Practices.ESB.Itinerary.IItineraryStep, System.String)

Error StackTrace: at Microsoft.Practices.ESB.Itinerary.OM.V1.BAMItineraryProcess.GetItineraryDataForBAM(Itinerary itinerary, IItineraryStep step, String interchangeId)
at Microsoft.Practices.ESB.Itinerary.OM.V1.BAMItineraryProcess.SubmitToBAM(Itinerary itinerary, IItineraryStep step, IPipelineContext context, IBaseMessage msg)
at Microsoft.Practices.ESB.Itinerary.OM.V1.ItineraryV1.<>c__DisplayClassa.b__8()
at Microsoft.Practices.ESB.Itinerary.OM.V1.ItineraryV1.AdvanceByOrder(ItineraryMessageDirection messageDirection, String serviceInstanceId, IItineraryStep step, Action submitToBam, Boolean advanceStep)
at Microsoft.Practices.ESB.Itinerary.OM.V1.ItineraryV1.Advance(IBaseMessage message, IPipelineContext context, IItineraryStep step, Boolean advanceStep)
at Microsoft.Practices.ESB.Itinerary.OM.V1.ItineraryV1.Advance(IBaseMessage message, IPipelineContext context, IItineraryStep step)
at Microsoft.Practices.ESB.PipelineComponents.Dispatcher.Execute(IPipelineContext context, IBaseMessage msg)

Any help would be appreciated.

p.s. I've also posted this question to the ESB Toolkit Form here http://social.msdn.microsoft.com/Forums/en/biztalkesb/thread/28c5befe-4c7f-4dc1-a5e7-8fe5b3ec1c75

Best Answer

First, I think the key is to preserve the context of the original message. When receiving a message from the pipeline, you need to use the following syntax in a construct shape, in order to restore the context:

PipelineMessage = null;

RcvPipeOutput = Microsoft.XLANGs.Pipeline.XLANGPipelineManager.ExecuteReceivePipeline(
    typeof(MyCompany.Itinerary_GenericSelector), BeginConversationMessage);

RcvPipeOutput.MoveNext();
RcvPipeOutput.GetCurrent(PipelineMessage);
PipelineMessage(*) = BeginConversationMessage(*)

In fact, the context of the message needs to be preserved at all times during intermediate message contruction in the orchestration. Also, it is important you promote the right context properties before leaving the orchestration.

This can be done by Initializing a correlation on the last send shape in the orchestration. Make sure the correlation includes the correct properties, including the ones mentioned in the error message.

Related Topic