Welcome back to the “Throwing typed WCF faults back to consumers in a BizTalk messaging only application” blog series. This is the 4th part in the series and specifically focuses on creating a service behavior that enlists a custom error handler that inspects out of the box exceptions thrown by BizTalk pipelines and replaces them with the custom exception that was created in the second part of this series. If you haven’t yet read the prior entries in this series then follow the below links before you continue reading this entry.
In order to intercept out of the box BizTalk pipeline exceptions and replace them with our custom typed fault we must create a class which implements the System.ServiceModel.Dispatcher.IErrorHandler interface as below.
In the above error handler class a ProvideFault method is created which has access to the out of the box generated exception. This exception is inspected and the reason, message, and faultCode variables have values set based on evaluation of the exception. For example if the exception message contains the string “Source: “”XML validator””” then we can derive that the exception is an XML validation fault so we can set the faultCode to XMLVAL, the reason to XML Schema Validation Failure, and we can set the message to a sanitized version of the original exception’s message, stripping out any unnecessary details.
We then use these variables to instantiate an instance of a System.ServiceModel.FaultException object of the type of our custom typed fault, passing in a new instance of our typed fault using the aforementioned variables to populate it’s elements into the constructor of the FaultException. We then instantiate a System.ServiceModel.Channels.MessageFault object with the help of our FaultException object, and then populate the fault message which is of type System.ServiceModel.Channels.Message, and was passed into the method by reference, with the MessageFault object.
When we populate the Message object we must also specify a SOAP Action, however as you might have noted in the third part of this series when you generate proxy code from the WSDL the action against the FaultContract is the same as that of the request message rather than * which allows for any action. This means that hardcoding a SOAP action is going to cause problems for the client so we really need to populate it with the action value from the original request that was received by the service, but I have not quite found a way to do this in a service behavior. For now we will just populate the action with a hard coded value and I will show you how to fix this up in an endpoint behavior in the fifth part of this blog series.
Next up we must create a service behavior that will enlist our custom error handler class as below.
Finally we need to create a behavior extension element class that binds our service behavior, which is very simple since our service behavior doesn’t expose any parameters, as below.
You will now need to build your service behavior project, register it in the GAC, and register it in your machine.config files. As stated in part three of this blog series, my colleague Shadab has written a blog post on using WIX installers to install custom behaviors which includes registering them in the required machine.config so that is worth a read if you want more details on this.
You can now add this service behavior to your BizTalk WCF-Custom or WCF-CustomIsolated receive location. On the behaviors section of the adapter configuration you should now be able to right click on ServiceBehavior, choose add extension and select the behavior name that you bound your extension element class to in the machine.config. If you don’t see it in the list then either your code has some problems in it, you haven’t registered the assembly in the GAC correctly, you haven’t registered the behavior in your machine.config files correctly, or you haven’t restarted the BizTalk Administration Console after doing the aforementioned tasks.
The result of this is that the behavior will now intercept your out of the box exceptions and will replace them with your custom exceptions. A BizTalk consumer of the service is now able to receive fault response messages and you can route them to the appropriate error handler (though you will need to use XSLT in your maps if you want to access any of the values in the Detail node of the message, as according to the Fault schema, Detail is an xs:any node). An example fault message looks like the below.
However this is not the end of the story since .NET clients are frustratingly still not able to catch the typed fault due to the incorrect SOAP action being set against the fault. This can be illustrated quite easily in the below screenshot in which the above exception is returned to a .NET client however because of the incorrect SOAP action the typed exception handler is bypassed and a more generic System.ServiceModel.FaultException exception is caught. If you inspect the exception you will see that all the element values that were contained in the XML representation of the typed fault in the above screenshot have been lost as the .NET serializer did not know how to deserialize the XML and thus threw those element away. This problem will be addressed in the fifth part of this blog series.
If you are interested in reading further then do follow the links to further entries in this blog series.