In the latest
round of documentation that was released for BizTalk 2004 there is an “orchestration
operator” defined that was not previously documented: ‘succeeded()’
The documentation states that this operator can be used to determine the outcome of
a transactional scope or orchestration. When might this operator be needed?
Well, it turns out that the orchestration compiler has some interesting rules about
what you can do in an exception handler that might not be entirely intuitive at first
(though as you reflect on analogies to C# or other exception-enabled languages, it
begins to make sense.)
Suppose that you have defined a Request/Response port as the means of interacting
with an orchestration, and you want to ensure that some response is generated regardless
of the failure conditions you encounter. Your first attempt might look like this (I
know mine did…) Stretch this JPG out to full size to see it clearly (IE
will shrink it.)
This will generate a compiler error:
error X2162: must receive before sending a fault message on an implemented port
What is going on here? It sure seems as if we have received a message already
– we did it in the Rcv_SomeDoc shape. However, we have the Snd_ResponseDoc shape
inside of Scope_WorkThatMightFault, and the orchestration compiler is assuming that
we might have already executed that shape prior to the catch block executing (i.e.
prior to an exception being raised.) A Request/Response port must only have
one response for any given request…and our Snd_FaultDoc shape has the potential
to violate this rule. It sure would be nice if X2162 could be more explanatory
in this regard…
How do we overcome this? It isn’t terribly obvious…We must wrap the Snd_ResponseDoc
shape in an (additional) transactional scope, and check in our catch block to ensure
that the associated transaction did not succeed before performing Snd_FaultDoc.
See this diagram (Acrobat required).
What we are doing here is structuring the flow such that exactly one response will
be sent for the original Rcv_SomeDoc shape. The way we do this is to use a Decide
shape, with an expression such as “!succeeded(Transaction_SndResponse)” in the rule
branch. The Snd_FaultDoc will be in the ‘true’ side of the branch (i.e. we did
not successfully perform Snd_ResponseDoc), while the ‘false’ side will likely be empty.
This is a pretty subtle bit of enforcement that the orchestration compiler is performing.
It is somewhat analogous to a typical language compiler ensuring that all code paths
have a return value for non-void functions or methods. And, of course, even
though it is not enforced, it is certainly the case that ‘catch’ and ‘finally’ blocks
in standard languages often have to be aware of what has or hasn’t taken place in
the associated ‘try’ block. The orchestration compiler (apparently) just has
some well-defined & strict rules it wants orchestrations to adhere to (such as
“exactly one response for each request emanating from a Request/Response port”.)
There is a somewhat similar case that is described briefly in the BizTalk documentation.
Imagine we wish to make reference to a message or variable in our ‘catch’ block that
was initialized within the associated scope. In this case, the orchestration
compiler will assume that we might not have gotten around to initializing that variable/message
prior to the exception being thrown – and a compiler error will be generated as a
result: error X2109: use of unassigned local variable ‘Variable_Blah’
In this case, we can wrap the portion of the scope’s work that is responsible for
initializing the variable/message of interest in an (additional) transactional scope
(i.e. “Scope_InitWork”), and we can use a Decide shape with an expression such as
“succeeded(Transaction_InitWork)” in the rule branch. This will allow the orchestration
Wow! One might start to agree with Charles’