Welcome back to the “Throwing typed WCF faults back to consumers in a BizTalk messaging only application” blog series. This is the 3rd part in the series and specifically focuses on how you can publish your typed fault contract in your BizTalk WCF service’s WSDL. If you haven’t yet read the prior entries in this series then follow the below links before you continue reading this entry.
This part has largely been figured out by Paolo Salvatori in this fantastic blog post which proves it’s relevance many years later. To a large degree I have used Paolo’s WsdlExportExtenions endpoint behavior code as is. The one major exception to this is that I had to modify his AddImportedSchemas method in the Microsoft.BizTalk.CAT.Samples.PublishTypedFaults.WsdlExportExtensions.WsdlExportEndpointBehavior class in the WsdlExportExtensions project. The reason for this is that it contains a foreach loop which iterates through each XmlSchemaImport object in schema.Includes, however you will find that this falls over if one of your schema in the WSDL makes an includes reference to another schema (i.e. they both belong to the same namespace) rather than just imports references which this behavior already works perfectly for. The fix for this appeared to be to iterate over each XmlSchemaExternal object in schema.Includes instead, XmlSchemaExternal being the base class from which XmlSchemaImport is derives from. The method now looks like the below.
Once this was done the next step was to build the WsdlExportExtensions project, register it in the GAC, and register it in both the 32-bit and 64-bit machine config files. 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.
Now the next step requires you to inspect your WSDL and plan out how you will associate your typed fault as a fault message on your given operations. In the below screenshot you see that I have focused on the portType section of the WSDL very specifically, and what you need to take note of is the portType name, the name of any contained operations (in this example there is only one operation but you might have many if your service contains multiple operations)
The next thing you will want to do is to prepare the XML configuration you will need to feed into the WsdlExtensions property of the service behavior which is used to inject elements into your WSDL. You can copy the example XML from Paolo’s blog post (search for “WsdlExtensions property” on the page).
There are a few important sections in this XML.
- The first important thing is to declare a namespace prefix. The choice of value isn’t really significant except you probably want to avoid clashes with default namespace prefixes so I suggest you be creative in your choice.
- Next up we need to declare the name (equivalent to the root node of your schema) and namespace of the schema which we have deployed to the BizTalk runtime that represents our custom exception in the XmlSchema node.
- Next we need to create a WSDL message that represents our custom exception message in the Message node. To do this we need to assign the message with a name which is rather arbitrary except that you will want to avoid clashes with other message names. You will want to specify the namespace of your schema, and then in the part node specify the root node name of your schema in the element node and give the part a name which is rather arbitrary, and I don’t believe you need to worry about clashes unless you are creating a multi-part message which we aren’t.
- Next up we need to associate our exception message with a given operation on a given port type. To do this we specify the name of the port type from the WSDL in the PortType/Name element, and the name of the operation from our WSDL in the PortType/Operations/Operation element. In the PortType/Operations/Faults/Fault node we then specify a name for our exception which is rather arbitrary from a runtime perspective but best to choose an appropriate name, and then specify the name of the message that we declared in our previous step.
Once the XML is prepared then we need to remove all line breaks from it so that it can be pasted into the WsdlExtensions property of the service behavior. I personally use the Remove Line Breaks Online Tool to help me do this.
In order to make use of the service behavior it is very important that our receive location uses either the WCF-CustomIsolated (if to be hosted by IIS or another isolated host) or WCF-Custom (if to be hosted by an in-process host) adapter, as adapters such as WCF-WSHttp or WCF-BasicHttp can not enlist the use of WCF behaviors (I’m not sure if you can manually adjust the web.config files for these adapters to bind behaviors to the service but I would suggest that this is avoided even if possible). On the behaviors section of the adapter configuration you should now be able to right click on EndpointBehavior, choose add extension and select the wsdlExport behavior. 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. Once you have selected the wsdlExport behavior you can paste in the flattened XML configuration into the WsdlExtensions property.
This endpoint behavior will adjust the WSDL in the below ways.
- The WSDL has now been flattened, which means that schemas are no longer contained in separate XSD files referenced from the WSDL, but rather are defined within the WSDL itself.
- The custom exception schema is now contained within the WSDL so will be generated in proxy code if you add a service reference within your client application to the service.
- There is now a message which contains a part of the custom exception type, and this message is associated with the operation we extended in the XML configuration for the endpoint behavior as a fault message.
If you generate a service reference off this new WSDL and you inspect the OperationContract generated you will notice that the operation is now decorated with a FaultContractAttribute which specifies a type of our custom exception. In theory now we can surround our calls to this specific operation with a try/catch block in which we catch an exception of type System.ServiceModel.FaultException<CustomException> where CustomException is the typed fault class generated as part of the service reference.
Also take note of the fact that the action specified against the FaultContract is the same as that on the request. This is not consistent with the response which has an action of * which implies that any action will be accepted. This has some further implications that we will explore further in the fourth part of this blog series.
If you are interested in reading further then do follow the links to further entries in this blog series.