This is the final part of a series of posts where I talk about various issues when creating SOAP-compatible BizTalk WCF services. In this post, I briefly cover the handing of SOAP headers in the case of boath the SOAP and the WCF adapters.
In the last two posts, I covered the steps to follow for migrating existing SOAP 1.1 or SOAP 1.2 web services to WCF services without impact for the calling applications. As a further benefit, those steps did not require a single change of implementation on the server side.
Handling SOAP headers with WCF in a compatible way, however, requires some minor adjustments in our orchestrations and/or schemas. The reason is that the SOAP adapter and the WCFadapters handle SOAP headers in a different way.
Let’s see how it goes:
Handling SOAP Headers in the Incoming Request
The BizTalk SOAP Adapter handles inbound SOAP headers by inspecting the appropriate part in the XML body of the incoming HTTP request and maps any existing headers to an XML fragment.
Each header is then written as a property into the context of the incoming message. The property for a SOAP header has the same name as the root tag of the XML fragment and is associated with the following built-in namespace:
In contrast, the BizTalk WCF-WsHttp and WCF-WsBasicHttp Adapters, handle inbound SOAP headers by writing properties into the context of the incoming message. Each header is associated with a context property whose name is the same as the root tag of the XML fragment and whose namespace is the same of the original TargetNamespace of said root tag.
In effect, the behaviour of both adapters regarding the handling of incoming SOAP headers is restricted to a difference in the namespace of the context property.
In order to iron out those differences, you might need to adapt the TargetNamespace of the property schema associated with your custom SOAP headers. Or you could create a custom pipeline component to create appropriate properties with the correct namespace.
Handling SOAP Headers in the Outgoing Response
Potentially, the web services that you want to migrate over WCF have SOAP headers as part of the response. Those need to be handled as well.
SOAP headers associated with a response message must explicitly be written to the context of the outgoing message.
When using the SOAP Adapter, SOAP headers must be defined in a custom property schema where the TargetNamespace is specified as the built-in SOAPHeader namespace. Then, headers can be specified using an Expression shape in an orchestration with the following syntax:
OutboundMessage(MySoapHeaders.Header1) = "" + "<tns1:Header1 xmlns:tns1='http://tns1'>" + "</tns1:Header1>" + ""; OutboundMessage(MySoapHeaders.Header2) = "" + "<tns2:Header2 xmlns:tns2='http://tns2'>" + "</tns2:Header2>" + "";
In this example, MySoapHeaders is the namespace associated with the property schema.
When using the WCF Adapters, SOAP Headers are defined with the built-in WCF.OutboundCustomHeaders context property. There is no need for custom property schema. The difference, however, is that all custom SOAP headers must be written in this single context property, wrapped inside an additional <headers> tag.
Therefore, headers can be specified from within an orchestration with the following syntax in an Expression shape:
OutboundMessage(WCF.OutboundCustomHeaders) = "" + "<headers>" "<tns1:Header1 xmlns:tns1='http://tns1'>" + "</tns1:Header1>" + "<tns2:Header2 xmlns:tns2='http://tns2'>" + "</tns2:Header2>" + "</headers>" + "";
As we’ve seen, minor adjustments need to be made on the service side, in order to transparently handle SOAP headers in WCFC services migrated from SOAP.