Welcome back to the “Throwing typed WCF faults back to consumers in a BizTalk messaging only application” blog series. This is the 6th and final (hopefully) part in the series and aims to describe the improvements in the client experience as a result of applying the solution described throughout this blog series, and to conclude the series. If you haven’t yet read the prior entries in this series then follow the below links before you continue reading this entry.
To quickly summarize what has been covered in this series, in the second post we created a custom serializable class which is decorated with DataContract/DataMember attributes and represents our custom typed fault but doesn’t derive from System.Exception. We have also created the schema representation of the fault class and deployed it to the BizTalk runtime. In the third post we made use of a slight variation of the WsdlExtensions endpoint behavior to extend our WSDL such that it published the metadata for the typed fault and associated it as a fault message on operations described in the WSDL. In the fourth post we implemented a custom service behavior that enlists a custom error hander that intercepts the out of the box BizTalk pipeline exceptions and replaced them with the custom typed fault, populating the fault elements with sanitized fault details, and setting a hardcoded SOAP action on the response message (which would be a problem for programmatic clients if this was not overridden). In the fifth post we implemented a custom endpoint behavior which enlists a custom message inspector that copies over the soap action as well as a specific SOAP header from the request message to the response, thus fixing the issue with the wrong SOAP action being associated with fault messages as well as making life easier for BizTalk service consumers.
The remainder of this post will summarize the client experience for .NET and BizTalk consumers of a BizTalk hosted WCF service that makes use of these solutions.
.NET clients need simply add a service reference pointing to the WSDL associated with the service in question to generate all the proxy classes required to call on the service and consume exceptions. Calls to operations exposed by the service reference should be surrounded by try catch blocks, specifically catching an exception of type System.ServiceModel.FaultException<CustomException> where custom exception is the typed fault class generated by the service reference. Once within the catch block, you can access the elements contained within the typed fault by inspecting the Details property of the exception object. We have managed to make life much easier for .NET consumers of our service and as far as they are concerned they shouldn’t even be aware that they are connecting to a BizTalk hosted service.
BizTalk clients have a relatively similar experience as well with a few additional challenges to overcome. Running the “Add generated items/Consume WCF Service” wizard against the WSDL results in schemas being created for all the operations contained within the service as well as the typed fault schema. What is also interesting is that the orchestration file that gets generated also correctly creates a port type representing operations contained within the service with the correct typed fault as well.
The client now has the option of copying over the identifier value to an outbound header which ensures that it is also included in the response message. One way in which I would look at populating the outbound header would be to promote the element within my message body that relates to the identifier to a context property and then use the BRE Pipeline Framework on the send port’s send pipeline to copy that context property value to the WCF.OutboundCustomHeaders context property. This can be achieved by using string concatenate, get context property and set context property vocabulary definitions provided for in the BRE Pipeline Framework to set the value of the WCF.OutboundCustomHeaders context property in the following format – <headers><s:CustomHeaderName xmlns:s=”urn:customheaderns”>ContextPropertyValue</s:CustomHeaderName> </headers>. This results in the header being copied onto the response message and being converted into a context property with a name and namespace matching those of the header in the request message as below. This context property could be accessed in a pipeline or an orchestration, or in combination with the context accessor functoid it could even be accessed in a map.
There is another challenge encountered in my scenario as the service is hosted by a one-way receive location thus returns a blank or void response. In order to consume the typed fault returned by the service, the BizTalk send port used to consume the service would need to be created as a Solicit-Response send port rather than a One-way send port, the propagate fault message option in the message tab needs to be enabled, routing for failed error should be disabled to ensure that transport exceptions result in retries and suspension of the messaging instance rather than the messaging instance being terminated and routed to the error handler (I recommend that NACKs are used to escalate these transmission failures to the appropriate exception hander, see this blog series of mine for more details on NACKs), and the receive pipeline on the send port should be set to one that makes use of an XML Disassembler pipeline component so as to resolve the message type on the response message so that it can be run through maps or routed based on message type.
The challenge is that while the XML Disassembler pipeline component can correctly resolve the SOAP fault message, it can’t really resolve the message type on successful responses since the body of the message is empty. I would recommend looking at the BizTalk 2006 Create Body Part pipeline component for inspiration on creating a body part when the body part is empty, or to otherwise look at doing the same through a custom WCF behavior, most likely through the use of a message inspector.
The fault message received by BizTalk looks like the below and the typed fault elements and the custom header values can be accessed and manipulated as desired.
A lot of the solutions I have discussed could be made more dynamic and I welcome suggestions and feedback. For example the custom error handler could be made to use an external config store such as the BRE or the SSO for mappings of out of the box exceptions to custom exceptions rather than hardcoding them into the error handler, or the message inspector could also similarly be made to use an external config store to lookup which headers get copied from the request to response. The solution could also be extended further to cater for multiple typed faults, etc… I’m sure there are many ways to implement the solution I have described, possibly in an easier fashion (not that I know of though), and I would be very keen to hear your thoughts.
I hope that you have taken something away from this blog series, and at the very least the content discussed makes you ask a few more questions about how you are going to deal with exceptions the next time you approach a BizTalk project that relies on WCF.