Article Source: http://geekswithblogs.net/charliemott
What is the best approach for developing a WCF client application that sends messages to the WCF on-ramps exposed by the BizTalk ESB Toolkit?
I had considered various approaches:
- Generate an xml message from a string template using string replacements. Then submit the message to the ESB endpoint using code similar to the Itinerary Test Client provided with the ESB Toolkit. Then for the response use XPath to get the required data.
- This is obviously a lot of coding effort, inflexible and difficult to maintain.
- Modifying the generic wsdl for the ESB WCF service as described here.
- However, this is too much of an administrative nightmare. You need to create a wsdl for each possible service method. In addition it does not support the catching of expected SOAP faults without additional effort.
- Our team then considered an approach similar to that described here. This uses a generic ServiceContract interface that can take any object and serialise it to a System.ServiceModel.Channels.Message.
- However, the problem is that developers will still need to manually generate the DTO classes using a tool such as svcutil (getting the schemas from the location specified in the wsdl). As such, there is still a lot of effort required.
- A colleague then asked "why don't you just add a service reference to the end service and then re-point the client endpoint config to the ESB on-ramp". I had previously dismissed this idea because the end service exposes many methods\actions while the ESB on-ramps expose just one with a different name. However, he suggested you should be able to alter the action.
Using a WCF Message Inspector
Option 4 is the best option I think. You can modify the Action header using a custom behaviour with a custom Message Inspector following the approach described here.
The modified message inspector code for the request-response on-ramp would be as follows:
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel)
request.Headers.Action = "http://microsoft.practices.esb/ProcessRequestResponse";
The client service code would be something like this:
public int FindProducts (ProductSearchCommand searchCommand)
var client = new ProductServiceClient(this.EsbOnRampRequestResponseEndpointConfig);
client.Endpoint.Behaviors.Add(new OnRampRequestResponseBehavior()); // this could be done via endpoint config (see here)
ProductsDocument products = client.Find(searchCommand);
The client direct call endpoint config would be modified to something like this to point to the ESB:
<userPrincipalName value="MyMachine\BizTalkUser" />
- In BizTalk, for the WCF receive location for the default ESB on-ramp has been modified so that the WCF adapter Message “UseBodyPath” settings use "Body" for the "Inbound BizTalk message body" and "Outbound WCF message body".
- The default on-ramp uses wsHttpbinding. This binding is based on SOAP 1.2. As such, soap faults will be returned using a soap 1.2 namespaces. If the end service uses basicHttpBinding, then the client code will not be able to catch the soap 1.1 fault. As such, mixing soap versions for the on-ramp and services called by an itinerary would require some additional research.