Supporting both Soap 1.1 and Soap 1.2 with BizTalk WCF Services

Last week, we’ve seen how to implement Soap-compatible services of BizTalk schemas or orchestrations with WCF. At the end of that post, I touched on an issue one faced while trying to call the resulting service with a Soap 1.2 compliant application.

The resulting WCF services take advantage of the BasicHttp WCF binding. As we’ve seen, this binding only supports Soap 1.1 messages. When trying to call our WCF service, we’re faced with the following error message:

HTTP/1.1 415 Cannot process the message because the content type ‘application/soap+xml;charset=UTF-8;action="http://services.sample.org/BizTalk/2010/soap/input/WebService/WebMethod"’ was not the expected type ‘text/xml; charset=utf-8’.

In this second article of the three part series, I will show how to support both Soap 1.1 and Soap 1.2 messages with WCF.

Supporting both Soap 1.1 and Soap 1.2 with BizTalk WCF Services

The key to supporting two (or more) protocols on a WCF service is to use the concept of endpoints. Indeed, as we’ve seen already, BizTalk web services exposed over SOAP implement two endpoints on the single .asmx address.

Configuring the service endpoints

The concept of WCF service endpoints has a one to one mapping with BizTalk receive locations.

Therefore we’ll create an additional receive location on the BizTalk side.

Configuring a custom binding

Out of the box, there is not any WCF binding that supports plain Soap 1.2 requests. The solution will be to create a custom binding. Don’t worry ! Even though creating a custom binding by code might seem like a daunting task, most of the time, custom bindings can be synthesized via configuration only. In BizTalk, a custom binding can be configured on the WCF-CustomIsolated adapter.

There are two ways to achieve what we want.

The first solution would involve taking the base WsHttp binding and removing unwanted features. The WsHttp binding implements Soap 1.2 messaging, as well as a host of different features such as transactions, reliable messaging and WS-Addressing.

The second solution seems more sensible. It involves taking the base components from the BasicHttp binding and customizing the Soap message version where appropriate.

This is the approach taken here.

The basicHttp binding is probably one of the simplest bindings available. It only contains two channel components in its messaging layer, which is the minimum required.

The HttpTransport component, at the bottom of the stack, is responsible for receiving the stream of data from the communication as a SOAP message. It uses a messaging encoder component to produce a WCF message to be processed further up in the channel stack.

The TextMessageEncoding component is responsible for adhering to the specified character encoding and message versioning used for text-based XML messages. This is the component where we’ll configure to handle Soap 1.2 message requests.

The configuration of the Messages tab is identical to that of the basicHttp receive location. We’ve seen previously that this is necessary for extracting the correct portion of the request as expected by the existing service, as well as customizing the XML message emitted in return.

One last thing about BizTalk receive locations. It is not possible to use two different "web service adapters" (WCF and SOAP/HTTP) on the same Isolated Host Instance (a.k.a. AppPool). This means that, obviously, the URI address configured on the BizTalk receive location must be unique.

This also means that we will need to either expose the two different endpoints on two different services or, more likely, to change the BasicHttp binding to an equivalent Custom binding, as have mostly been described already in this article.

Configuring the service host

– duplicate file, but modify WebServiceSoap11.svc Web Service Host Factory :

The markup in both resulting .svc files must be changed, to reflect the switch from a BasicHttp binding to a Custom binding. Specify the CustomWebServiceHostFactory instead of the BasicHttpWebServiceHostFactory used initially.

<%@ ServiceHost
	Language="c#"
	Factory="Microsoft.BizTalk.Adapter.Wcf.Runtime.CustomWebServiceHostFactory
	  , Microsoft.BizTalk.Adapter.Wcf.Runtime
	  , Version=3.0.1.0
	  , Culture=neutral
	  , PublicKeyToken=31bf3856ad364e35"
	%>

In case of difficulty for updating this file, it is always possible to re-generate the WCF service with the Publishing Wizard, and choose Custom-Isolated as the binding. Do not forget to update the custom service description WSDL to match the new Soap 1.2 endpoint :

  <wsdl:service name="WebService">
    <wsdl:port name="WebServiceSoap" binding="tns:WebServiceSoap">
      <soap:address location="http://localhost/Sample/WebServiceSoap11.svc" />
    </wsdl:port>
    <wsdl:port name="WebServiceSoap12" binding="tns:WebServiceSoap12">
      <soap12:address location="http://localhost/Sample/WebServiceSoap12.svc" />
    </wsdl:port>
  </wsdl:service>

Wrapping-up

Voilà ! A successful Soap 1.2 request:

Conclusion

In this post, I’ve shown a simple way to customize the WCF BizTalk adapter to implement an additionnal Soap 1.2 endpoint on the same service. Like the last time, this did not require any code nor any change in the service implementation.

In the final post of the series, I’ll briefly talk about handling SOAP headers.

This entry was posted in Wcf. Bookmark the permalink.