We all hate to use Atomic Scopes in BizTalk orchestrations when not needed.  I have a static C# Trace routine that normally takes passing an enum of System.Diagnostics.TraceLevel (for Error, Warning, Info, etc…).   In the current project, our web services can return “soft errors” in a common field called “Result”.

So I could have used a Decide shape, but since the code repeats on many webservices, I wanted to us an if/else statement in an expression shape called “GetResults” (in picture below).

if (msgResponse.RESULT == "Ok")
  {
     vTraceLevel = System.Diagnostics.TraceLevel.Info;
  }
else   
  {
     vTraceLevel = System.Diagnostics.TraceLevel.Error;
  }
if (msgResponse.RESULT != "Ok")
{
  strSoapFaultMessage = "2510:msgResponse:" + msgResponse.Message;
  throw new System.ApplicationException(strSoapFaultMessage); 
}

The reason I coded like this is that I had a large orchestration with about 8 web service calls, and I wanted a common error handler for all of them. That Catches a System.ApplicationException, writes to EventLog, and sends an email with the full Request and Response XML of the call/response to/from the web service.

Now all this happens to be in a debatching loop. When I ran it, and had multiple errors, the first one had a blank response in the email, and the second and third ones worked. It seems very inconsistent, but here’s what a colleague and I figured out.

In the picture below, my original shapes are on the left, and the revision is on the right. Scope_C_NonSerializable_TraceLevel was an Atomic Transaction to support the fact that TraceLevel was non-serializeable. So if the orchestration blows up in this Scope, it would have to restart at the beginning of the scope.

My mistake was to include the “Throw” in that scope. Apparently the “Throw” sometimes acts as sort of a Rollback, and clears some or all variables set in that Scope.

In the shape called “TRC 2510”, I had the following, along with a call to my C# trace routine.

xmlDocResp = msgAsurionOrderRoutingResponse; 

So when the Throw happens, at least on the first time through the loop, the xmlDocResp had no value. Simply moving the “Throw” and “Trc 2511” outside the loop seemed to solve the issue.

Orchestration_Scope_Throw_Issue

The Catch you see above is the Captch of the BTS.soap_envelope_1__1.Fault.  It also sets xmlDocResp to the value of the SoapFault, and throws an ApplicationExcpetion so that same error handler can work for both Soap Faults and the “soft” web service errors.

The common error handling had the following in a message assignment shape:

tempStrBuilder.AppendLine("===========================");
tempStrBuilder.AppendLine("Request Message:");
tempStrBuilder.AppendLine(System.Convert.ToString(xmlDocReq.OuterXml));
tempStrBuilder.AppendLine("===========================");
tempStrBuilder.AppendLine("Response Message:");
tempStrBuilder.AppendLine(System.Convert.ToString(xmlDocResp.OuterXml));
tempStrBuilder.AppendLine("===========================");

I’m considering adding a C# formatter to do a “pretty print” on the XML (done) to make the error email look even nicer, probably based on the code on this Stackoverflow page.

Filed under: Orchestrations