This blog post contains some guidelines for consuming web services, with a focus on exception handling. We will both handle pure messaging scenario and web service calls from within an orchestration. I also make a distinguishment between asynchronous and synchronous flows. Synchronous means that the flow needs to return a message to the original caller. So in case of troubles, a SoapFault needs to be returned to the calling application. In an asynchronous flow, you just need to make sure that your web service call is resumable.
Messaging Scenario – Asynchronous
When an error occurs during the web service call, the default behavior of BizTalk retry 3 times and will suspend the request message on the BizTalk Send Port and this instance will be resumable. This is the perfect behavior for this asynchronous process.
Messaging Scenario - Synchronous
If you are in a synchronous process, a suspended Send Port will lead to a timeout on your Receive Port. In this scenario you need to enable "Propagate Fault Message" on the Send Port and a SoapFault will be returned to the original caller. Also think about the Retry Count and Retry Interval settings, because a bad configuration can also lead to timeouts.
Orchestration - Asynchronous
When you consume a web service from within an orchestration, it's getting more complex. If the consumed web service throws an exception, BizTalk creates by default 2 suspended service instances. Resuming them does not always have the expected behavior.
- The Orchestration is suspended. A resume will not change anything to the state of the Orchestration.
- The Send Port is suspended. A resume will resume the web service call as expected, but the Orchestration will not be able to continue processing afterwards.
How can we now achieve a resumable web service call?
First of all enable "Propagate Fault Message" on the Send Port.
Also modify the calling orchestration:
- You need to create a loop. This loop continues as long as the Boolean bSuccess equals false.
- Modify the logical Orchestration Send Port and add a Fault Message. To keep it general, you can choose the SoapFault (which is part of the Microsoft.BizTalk.GlobalPropertySchemas).
- Add an exception handler to the web service call. Catch the Fault Message that was returned. Add a suspend shape for human intervention. Note that it’s a good practice to also add an extra exception handler which catches a System.Exception.
- If the web service call fails: set bSuccess == false in the exception handler. If the call succeeds, set bSuccess == true, so the orchestration will exit the loop.
The result should look like this:
Now we've created a resumable web service call from within an orchestration. When testing the orchestration in a failure scenario, you will see that there are still two suspended service instances:
- The Orchestration is suspended. This is the one that we've made resumable.
- The Send Port is suspended. To avoid this second service instance to be suspended, you can enable "Routing for Failed Messages". This will generate an ErrorReport, instead of suspending the Send Port. Subscribe on the ErrorReport with the filter ErrorReport.ErrorType == “FailedMessage”.
Orchestration - Synchronous
In this scenario, you will also need to catch the SoapFault (or other exception) and make sure that you don’t end up with suspended send port instances. See “Orchestration – Asynchronous”
The extra functionality that you’ll need to add is returning a SoapFault to the original caller.
- Add a Fault Message to the Request/Response receive port of your orchestration.
- You can choose to return a typed Fault or, to keep it general, a SoapFault (which is part of the Microsoft.BizTalk.GlobalPropertySchemas).
- Make sure you return the catched SoapFault (or the created SoapFault in case of other exception) in case of errors.
- Remark that you’ll need to add a decide shape to determine you’re in a success/failure scenario. Otherwise, the compiler will fail (complaining about unconstructed messages).
Again, think about the Retry Count and Retry Interval settings on the send port.