A natural follow up to my BizTalk 2010: Calling Dynamics CRM 4.0 Web Services post is one that deals with the Exceptions, or Faults, that these Web Services may return. When using the CRM 4.0 Adapter, the adapter would take care of handling SOAP exceptions and bundling them up into a CRM Response message that had a Return Code and Error Nodes. Whether your operation was successful or not, you could always expect the same type of response message from CRM.
<ns0:Response xmlns:ns0="http://schemas.microsoft.com/crm/BizTalkAdapter/Response">
<Header>
<ReturnCode>1</ReturnCode>
<ErrorCode />
<ErrorString />
<Retryable />
</Header>
Now that we are not using this adapter anymore we need to be able to catch our own exceptions coming out of CRM. If we don’t perform these actions below(or similar actions) we can expect an error message like the following.
Inner exception: Received unexpected message type 'http://schemas.xmlsoap.org/soap/envelope/#Fault' does not match expected type 'http://schemas.microsoft.com/crm/2007/WebServices#CreateResponse'.
The issue is we have a Solicit Response Send Port in which we are sending a typed Request message into CRM and are expecting a typed Response message in return. When we encounter a SOAP Fault, a typed message is being returned, it just isn’t what we are expecting. In order to avoid these situations, we need to perform the following actions within our BizTalk solution.
Note: these actions are not specific to CRM, but may be used in other Web Service scenarios.
- Create a multi-part message that includes a part that is of type BTS.soap_envelope_1__1.Fault. You will find this schema in the Microsoft.BizTalk.GlobalPropertySchemas assembly.
- Right mouse click on your selected operation and select “New Fault Message”
- Select the Message Type to be the value of our Multi-part message that we just created.
- Add a scope around your send/receive shapes. The transaction type can be “None” and the Exception Object Type should be set to the Fault that we just created within our Operation.
- So while technically this is defined as a message, within our current scope exception handler it is actually an object. So if we wanted to dump the contents of this message to the Event Viewer we could perform the following actions by assigning the message to an XML Document and then getting the OuterXml so that we can send this text into the event viewer.
- At this point we can stop if we are so inclined. If we wanted to actually use this information in our CRM Response message we can assign this “exception” object into an instance of a message that is of the same type (our multi-part message).
- We then can use a Message Assignment shape to assign this object into an instance of our message.
- Now that we have a typed message, we can use this message in a map to instantiate an instance of our CRM Response. To keep things simple I am just going to concatenate the faultcode, faultstring and faultactor values and assign to the CreateResult node. If we wanted to get the actual details out, we will need to write a .Net helper method or use XSLT to extract this content out since we have an untyped “Any” node.
- After all of these changes, our Orchestration should look like this:
- We can now deploy our application and test it. In order to generate a SOAP Fault, I am going to send in the same message as in my previous post, but this time I am going to make the First Name to be greater than 50 characters.
- Now when we process this message, we will not get an unhandled exception or suspended message. Instead, we will see an informational message in our event viewer that contains the details that we are interested in.
- Also, we will send this error information to a folder in the form of a CreateResponse message that will include some SOAP Fault details.
<ns0:CreateResponse xmlns:ns1="http://schemas.microsoft.com/crm/2007/CoreTypes" xmlns:ns2="http://microsoft.com/wsdl/types/" xmlns:ns3="http://schemas.microsoft.com/crm/2006/Query" xmlns:ns0="http://schemas.microsoft.com/crm/2007/WebServices" xmlns:ns4="http://schemas.microsoft.com/crm/2006/Scheduling" xmlns:ns5="http://schemas.microsoft.com/crm/2006/WebServices" xmlns:ns6="http://schemas.microsoft.com/crm/2006/CoreTypes">
<ns0:CreateResult>soap:Server - Server was unable to process request. -</ns0:CreateResult>
</ns0:CreateResponse>
Note: some other blog posts mention using an XPATH statement, within our WCF Send Port, for both types of messages that we are expecting; typed CRM response and SOAP Fault. In my scenario, this step was not required since I am expecting a typed SOAP Fault exception object within my Scope – Exception handler.