Saturday, April 12, 2008

Fixing BizTalk's WCF Message Contract Mix-Up, Part 3

The final solution to the Message Contract Mix-Up doesn’t require you to define your own message contracts, but does require some tricks in both the operation contract and the BizTalk ports.

First, modify the operation contract by adding a MessageParameterAttribute to the argument and return type:

[OperationContract]
[return:MessageParameter(Name="OrderStatus")] PurchaseOrderStatus PlaceOrder([MessageParameter(Name="PurchaseOrder")]PurchaseOrder po);

MessageParameterAttribute lets you change the names that the parameter and return value will have in the SOAP body. The names need to be changed to “PurchaseOrder” and “OrderStatus” so BizTalk can associate the schemas PurchaseOrder.xsd and OrderStatus.xsd with those elements. (Without MessageParameterAttribute, WCF would force the names of the parameter and return value to be “po” and “PlaceOrderResult”, which mean nothing to BizTalk).

Now you need to modify the WCF adapter settings in the two-way receive location in BizTalk. For general instructions and screenshots illustrating the following steps see the BizTalk documentation here. Open the Messages tab of the WCF adapter. Under “Specify the source of the inboud BizTalk message body”, check the third radio button, “Path – content located by body path”. In the text box type an XPATH expression consisting of the name of your operation contract, followed by the name of your data contract schema:

/*[local-name()='PlaceOrder']/*[local-name()='PurchaseOrder']

Make sure the combo box below the text box, “Node encoding”, is set to XML.

The first element in the XPATH is actually the WCF-generated message contract, which has the same name as the operation contract (“PlaceOrder”). The following element is the name of the parameter inside the message contract, which we forced to be “PurchaseOrder” by applying the MessageParameterAttribute.

The consequence of these settings is that the WCF adapter will drill through the message contract and pass the PurchaseOrder element to BizTalk as the message body. Bingo!

Since this is a two-way port, we need to return a data contract back to the caller, and to do that we need to tell the WCF adapter how to wrap the data contract inside a message contract. To do that, go to the bottom half of the tab and check “Template – content specified by template.” In the text box below, be careful not to delete or change the bts-msg-body element that’s already there, since that represents the data contract part of the message. Instead, insert an XML element around the bts-msg-body to represent the message contract. The name of this element is the operation contract’s name plus the suffix “Response”, and it must include the correct XML namespace:

<PlaceOrderResponse xmlns="urn://MyCompany.Purchasing.1_0_0.com" >
<bts-msg-body xmlns="http://www.microsoft.com/schemas/bts2007" encoding="xml" >
</PlaceOrderResponse >

If this were a one-way send port we would follow the same procedure.

The result is that BizTalk will send the return value to client wrapped inside the same message contract that WCF would have generated automatically if the service were hosted in a pure .NET application. Bingo Bingo!

So there you have three ways to solve the Message Contract Mix-Up with the BizTalk WCF adapters. If you’ve read all the way through this series, I surmise that you either find the subject fascinating, or you need to solve these problems as badly as I did.

1 comment:

Vivek Dahiya said...

Hello Richard: I am having a problem while consuming a WCF Service using Dynamic send port. The message I am trying to pass becomes null when it hits the wcf service. I am assuming that it might have something to do with message contracts. I've posted the problem here on ESB forum: http://social.msdn.microsoft.com/Forums/en-US/biztalkesb/thread/9e703741-907e-4d50-8e9c-4a587985b145

I would appreciate if you could provide some guidance on that. Thanks in advance.