Troubleshooting Orchestrations

Debugging orchestrations can be a complex undertaking. Orchestrations are often complex with many moving parts and external dependencies. To make matters worse, business logic is often located throughout an orchestration with business processes distributed across multiple orchestrations, potentially on many servers.

This section explores different ways to troubleshoot your orchestrations and provides detailed advice for solving many common errors.

Orchestration start and end, message send and receive, and shape start and end activities are tracked by default. You may configure additional tracking options using the BizTalk Server Administration console.

Cc825581.note(en-US,BTS.10).gifNote
If you disable any of the orchestration activity tracking options, Health and Activity Tracking (HAT) will be unable to replay orchestration instances for that orchestration.

  1. Click Start, point to Programs, point to Microsoft BizTalk Server 2006, and then click BizTalk Server Administration.

  2. In the console tree, expand BizTalk Server 2006 Administration, expand the BizTalk group, expand Applications, and then expand the application containing the orchestration for which you want to configure tracking.

  3. Click Orchestrations, right-click the orchestration for which you want to configure tracking, and then click Properties.

  4. Click the Tracking tab, select the tracking options you want, as described in the following table, and then click OK.

    Option Description

    Track Events - Orchestration start and end

    Select this check box to track the orchestration instance before and after processing of the entire business process. Orchestration tracking enables you to see the instances in the reporting views of Health and Activity Tracking.

    Track Events - Message send and receive

    Select this check box to track message send and receive events. This check box is available only if you select the Orchestration start and end check box.

    Track Events - Shape start and end

    Select this check box when you need to debug orchestration instances in the Orchestration Debugger. When this check box is selected, the event list in the Orchestration Debugger is populated. This check box is available only if you select the Orchestration start and end check box.

    Track Message Bodies - Messages before orchestration processing

    Select this check box to save and track the actual message content before processing by the orchestration instance. This check box is available only if you select the Message send and receive check box.

    Track Message Bodies - Messages after orchestration processing

    Select this check box to save and track the actual message content after processing by the orchestration instance. This check box is available only if you select the Message send and receive check box.

    Track Message Properties - Incoming messages

    Select this check box to track message receive events. You must select this option to track incoming message bodies.

    Track Message Properties - Outgoing messages

    Select this check box to track message send events. You must select this option to track outgoing message bodies.

When you replay an orchestration, you are given the opportunity to watch the activity of an orchestration on a shape-by-shape basis. By replaying an orchestration in HAT you can pinpoint where a problem may have originated. For example, by looking at a message flow through a decision shape you can determine if the decision logic is working properly. You can also easily determine where a message was suspended due to an exception or error.

  1. To start the HAT tool, click Start, point to Programs, point to Microsoft BizTalk Server 2006, and then click Health and Activity Tracking.

  2. On the HAT tool menu, click Queries, and then choose Most recent 100 service instances or one of the other query choices as appropriate to your situation.

  3. In the search results, right-click an orchestration service instance and then click Orchestration Debugger. This brings up the Orchestration Debugger as shown below:

    Orchestration debugger showing a replay.
  4. Individual actions are listed on each row. Click a row to see the corresponding shape. The shape will be green for start actions and blue for completion actions.

  5. Clicking the final initialization action will highlight the path a message took through the orchestration. This can be useful when an orchestration has one or more decision shapes.

  6. To switch to the Message Flow views, click Debug | Switch to Message Flow. On the Message Flow screen, click the Orchestration Debugger link at the top of the flow to return to the Orchestration Debugger view.

When viewing an orchestration in the Orchestration Debugger, you will see its state at the last commit point. If you want to see the actual state of the orchestration, you must attach to it by first suspending the instance and then resuming debug mode. You can then attach to the instance and see its current state.

To perform interactive debugging of an orchestration in HAT, you must deploy and execute at least one instance of the orchestration you want to debug. To do so, you will have to perform the following steps:

  1. Deploy and execute the orchestration you want to debug at least once. This will generate an instance of the orchestration that you can attach to in HAT. Without this step, HAT will not know about your orchestration and will not have a way to display it.
  2. View the orchestration in the Orchestration Debugger by executing one of the canned queries or by running a custom query. This exposes the orchestration so that you can set class-level breakpoints.
  3. Set a class-level breakpoint on the orchestration shapes you are interested in debugging. Future instances of the orchestration will break at the shapes specified.
  4. Generate one or more new orchestration instances by submitting appropriate messages. You should use messages that exercise the appropriate shapes in the orchestration. For example, if you have a decision shape, make sure your sample message will trigger the branch you are interested in.
  5. Attach to the orchestration instance by using Debug | Attach.
  6. Review variable names and values including message part contents.
  7. Resume the orchestration. If no more breakpoints are encountered, the debugger will detach from the instance.
  8. Remove class-level breakpoints.

The following sections discuss these and other important aspects of interactive orchestration debugging using the Orchestration Debugger in HAT. For a checklist of important configuration and security considerations, see Checklist: Health and Activity Tracking.

Setting a Class-Level Breakpoint

At least one class-level breakpoint must be set on your orchestration before you can use HAT for interactive debugging of specific instances.

  1. Click Start, point to Programs, point to Microsoft BizTalk Server 2006, and then click Health and Activity Tracking.

  2. On the HAT tool menu, click Queries, and then choose Most recent 100 service instances or one of the other query choices as appropriate to your situation.

  3. In the search results, right-click an orchestration service instance and then click Orchestration Debugger.

  4. In Orchestration Debugger, right-click one of the shapes and then click Set Breakpoint on Class or press F9. A red circle appears in the upper-left corner of the shape when a breakpoint is set as shown in the following screenshot:

    Orchestration with a break point set
    Cc825581.note(en-US,BTS.10).gifNote
    Breakpoints are not supported for some orchestration shapes. You will be unable to toggle breakpoints on such shapes.

  5. The breakpoint will be active for all subsequent messages. Messages can only be resumed through human interaction using the Orchestration Debugger.

    Cc825581.Caution(en-US,BTS.10).gifWarning
    Class-level breakpoints should be used with caution in production environments, especially in high-volume environments.

Removing a Class-Level Breakpoint

You can remove class-level breakpoints individually or in their entirety by using the Orchestration Debugger.

  1. Click Start, point to Programs, point to Microsoft BizTalk Server 2006, and then click Health and Activity Tracking.

  2. On the HAT tool menu, click Queries, and then choose Most recent 100 service instances or one of the other query choices as appropriate to your situation.

  3. In the search results, right-click an orchestration service instance and then click Orchestration Debugger.

  4. In the Orchestration Debugger, right-click one of the shapes and then click Set Breakpoint on Class or press F9.

    -- OR --

    To remove all class-level breakpoints, click Debug on the HAT tool menu and then click Clear All Breakpoints on Class or press CTRL+SHIFT+F9.

If you are attached to an orchestration instance, removing class-level breakpoints will affect current orchestration instances that have not yet reached the removed class-level breakpoint and all new orchestration instances.

Setting an Instance-Level Breakpoint

Instance-level breakpoints are distinguished from class-level breakpoints by scope. Where class-level breakpoints affect all instances of an orchestration, instance-level breakpoints affect only a particular instance. For example, a class-level breakpoint on a Receive shape causes all message instances that encounter that shape to halt; setting an instance-level breakpoint on a subsequent Send shape when attached to a specific instance of the orchestration will halt that instance when the Send shape is reached.

  1. Set a class-level breakpoint.

  2. Attach to an orchestration instance by using the Orchestration Debugger.

  3. In the Orchestration Debugger, right-click one of the shapes and then click Set Breakpoint on Instance or press F9.

    When you continue the orchestration, execution will stop when the breakpoint is reached for that instance only. No other instances will be affected.

If you have multiple breakpoints in your orchestration, remember to refresh the display as each new breakpoint is reached after execution is resumed. To refresh the display, click File on the Orchestration Debugger menu and then click Refresh to update the Tracked Events and Orchestration panes.

Cc825581.note(en-US,BTS.10).gifNote
The Orchestration Debugger does not automatically refresh the display. You should refresh the display as each new breakpoint is reached or when you think another process may have changed the state of the orchestration instance you are working with.

Removing an Instance-Level Breakpoint

Instance-level breakpoints can be removed from within the Orchestration Debugger.

  1. Attach to an orchestration instance by using the Orchestration Debugger.

  2. In the Orchestration Debugger, right-click one of the shapes and then click Remove Breakpoint on Instance or press F9.

    When the orchestration is continued, execution will stop when any other active instance-level or class-level breakpoints are reached.

Attaching to an Orchestration Instance by Using Orchestration Debugger

To debug an orchestration instance, you must use the HAT tool to find the orchestration instance you are interested in debugging, view the instance using the Orchestration Debugger, and then manually attach to the instance.

  1. Click Start, point to Programs, point to Microsoft BizTalk Server 2006, and then click Health and Activity Tracking.

  2. On the HAT tool menu, click Queries, and then choose Most recent 100 service instances or one of the other query choices as appropriate to your situation.

  3. In the results pane, click the ServiceInstance/State header drop-down list and then deselect Completed and Terminated to show only started orchestrations.

  4. Right-click an orchestration service instance from the search results and then click Orchestration Debugger.

  5. From the Orchestration Debugger, click Debug and choose Attach.

Once attached, you can view orchestration variables, save messages, set instance-level breakpoints, and perform other debugging tasks.

Detaching from an Orchestration Instance

The Orchestration Debugger can be automatically or manually detached from an orchestration instance. It is automatically detached under the following conditions:

  • When you resume an orchestration from a breakpoint and no other breakpoints are encountered
  • When the orchestration state changes to Suspended, Terminated, or Completed

An orchestration instance can be terminated through the Orchestration Debugger by clicking Debug and choosing Terminate. An instance can also be terminated by any user with sufficient rights using the BizTalk Server Administration console, even when you are actively attached to it. When working in a team environment, you should alert other team members of your debugging activity.

It is often useful to detach from an orchestration instance manually. For example, if a team of developers is working on a particular orchestration instance, one developer will need to detach the Orchestration Debugger from an instance before another developer can attach to the same instance.

To explicitly detach from an orchestration instance from within the Orchestration Debugger, click Debug on the menu and choose Detach. You will not be able to reattach to an orchestration instance if it does not encounter any other breakpoints.

Working with the Orchestration Debugger

The following screenshot shows a typical debugging session in the Orchestration Debugger.

Orchestration Debugger with break point hit.

The Orchestration Debugger consists of three panes that are always present and two optional panes that appear when attached to an orchestration instance:

  • The Service pane displays the instance service name and GUID that uniquely identifies the orchestration instance, debug mode, orchestration state, whether the Orchestration Debugger is attached, and service options.
  • The Tracked Events pane lists the status of every action performed in the orchestration, such as whether it started or completed. As you select each of the rows in this pane, the corresponding shape in the Orchestration pane appears highlighted in green when the shape starts and blue when the shape finishes.
  • The Orchestration pane is where a visual representation of the orchestration is rendered with all of its shapes.
  • The Variable List pane appears when attached to an orchestration instance and displays the name, value, and type of the variable. The value indicates if the variable is null or, if not, then what kind of object it contains. Type is the Assembly.Namespace.Name of the object.
  • The Variable Properties pane appears when attached to an orchestration instance and displays properties for the variable that vary according to the type of object. For example, for messages this includes Message Parts (including Name, Properties, Size, Type, and Value) and Message Properties (including Context, Name, PartCount, Scope, Type, and Value).

You will likely focus on the Orchestration, Variable List, and Variable Properties panes when debugging orchestration instances. Using the Orchestration pane, you can determine how a message is flowing through an orchestration, while the Variable List and Variable Properties panes show current variables and their properties, values, and types. This is useful for debugging decision shape errors, determining what content is reaching a port, seeing the "before" and "after" messages in a transform operation, and other tasks.

Resuming an Orchestration Instance

To resume the execution of an orchestration in the Orchestration Debugger, click Debug on the menu and choose Continue. The instance will continue execution until either another breakpoint (either class-level or instance-level) is hit or the orchestration completes.

Cc825581.note(en-US,BTS.10).gifNote
Tracked events will not be refreshed until you click Refresh on the File menu.

Debugging a Called Orchestration

If the orchestration calls another orchestration, you can debug the called orchestration by right-clicking the call orchestration action in the Tracked Events pane and then clicking View Called Orchestration. In the orchestration below, the Call Orchestration shape is named CallOrchestration_1.

Viewing a called Orchestration in debug mode.

Right-clicking the corresponding Call event in the Tracked Event pane and then clicking View Called Orchestration causees the Orchestration Debugger to load the called orchestration. In the above orchestration, notice that the title bar displays the instance's GUID as well as #0. This number represents the orchestration being called; the original orchestration is always #0. When the called orchestration is brought up, it will be #1 and so on.

You can return to the calling orchestration by clicking Debug and choosing View Calling Orchestration in the Orchestration Debugger. This works recursively so if your original orchestration (#0) calls another orchestration (#1) that in turn calls another orchestration (#2), you would need to choose Debug | View Calling Orchestration twice.

Debugging an Orchestration Instance That is Suspended (Resumable)

Orchestration instances that are in the Suspended (Resumable) state can be debugged by the Orchestration Debugger by resuming the instance in debug mode.

  1. Click Start, point to Programs, point to Microsoft BizTalk Server 2006, and then click Health and Activity Tracking.

  2. On the HAT tool menu, click Queries, and then choose Most recent 100 service instances or one of the other query choices as appropriate to your situation.

  3. In the search results, right-click an orchestration service instance that is in the Suspended (Resumable) state and then click Orchestration Debugger.

  4. From the Orchestration Debugger, click Debug and choose Resume in Debug Mode.

    The Orchestration Debugger opens the orchestration instance in debug mode as if a breakpoint had been reached.

  5. Debug the orchestration.

Debugging Orchestrations on a Remote Computer

You can use the Health and Activity Tracking tool to debug a remote computer provided the following conditions are met:

  • The BizTalk Server Administration tools have been installed.
  • You are a member of the BizTalk Server Administrators group on the computer where the BizTalkMsgDb exists.
  • The SQL Server instance has been configured to allow inbound network connections.
Cc825581.Caution(en-US,BTS.10).gifWarning
Grant access only to individuals that require access. For more information about HAT and security, see Security Considerations for Health and Activity Tracking.

  1. Click Start, point to Programs, point to Microsoft BizTalk Server 2006, and then click Health and Activity Tracking.

  2. On the HAT tool menu, click Tools and choose Preferences. This will bring up the Preferences screen.

  3. Click Live Data, and then specify the Management SQL Server name and database name. In the example below, the HAT tool is configured to connect to the remote Management SQL Server BTS_MGMNT_SVR01 using the default management database named BizTalkMgmtDb.

    HAT Preferences screen
  4. Click OK.

Limitations of the Debugger

The Orchestration Debugger does not support the following scenarios:

  • Debugging inside of a Message Construction shape. You can set a breakpoint on the Message Construction shape.
  • Debugging inside of an atomic scope. You cannot set a breakpoint on shapes inside of an atomic scope or an orchestration that is defined as Atomic.
  • Setting a breakpoint on a Group shape. You can set a breakpoint on individual orchestration shapes inside of the Group shape.
  • Setting a breakpoint on a compensation block. You can set breakpoints on the actions inside of the compensation block.
  • Setting a breakpoint on a catch block. You can set breakpoints on the actions inside of the catch block.

You should also be aware of the following considerations when using the Orchestration Debugger:

  • If you track an orchestration modified without changing the version number, you must restart all the host instances to which the orchestration is enlisted. This ensures that any shape change in the newly deployed version displays correctly as you step through the Orchestration Debugger
  • When you attach to an instance in the Orchestration Debugger, any atomic scopes in the orchestration instance will cause gaps to appear in the tracked events list. This happens because events for the shapes inside atomic transactions do not get persisted until the scope commits and because the debugger reloads events onto the end of the list, so any gaps remain unfilled during the live session.
    Cc825581.note(en-US,BTS.10).gifNote
    You can eliminate gaps in the tracked events list by refreshing the view.

If you need to capture detailed information about program flow, variable contents, versions, and other diagnostics, you may want to use Debug and Trace statements as explained below.

One of the oldest tools in the developer's toolbox is the print statement. By printing key values at critical points in the code, developers are given a clearer picture of what processes are running and how data changes during program execution. The same functionality can be achieved in BizTalk Server orchestrations (and custom components) by using the .NET System.Diagnostics.Trace and System.Diagnostics.Debug class libraries.

The System.Diagnostics.Trace and the System.Diagnostics.Debug class libraries enable you to write trace and debug information to one or more listeners. A listener implements certain interfaces to capture and process trace and debug messages. You can write your own custom listener by using the freely available utility program DebugView from SysInternals, or by using a different utility program. If you use DebugView (available here), you can monitor debug output on your local system or on any computer on the network that you can reach via TCP/IP.

Cc825581.note(en-US,BTS.10).gifNote
You should not write sensitive or confidential data using the Trace or Debug class libraries. Doing so will enable anyone with access to the BizTalk server to potentially capture and examine sensitive or confidential data.

  1. Using Visual Studio 2005, open an existing orchestration. If you would rather work with an SDK sample, try the HelloWorld project in the <installation directory>\Orchestrations SDK directory.

  2. Create a new Expression shape below the activation shape in the orchestration. For example, in the HelloWorld orchestration the shape would be placed below the ReceivePO shape.

    Orchestration with expression shape
  3. In the properties pane, set the Name of the Expression shape to "Trace_Entering".

  4. Double-click the new activation shape and enter the following code in the expression editor:

    System.Diagnostics.Trace.WriteLine("Entering HelloOrchestration");
    
  5. Deploy the application. If you are using the HelloWorld project and have not deployed it, run Setup.bat in the HelloWorld directory; otherwise choose Build | Deploy on the Visual Studio 2005 menu.

    Cc825581.note(en-US,BTS.10).gifNote
    Remember to restart the host when redeploying your BizTalk application.

  6. Start DebugView.

  7. Activate your orchestration. If you are using the HelloWorld sample, copy the file SamplePOInput.xml into the In directory. DebugView will capture the orchestration trace statement as well as diagnostic output from internal BizTalk Server components.

    DebugView capturing dbug information
  8. To save the captured events, click Save on the File menu, and then choose an appropriate directory and file name.

Writing the Assembly Version

Knowing which version of an assembly is currently deployed and running is often enough to pinpoint an issue. The following code retrieves information about the current assembly (containing the orchestration) and uses it in a trace statement. The information can also be written to the event log or used as part of other debugging code.

The first step is to add the appropriate orchestration variable declarations:

  • executingAssembly of type System.Reflection.Assembly
  • assemblyName of type System.Reflection.AssemblyName
  • assemblyVersion of type string

After these variables have been declared, add the following code to an Expression shape in your orchestration:

executingAssembly = System.Reflection.Assembly.GetExecutingAssembly();
assemblyName = executingAssembly.GetName();
assemblyVersion = executingAssembly.Version.ToString();
System.Diagnosics.Trace.WriteLine("Assembly " + assemblyName + " version: " + assemblyVersion); 

The assembly version will be sent to active trace and debug listeners for capture and study.

Writing Message Content

Trace and debug messages are also useful for writing out the contents of messages and orchestration variables. This is useful for inspecting intermediate messages produced by multiple transforms and for determining the values of other transient values.

The first step is to add the appropriate variable declarations to the orchestration:

  • stringMessage of type string
  • xmlMessage of type System.Xml.XmlDocument
  • myMessage is the orchestration message whose contents are to be output

After these variables have been declared, add the following code to an Expression shape in your orchestration:

xmlMessage = myMessage;
stringMessage = xmlMessage.OuterXml;
System.Diagnostics.Trace.WriteLine(stringMessage);

When the orchestration is compiled and deployed, the XML contents of myMessage will be sent to active trace and debug listeners for capture and study.

You may want to monitor the progress of the different business processes within your BizTalk application by writing information to the default Application log or to a custom event log. Writing to the event log can be useful in the following scenarios:

  • You want to access application messages in a standard way using tools supplied by Windows.
  • You want to archive information with other messages from the server environment for a more complete history.
  • You want the ability to monitor your application using tools that interact with the event log.

Writing to the Application Log

You can write to the Application log or any other log from your code by using System.Diagnostics.EventLog as shown:

EventLog appLog = new EventLog(); 
appLog.Source = "This Application's Name";
appLog.WriteEntry("An entry to the Application event log.");

If you are using a custom log, you should use the SourceExists method to ensure it exists before you write to it.

Writing to a Custom Log

Writing to a custom log is similar to writing to the Application log with the exception that you must first create the custom log. The code to create a custom log is straightforward:

// Create the source, if it does not already exist. if(!EventLog.SourceExists("MySource")) 
{ 
  //An event log source should not be created and immediately used.
  //There is a latency time to enable the source, it should be created
  //prior to executing the application that uses the source.
  EventLog.CreateEventSource("MySource", "MyNewLog");
}

However, you should not assume that your code will be run under an account that has the security privileges to create a new event log. Creating an event log takes administrator privileges and should be done in a separate utility program or, ideally, as part of an .msi installation. For more information about using custom script with an exported .msi installation, see Using Pre- and Post-processing Scripts to Customize Application Deployment.

This section contains a set of questions and answers designed to help you resolve issues with your orchestrations and to prevent errors from being introduced.

How can I share global variables across all instances of an orchestration?

There is no easy way to share global variables across all instances of an orchestration. If the global variables are static values, you might consider storing them in a persistent storage, such as a configuration file or SQL database, and allowing each instance to get the values from storage. You can also share a static state in user code as long as locks are placed correctly on access and modification of the shared state.

For more information about locks and synchronization, see Thread Synchronization.

Why is my orchestration instance suspended with the status "Complete with Discarded Message"?

An orchestration ends with a status of Complete with Discarded Message when a new message is dispatched to the orchestration instance at the exact time a time-out from a Delay shape or scope time-out property occurs. Orchestrations in this state are also known as zombies.

Zombie can result when your solution uses any of the following:

  • Terminate control messages. This scenario uses a protocol that allows for a control message to be sent that cancels all currently running work in a specific orchestration instance. Human workflow-related designs tend to rely on this mechanism and typically want to terminate.
  • Parallel listen receives. In this scenario the protocol waits for 1 of n messages before performing work on the collected messages and terminating. If a message is correlated, it is possible to terminate as a message is being received for a different branch of the parallel listen.
  • Sequential convoys with non-deterministic endpoints. This scenario relies on a master schedule to handle all messages of a certain type in order to meet one or more protocol requirements. Typical examples include ordered delivery, resource dispensing, and batching. These are characterized by a while loop surrounding a listen with one branch having a Receive shape and the other having a Delay shape followed by a mechanism that sets a flag indicating when the loop should stop. This is non-deterministic and susceptible to creating zombies because a message could be delivered while the delay is triggered.

A recommended solution is to use WMI to listen for suspend events, and then find the message associated with the orchestration instance and resubmit it. To accomplish this, we can modify the script supplied in the topic Removing Zombie Orchestration Instances to save and terminate message instances that were not consumed by an instance. The resulting script is shown below with changes noted.

' This script needs to be run under a user account that is a member of the BizTalk Administrators
' group. This script needs to be run on a machine that is configured with BizTalk administration
' tools.
'
' Impersonate the user account running the script to connect to BizTalk WMI objects.
'
Set objWMIServices = GetObject("WinMgmts:{impersonationLevel=impersonate, (security)}\\.\root\MicrosoftBizTalkServer")

' Create the event sink object that receives the service instance suspended events.
'
Set sinkSuspInst = WScript.CreateObject("WbemScripting.SWbemSink","SINK_INST_")
objWMIServices.ExecNotificationQueryAsync sinkSuspInst, "select * from MSBTS_ServiceInstanceSuspendedEvent"

' Wait for the events to fire.
'
while(true)
  WScript.Echo "Waiting for suspended service event..."
  WScript.Sleep(1000)
wend

' Event handler subroutine for suspendend service event.
'
Sub SINK_INST_OnObjectReady(objObject, objAsyncContext)
  On Error Resume Next
  Dim unconsumedMessageInstanceSet, objWMIServices, serviceInstanceSet

  ' Impersonate the user account running the script to connect to BizTalk WMI objects.
  '
  Set objWMIServices = GetObject("WinMgmts:{impersonationLevel=impersonate, (security)}\\.\root\MicrosoftBizTalkServer")
  If Err <> 0 Then
    PrintWMIErrorThenExit Err.Description, Err.Number
  End If

  WScript.Echo ("")
  WScript.Echo ("Entering the event handler for suspendend service instances.")
  WScript.Echo ("Service instance id: " & objObject.InstanceID)
  Wscript.Echo ("Service status: " & objObject.ServiceStatus)

  ' Check if the service completed with unconsumed messages, status code 4.
  ' If not exit the event handler subroutine.
  '
  if objObject.ServiceStatus <> 4 then
    WScript.Echo ("The service instance was not in the Compelted with un-consumed messages state.")
    WScript.Echo ("Service instance not terminated.")
    Exit Sub
  end if

  ' Search for message instances that were not consumed by the service instance.
  '
  WScript.Echo("Searching for message instances not consumed by the service instance.")
  Query = "Select * from MSBTS_MessageInstance where ReferenceType = 8 and ServiceInstanceID =""" &  objObject.InstanceID &  """"
  WScript.Echo (Query)

  Set unconsumedMessageInstanceSet = objWMIServices.ExecQuery(Query)
  If Err <> 0Then
    WScript.Echo ("Query failed.")
    PrintWMIErrorThenExit Err.Description, Err.Number
    Exit Sub
  End If

  ' Exit the event handler subroutine if there were no unconsumed messages.
  '
  if (unconsumedMessageInstanceSet.Count = 0) then
    WScript.Echo ("No unconsumed messages.")
    WScript.Echo ("Service instance not terminated.")
    Exit Sub
  end if

  ' (*) Removed message instance count; the loop below removes only
  ' specific message types so we don't care if there are multiples

  ' Loop over the set of unconsumed messages.
  ' The set should contain exactly one message instance at this point.
  '
  For each messageInstance in unconsumedMessageInstanceSet
    '
    ' If the message type is not http://YourSchema#YourRoot, move on to the next one. You should change messagetype to your type.
    '
    ' (*) Modified to check for a specific message type and only process if
    ' a match is made.
    If (messageInstance.MessageType = "http://YourSchema#YourRoot") then

      ' Search for the service instance that needs to be terminated.
      '
      WScript.Echo ("Querying for the service instance to be terminated.")
      Query = "Select * from MSBTS_ServiceInstance where InstanceID = """ &  objObject.InstanceID& """"
      WScript.Echo (Query)

      Set serviceInstanceSet = objWMIServices.ExecQuery(Query)

      If Err <> 0 Then
        PrintWMIErrorThenExit Err.Description, Err.Number
        Exit Sub
      End If

      ' Loop over the service instances found.
      ' Save each instance to file
      ' Call Terminate method on the service instance.
      '
      For each serviceInstance in serviceInstanceSet
        serviceInstance.InvokeMethod "SaveToFile", "c:\"
        If Err <> 0 Then
          PrintWMIErrorThenExit Err.Description, Err.Number
        Else
          WScript.Echo "Service instance saved successfully."
          WScript.Echo ("Terminating instance "+ serviceInstance.InstanceID)
          serviceInstance.Terminate()
          If Err <> 0 Then
            PrintWMIErrorThenExit Err.Description, Err.Number
          else
            WScript.Echo "Service instance terminated successfully."
          End If
        End If
      Next
    End If
  Next
End Sub

'
' Subroutine for displaying WMI errors.
'
Sub PrintWMIErrorThenExit(strErrDesc, ErrNum)
  On Error Resume Next
  DimobjWMIError

  Set objWMIError = CreateObject("WbemScripting.SwbemLastError")
  If (TypeName(objWMIError) = "Empty") Then
    wscript.echo strErrDesc & " (HRESULT: "& Hex(ErrNum) & ")."
  Else
    wscript.echo objWMIError.Description & "(HRESULT: " & Hex(ErrNum) & ")."
    Set objWMIError= nothing
  End If
End Sub

Should I be concerned with messages that are "Delivered Not Consumed"?

A message is in the Delivered Not Consumed state when it is in the BizTalk Server internal work queue. It might be in this state because the engine is busy with other messages, the message destination is processing more slowly than expected, or because the message destination does not exist or is unavailable.

To troubleshoot, you first need to determine if the message is destined for an orchestration or a send port by using HAT to look at which services the "Delivered Not Consumed" messages are associated with. You then must verify that the service is performing correctly.

Troubleshooting is a two-step process:

  1. Determine where the messages are headed. To do this in HAT, run a query to bring up a list of Delivered Not Consumed messages, and then check which services they are associated with (typically another orchestration or a send port).
  2. Troubleshoot the destination service. For example, if the destination service is a port, and the port uses the MSMQ adapter, is the specified server and queue name correct? Is the target queue available? Is the queue experiencing performance degradation?

For more general information about troubleshooting adapters, see Using Adapters. For programmer-specific help, see specific adapter help in this document.

Why does the compiler require my variable to be serializable?

Variables must be serializable because they will be serialized and deserialized if the orchestration dehydrates and rehydrates. Dehydration/rehydration can occur at any point the XLANGs runtime deems it necessary except when running inside an atomic scope. Because of this, serializable objects can be used in any orchestration expression whereas non-serializable objects can only be used inside an atomic scope.

Non-serializable objects are not detected at compile time; they are detected by the runtime on first execution. When a non-serializable object is detected, an exception is thrown and is caught by the runtime and written to the Application log.

Cc825581.note(en-US,BTS.10).gifNote
Error details will be in one or more inner exceptions. You will have to scroll the Event Properties description pane to view them all.

The following application log error entry contains the inner exceptions PersistenceException and PersistenceItemException (both resulting from using a non-serializable object in a non-atomic scope); you can see part of the PersistenceException.

Event Properties showing persistence exception

To avoid this error in a production environment, be sure to test all orchestrations and review the Application log for errors and other issues.

Why must interface-based programming be done inside atomic scope?

Interfaces cannot be marked serializable. The implementation of the interfaces may or may not be serializable, so XLANGs treats them as non-serializable even if the implementation is serializable. Because non-serializable objects must run in atomic scope, all interface-based programming is limited to atomic scope. This precludes the use of code like the following:

[Serializable()]
public class SurveyFollowUp : IDisposable
{ … }

To use this class outside of non-atomic scope, you must remove the IDisposable interface along with explicitly implemented methods.

How does an orchestration invoke a COM/COM+ component?

All orchestrations are compiled to C# from XLANGs and will behave as they do in other C# programs and components except in the case of atomic transactions. When a variable is referenced in the atomic scope but declared in an outer scope, the variable will be cloned to support rollback. This should be transparent.

Why doesn't my atomic transaction retry?

An atomic transaction will retry in either of the following circumstances:

  • When a RetryTransactionException is deliberately thrown by user code.
  • When a PersistenceException is raised when the atomic transaction attempts to commit.
Cc825581.note(en-US,BTS.10).gifNote
Any other exception raised in an atomic scope will not cause it to retry even if you have the Retry property set to True. If you are not sure why the atomic scope is not retrying, double-check both the exception type and any custom code to ensure a retry-friendly exception was thrown.

A PersistenceException could happen if, for example, your atomic transaction was part of a distributed DTC transaction and some other participant in that transaction aborted the transaction. Likewise if there were database connectivity problems at the time when the transaction was trying to commit, a PersistenceException would be raised.

There can be several root causes for PersistenceException, depending on the situation, but what you generally observe is that all the XLANGs actions in your atomic scope seem to go through correctly, but then instead of committing, the scope fails. If that happens for an atomic scope that has Retry=True, then the atomic scope will retry up to 21 times. The delay between each retry is two seconds by default (but you can modify that value). After 21 retries, if the transaction is still unable to commit, the whole orchestration instance gets suspended. Then you can manually resume it and it will start over, with a fresh counter, from the beginning of the offending atomic scope.

Cc825581.note(en-US,BTS.10).gifNote
The atomic scope will retry up to 21 times. You cannot override this value from your code. For example, you cannot configure the atomic scope to retry only three times.

If you are using RetryTransactionException you can override the two-second default delay between consecutive retries by setting a different value for the DelayFor property. For more information, see RetryTransactionException.DelayFor Property.

Cc825581.note(en-US,BTS.10).gifNote
All variables will be reset when RetryTransactionException is thrown in an atomic scope.

Do orchestrations support parallel activation?

It is only supported when used as a parallel convoy. Two conditions must be met for this to work:

  1. If one of the tasks of a parallel activation has an activatable Receive as the first shape, all of the tasks of that parallel activation must have an activatable Receive as the first shape, and all of those Receive shapes must initialize at least one correlation.
  2. If a particular correlation is initialized on more than one task of a parallel activation by a Receive shape, each of the concerned activating Receive shapes must initialize exactly the same correlation.

The following orchestration is an example of a parallel convoy. For a complete example using this parallel convoy, see the Parallel Convoy sample in the BizTalk Server Code Samples collection.

Orchestration Designer with parallel orchestration

This is the only parallel activation that XLANGs supports.

Why do I get intermittent subscription errors when sending to a child orchestration that was just started by the parent?

The subscription error "could not find subscription" is a result of a race condition. A race condition occurs when the outcome of a process depends on the particular order in which the process takes place. In this case, the condition occurs when the child orchestration has not been started in time to receive the message sent by the parent.

To avoid this problem, the child orchestration could send a message back to the parent when it has been started and is prepared to receive a message. In this way, the parent orchestration that started it would know that there is a receiver before sending a message.

How can I get context or other promoted properties from XLANGMessage?

Accessing promoted properties from an Expression shape is a straightforward process:

myID = myMessage(BTS.MessageID)

However, to access promoted properties from the XLANGMessage interface in your code you have to use XLANGMessage:

// msg is an XLANGMessage object
myID = msg.GetPropertyValue(typeof(BTS.MessageID));
msg.SetPropertyValue(typeof(MySchema.State)) = "TX";

Why do I get errors when I attach a dynamic send port to a logical port?

A dynamic port is not designed to inherit all of the attributes and characteristics of the port assigned to it. A dynamic port gets an address only; it does not inherit the other information associated with the logical port.

For example, if you attach a dynamic send port to a logical port with Delivery Notification = Transmitted, the runtime will not deliver a delivery notification. The XLANGs runtime only listens for a delivery notification if the port has actually been set up that way statically.

Cc825581.note(en-US,BTS.10).gifNote
In XLANGs, ports will behave only as they have been configured statically.

Why aren't updates made to message fields inside an Expression shape showing up on the message I send out?

Messages are immutable in BizTalk Server. If you want to modify a message, you must use a Construct shape to create a new message, copy the original message to the new message, and then update the fields on the new message.

In the following sample Construct shape code, a new message is created from an existing message and the Price field is updated:

// originalMsg and newMsg have been declared in the orchestration
ewMsg = originalMsg;
newMsg.Price = newMsg.Price + 1.00;

How can I retry a send when an exception occurs when calling a Web service with the SOAP sending adapter?

If you have a scenario in which an orchestration calls a Web service with the SOAP sending adapter and needs to retry if an exception occurs and suspends the orchestration as "Suspended (Not Resumable)", you can place the SOAP send inside a scope with an exception handler and let the exception handler catch the resulting SoapException. You can then retry the SOAP send by nesting the scope inside a while loop.

What parameters control dehydration?

Three parameters located in the BTSNTSvc.exe.config file control dehydration:

  • MaxThreshold is the maximum time that a dehydratable orchestration is retained in memory before being dehydrated.
  • MinThreshold is the minimum time that a dehydratable orchestration is retained in memory before it is considered for dehydration.
  • ConstantThreshold is used to attempt to ignore the throttling implication in deciding when to dehydrate. A value of -1 tells the engine not to use a constant threshold.
    Cc825581.note(en-US,BTS.10).gifNote
    Changing this value is not recommended.

For a complete discussion of the mechanics of dehydration including details about configuration parameters, see the section How Dehydration Works.

When does the persistence of an orchestration happen?

Persistence of an orchestration can occur under the following circumstances:

  • When the orchestration is waiting to receive a message and the wait is longer than a threshold determined by the engine.
  • When the orchestration is "listening" for a message, as it does when you use a Listen shape, and no branch is triggered before a threshold determined by the engine. The only exception to this is when the Listen contains an activation receive.
  • When a delay in the orchestration is longer than a threshold determined by the engine.
  • Between retries of an atomic transaction.

For a complete discussion of the mechanics of dehydration, see How Dehydration Works.

How can an orchestration be updated without bringing down the BizTalk Host?

It is possible to deploy an updated orchestration to your test or production environment without bringing down the host by updating the version number of the project containing the orchestration. After it is deployed, you can unenlist the original orchestration and then start the new orchestration. This can be useful when testing orchestrations that you are troubleshooting with inline debug code.

For more information about updating BizTalk applications, see Updating BizTalk Applications.

How can I load a message to construct an XLANGPart?

When constructing an XLANGMessage with a stream, the stream type must either implement IStreamFactory or be a MemoryStream. The following code sample shows how to construct an XLANGMessage:

public class FileStreamFactory : IStreamFactory
{
    string _fname;
    public FileStreamFactory(string fname)
    {
        _fname = fname;
    }
    public Stream CreateStream()
    {
        return new FileStream
        (
            _fname,
            FileMode.Open,
            FileAccess.Read,
            FileShare.Read
        );
    }
}
public static void AssignStreamFactoryToPart(XLANGMessage msg)
{
    IStreamFactory sf = new FileStreamFactory( @”c:\data.xml” );
    msg[0].LoadFrom(sf);
}

When is the Delivery Notification delivered?

A Send on a Delivery Notification (ACK/NACK) can appear at any point in the orchestration. The Receive for the ACK/NACK occurs at the end of the enclosing scope, unless the enclosing scope is atomic. If the scope is atomic, the Receive for the ACK/NACK occurs at the end of the atomic scope's enclosing scope (for example, you do not get the delivery failure exception until all shapes in the enclosing scope have executed).

When I try to run my application after deploying an orchestration with custom components, why do I get the error "File or Assembly name or one of its dependencies not found"?

This error usually means the BizTalk orchestration engine cannot locate the custom component. You must install all assemblies included in a BizTalk application in the global assembly cache of the computer that hosts the application.

A "WrongBodyPartException" occurs when handling a multipart MIME message in an orchestration

Problem

Receiving a multipart MIME message into an orchestration results in a WrongBodyPartException exception.

Cause

This error can occur if the order of the parts is specified incorrectly or messages do not conform to the part positions you have specified. For example, if you specify that the third part is a body part but messages arrive with a header part in the third position.

Resolution

Verify that the body part index setting is correct and then ensure that all messages arriving through the adapter are consistent with the setting. You can inspect the contents of MIME messages that fail inside an orchestration by stopping the orchestration (but keeping it enlisted); this will force the message to be published so you can examine it using the Administration console and verify the order of the parts.

Compiler asks if you are missing an assembly reference

Problem

When you compile your orchestration you get an error message that ends with the question "are you missing an assembly reference?" Two of the more common messages are:

  • The type or namespace name 'X' does not exist in the namespace 'Y' (are you missing an assembly reference?)
  • Identifier 'X' does not exist in 'Y'; are you missing an assembly reference?
Cause

Any of the following could be the cause of this error.

  • Your project does not reference one or more required assemblies.
  • Your project has a map or other object type that has the same name as the project.
  • Your project uses XML Schema definition language (XSD)-based Partner Interface Process (PIP) schemas and contains XSD schemas in a subfolder that is named System.
  • Your project is using a Global Property whose namespace is a subset of the current project's namespace. For example, using the Global Property namespace "File.ReceivedFileName" in an orchestration contained in the project "Accounts.FILE".
Resolution

Depending upon the cause of the problem, the resolution could be any of the following:

  • Add a reference to the missing assemblies your project requires.
  • Change the name of the map or other object to something other than the project name. This can typically be done through the object's property page (for example, the Map property page contains a Name property).
  • Change the namespace for the schemas in Visual Studio. To do this using Visual Studio, click Show All Files on the Project menu, and then expand the System node in Solution Explorer. Click each file in the System folder and in any subfolders, and then change the namespace entry in the Properties window so that any occurrence of System becomes _System. For example, change the MyProject.System.SubFolder namespace to the MyProject._System.Subfolder namespace. For more information about this issue, see KB article 916649.
  • Remove the conflicting Global Property namespace from the project.

Assignment to properties of type long fails on Windows 2000

Problem

A "bad variable type" error occurs when assigning a value to a promoted property that is a long type on Windows 2000.

Cause

There is a limitation in Windows 2000 that prevents BizTalk Server from allowing long properties to be promoted and manipulated.

Resolution

Deploy the solution onto a computer running Windows XP or Windows Server 2003. If you will be deploying to Windows 2000, change the property to another type.

An "AssemblyName context property was not valid" error occurs when submitting a document to a Web service via an orchestration

Problem

Submitting a document to a Web service via an orchestration results in an "AssemblyName context property not valid" error.

Cause

The BizTalk application was originally designed using a "messaging" approach without an intervening orchestration. This type of solution uses a send port filter to link the receive port and the send port so that the document is passed through to the send port upon receipt. Later, the solution was modified to include an orchestration that was bound to the send port.

Resolution

Remove the filter on the send port. If you apply a filter to a send port that is bound to an orchestration, messages will often bypass the orchestration and cause the context property error.

You receive a "Message has not been initialized in construct statement" error when building your project

Problem

When you compile your BizTalk application, you get the error "Message has not been initialized in construct statement".

Cause

When you construct a message, you specify all the message variables. Then you make assignments to the message or its parts. If part of a specific message assignment is included in a separate Construct Message shape, you may receive the initialization error message.

Resolution

To resolve this behavior, make sure that you include all parts of a specific message assignment in the same Construct Message shape. For a related support issue, see KB article 870606.

You can also resolve this behavior by creating your message in a Construct shape before using an instance of it in an Expression shape. For example, the following code will cause an error if placed in an Expression shape:

XMLDOM = new System.Xml.XmlDocument();
POAckMsg = XMLDOM;

To fix, create the instance of XMLDOM in a Construct shape, and then do the assignment in a downstream Expression shape.

You receive a "use of unconstructed message" error when building your project

Problem

When you compile your BizTalk project, you receive the error "use of unconstructed message '<message>'".

Cause

This error occurs when an unconstructed message is used in a Send shape.

Resolution

To resolve this issue, add a Construct Message shape to the orchestration. Include the Construct Message shape before the Send shape that is bound to the Web service.

For more information about this error and Web services, see KB article 92104.

Multipart MIME message part cannot be found

Problem

Attempts to retrieve a MIME message part with an index value greater than 0 results in the BizTalk Server runtime throwing an error similar to "can't find multi-part message with index = <value>".

Cause

The most common causes for this error are:

  • The MIME message has fewer parts than expected.
  • The MIME message could not be fully parsed.
Resolution

You can resolve this problem by ensuring that your code retrieves only message parts that are within the range expected from the message source. In the case of a parsing issue, you should verify that the original MIME message is structurally sound and properly constructed. If you expect occasional parsing problems, ensure that your orchestration has appropriate exception handlers.

Setting a transaction level for a scope results in an error

Problem

After configuring the transaction type for a scope or other entity supporting transactions in an orchestration, you receive the error "A Non-transactional Orchestration cannot contain any other Transactions".

Cause

This error occurs when you try to configure the transaction type of a scope (or other entity) in an orchestration to "Atomic" or "Long-Running" when the orchestration itself has a transaction type of "None".

Resolution

Ensure that the transaction type settings of your orchestration and constituent objects are compatible.

Project build results in the error "you must specify at least one already-initialized correlation set for a non-activation receive that is on a non-selfcorrelating port"

Problem

When you compile your BizTalk project, you receive the error "you must specify at least one already-initialized correlation set for a non-activation receive that is on a non-selfcorrelating port".

Cause

This error can occur if your orchestration has no activating Receive shapes (Activate = true) or has no activating Receive shapes and is not called directly by another orchestration.

Resolution

If your orchestration is not called by another orchestration, you must configure one of the Receive shapes to be an activated receive. For more information about configuring the Receive shape, including links to correlation, see How To Configure the Receive Shape.

You receive the error "Assembly generation failed -- Referenced assembly '<assembly>' does not have a strong name" when building your solution

Problem

You receive the error "Assembly generation failed -- Referenced assembly '<assembly>' does not have a strong name" when building your solution that has an orchestration.

Cause

This problem occurs when a type from an unsigned referenced assembly is used within an orchestration.

Resolution

Apply a strong name to the referenced assembly. If it is a custom assembly that you can recompile, use the strong name tool to create an .snk (key) file and then reference that key file in the assembly properties for the project. For more information about strong naming an assembly, see How To Configure a Strong Name Assembly Key File.

The error "Failed to add resource(s). Change requests failed for some resources" occurs when deploying an orchestration

Problem

When deploying an orchestration, an error similar to the following is displayed and deployment of the orchestration fails:

Failed to add resource(s). Change requests failed for some resources. BizTalkAssemblyResourceManager failed to complete end type change request. Object reference not set to an instance of an object.
Cause

This error can occur if the orchestration contains any objects that use C# keywords.

Resolution

Remove any C# keywords from the orchestration. For a list of C# keywords see C# Keywords.

You receive an "invalid property value" error when compiling your orchestration

Problem

You receive the error dialog "Invalid property value" when building your orchestration.

Cause

One or more of the objects in your solution has the same name as another object. For example, a message name is the same as a port name.

Resolution

Ensure that every object in your solution has a unique name. You can minimize the risk of this error by adhering to a naming convention.

Show: