When designing a BizTalk solution that involves WCF (which is most of the times), you need to carefully consider the exception handling mechanism. This requires understanding for both BizTalk Exception handling as well as WCF (and SOAF) faults.
This post explains the mechanisms to implement exception handling when you have a BizTalk process that both calls WCF services and when the process itself is exposed as a WCF service.
The process will show the following scenarios:
- The process calls into a WCF service when the service is down
- The process calls the same WCF service – this time when it’s up – but when the called operation throws a traditional SOAP fault
- The process calls a WCF service where the operation throws a typed fault exception
Note: Delivery notifications do not work with request-response and thus WCF ports
Before we start the scenarios, note that BizTalk delivery notifications (i.e. Microsoft.XLANGs.BaseTypes.DeliveryFailureException) do not work with request-response ports. They only work with one-way ports (where a negative acknowledgments triggers the DeliveryFailureException). And since WCF send adapters do not support one-way WCF operations (you’ll have to use void operations), then WCF ports must be request-response and thus they do not support delivery failure notifications.
So what does this mean? When handling WCF exceptions inside the Orchestration you’ll have to catch a generic exception to take into account scenarios when the message cannot be delivered to its destination. You cannot rely on the specific DeliveryFailureException. I will show you this in a moment.
Pre-requisite: Prepare the fault message to return to the Orchestration consumer
Before you start designing your exception handling blocks, you need to decide what you want to return to the Orchestration consumer.
Remember the scenario: the orchestration is calling into multiple WCF services and each call might result in a different exception type which you will see in the upcoming scenarios. So one call might generate a generic exception, another one might generate a SOAP fault exception, while another might generate a typed WCF fault contract. Regardless however, you need to decide on a single message to return to the orchestration consumer to indicate the presence of a fault.
So what I did was creating this schema which I will return to the orchestration consumer no matter what the exact exception was:
Now there is one important thing to notice: see the detail record which includes the <any> attribute and element. These mimic the structure of the SOAP 1.1 fault message schema (BTS.soap_envelope_1__1.Fault). The reason I did this is to make it easy to map the soap fault message (scenario 3 below) to the return message to the client. In real projects you might want to do proper XSLT mapping to extract the results that you want.
Side note: to make it easy for the same of this post, I am using the basichttp WCF adapters which means SOAP 1.1 is used. If you are using any of the ws adapters then SOAP 1.2 will be used in which case you’ll have to use the BTS.soap_envelope_1__2.Fault schema.
Now in each of the following cases, I will populate this custom schema with the exception details and then return it to the client.
Scenario 1: Orchestration calls into WCF service when it’s down
Let’s first examine the orchestration design for that portion of the process:
1: here I create the request message. For the sake of this process, I simply use a map to transform the input message to the request message (i.e. the request message to be sent to WCF)
2: here I use a dummy map to initialize the response message coming from WCF. Reason? When you receive a message inside a scope (which you need for exception handling), it gets initialized inside that scope. So if you try to use it outside the scope the compiler will complain because it has no way to guarantee that the message is actually constructed. So the not very beautiful solution (more like ugly actually), is to initialize the response using a dummy (empty) map before the scope shape, this way you will ‘fool’ the compiler. Of course you should NEVER do that unless you are CERTAIN that anytime the message is used outside the scope is when either the message is actually received inside the scope so it’s the message you expect, or you know you are using your dummy message. In short – design your process with the dummy message in mind.
3: here is where I send the message to the WCF service and expect the response
4: the first catch block explicitly catches SOAP fault exceptions which are thrown from inside the WCF service. I will talk about this in the next scenario.
5: this catch block catches generic exceptions which includes the service being down. Lets talk about this part in more detail. Here is the expanded block:
1: the exception I catch is of type System.Exception. This means that any exception that is not of type SOAP fault exception (which will be handled in the previous catch block), will be handled by this block
2: again I use a dummy map to initialize the custom schema I want to return to the client
3: having the message inialized, I then use an assignment shape to copy the message details into the distinguished fields of the message:
4: now I send the custom message back to the orchestration consumer. For this to happen, you will need to add a new fault message operation to your receive port and set the message type to that of the custom schema you intend to always send to the orchestration consumer:
5: finally, I terminate the orchestration. Obviously I do that only for testing purposes. In your real scenarios what you will do after handling the exception is up to the business requirements.
Scenario 2: Orchestration calls into WCF service which returns SOAP fault
Having seen the CatchGeneralException block to handle exceptions when the service is down, lets now see the see the CatchSOAPException block which handles SOAP (non-typed) exceptions thrown from the WCF operation. Here is the block:
1: the exception type to be handled is “Port_2.GetData.Fault_1”:
What is Port_2.GetData.Fault_1? This is the type of the fault operation message added to the send port sending the message to WCF:
As you can see, this is again the SOAP 1.1 fault message because I am using basichttpbinding and because in the WCF operation I throw a generic SOAP fault and non a typed one.
Inside the WCF operation, I throw a generic soap fault exception as follows:
2: next I construct a message of the same fault message type:
3: I then use this message as an input to a map which creates the output custom fault message I want to send to the client:
See the mass copy? As I said, this is the reason I selected the output schema (MyCustomFault.xsd) to mirror that of the SOAP exception so that I can do this simple mapping using the mass copy functoid.
4: I again send the custom fault message to the client using the same fault operation:
5: and finally I terminate the process.
Scenario 3: Orchestration calls into WCF service which returns a typed fault
Now lets see a similar scenario, only this time, the WCF operation will return a typed fault contract instead of the generic SOAP fault:
1: the exception I catch here is of type “Port_6.GetDataWithFaultContract.FaultDataFault”. again what is “Port_6.GetDataWithFaultContract.FaultDataFault”? “FaultDataFault” (I know a horrible name!) is the name of the typed fault contract exposed by the “GetDataWithFaultContract” operation:
And here is how the logical port is set up. Note that this time I do not have to right click the port and add a fault message (as I did when I was catching a generic SOAP fault). This time around because the fault is typed, its exposed as a schema which is imported by BizTalk when I generated the metadata from the wizard, therefore the fault operation is now part of the port type definition:
And here is the typed fault contract thrown from the WCF operation:
2: next I use an assignment shape to get initialize the exception message from the catch block:
3: and then I map the fault schema to that of my generic return schema to be sent to the client:
4: I then send the fault message back to the client:
See the advantage of having a common schema type to send to customers? No matter what the exception caught inside the orchestration is, you can always map it to that common return schema.
5: finally I terminate the process
Extracting fault message or operation response from the WCF adapter
One configuration you need to do is to tell WCF adapter how to extract the proper data when consuming the operation with the typed fault contract. What does this mean?
When you call a WCF operation with a typed fault contract, the following message will be returned in case there is an exception:
But what happens when you call the operation and no exception is thrown? You will get the expected SOAP response. Something such as:
Ok so this WCF. Now what happens when these reponses must be consumed by BizTalk over the same port? Why same port? Because remember you are sending a message from the orchestration to the WCF operation and you are expecting either the response of the typed fault over the same port; two different operations, but same port. So you need to tell the adapter how to extract the part of the required part of the message which will be dropped into the message box without causing a subscription failure.
To do so, you will supply something similar to the following expression into the WCF port:
Where the expression “/*[local-name()=’Fault’]/*[local-name()=’detail’]/* | /*[local-name()=’GetDataWithFaultContractResponse’]” tell the adapter to either extract the content of the fault or the regular response if no exception was thrown.
In case you have not noticed, this is the reason I used two ports inside my orchestration although both are using the same wcf port type:
Because for Port_6 which I am using to communicate with the WCF operation that returns typed fault, I wanted to supply the above expression.