It is the WSDL, Stupid!

time to read 5 min | 912 words

In my current project, I need to talk to BizTalk, and have BizTalk talk to me. I usually don't like to work with things such as BizTalk and SSIS, because almost invariably, they make simple things more complex than they should be.

At any rate, the sceario is simply consuming web services, and having web services that BizTalk can call. I had two options to use here, I could use the usual ASMX web services, or I could use WCF. I did some testing with WCF, and it seemed fairly straight forward to use, but what made me decide to use it (beside the wish to try it out) was the logging support. It makes debugging so much easier when not only does it write everything to file, but it also provide a tool that allows easy browsing of messages and conversations.

At any rate, predictably, I run into problems. I had taken the test code for the web services that I needed to put so BizTalk can call me, and converted it from ASMX to BizTalk. Everything seemed to work fine, I would get the mesage, but I wouldn't get the values.

Consider this:

public class AddOrderLineConfirmMessage
{
   public string WhoAuthorized { get { .. } set { .. } }
   public string OrderId { get { .. } set { .. } }
   public string OrderLineId { get { .. } set { .. } }  
}

I am skipping the attributes here, I think that you get the mesage :-).

Well, I managed to get the message just fine, and the OrderId and the OrderLineId were filled with the correct values, but the WhoAuthorized field (which is the most important one here) was null.

Naturally, I blamed BizTalk for this, and called them to have it fixed. They swore up and down that they are sending the value is being sent from their end, and that the problem is on my side. Since I don't believe that my code can be flawed, I decided to prove them wrong, and took the sample code that used ASMX, and tried that.

That worked, not only did it work, but it also had the oh so important WhoAuthorized field. I then pulled the logs from the WCF service and saw that indeed, the message was something like:

<AddOrderLineConfirmation>
   <WhoAuthorized>foo</WhoAuthorized>
   <OrderId>1</OrderId>
   <OrderLineId>2</OrderLineId>
</AddOrderLineConfirmation>

At that point I was getting annoyed by the whole "WCF can't even work for my simple scenario" and decided that I would solve this issue if I had to write my own XML parser to do it. I began to dig into the WCF configuration options (a world of its own), and find out why it was ignoring the value that was clearly there.

I tried this, I tried that, and I couldn't figure it out. Until eventually I pulled out the WSDL and looked at it, trying to see if there was a namespace difference that could case it to ignore the value, or something of this order, but everything looked fine.

After quite a few of head banging, I finally noticed something odd. The fields in the WSDL were ordered alphabetically. So the WhoAuthorized field came last. That was when I knew that I had the issue solved.

The problem was with field orderring and versioning.

Basically, ASMX service would generate a message where the fields are ordered by their source code order (unless you explicitly specify otherwise). WCF, however, will order the fields by default according o the alphabet.

By chance, the OrderId and OrderLIneId were placed in the source code in an order that matched their alphabetical orderring. That meant that when WCF was parsing the message, it encountered WhoAuthorized field at the beginning of the message, and discarded it because it wasn't valid for the first field. It continued to discard fields until it riched the OrderId field, after which it found the OrderLineId field. Both of them matched the definition of the service message, so they were filled, but anything else turned out to be out of order and thus ignored.

The solution was to put Order=num in all the DataMember attributes, which let WCF know what is the expected orderring of the field in the document.

The lesson, always look one level down, and make sure that you are looking, not staring.