A beauty of Web services is that they don’t need to care at all about who’s consuming them. Whether there is .NET on Windows, Java on Linux or some proprietary stuff on an iPad on the other end, they do exactly the same stuff.
To make it short: if something works on one platform and fails on another platform, it’s not the fault of the Web service being called, it’s the fault of the caller platform.
As I said in the last post, there are two ways, or platforms if you wish, native to .NET Framework, which you can use to connect to any Web services. And they don’t work exactly the same.
The first scenario which I am going to present doesn’t work if called from a .NET application through a Web Reference approach, while it works quite happily if called through a Service Reference.
Create a new Codeunit, create one single method there, and have it do this:
If you see from far away that this will fail – you are absolutely right. But the point here is that there are two ways for this code to fail: the right way, and the wrong way.
The right way for this to fail is this:
The wrong way for this to fail is if you call through a Web-Referenced Web service.
So, publish the codeunit as a web service, create new Windows Forms application in Visual Studio, and have it call this Web service. You’ll be surprised that the error message you get is something completely different: the error message reads “Response is not well-formed XML.”
That’s not what you need, though. And the XML is pretty much well-formed, thank you very much! The InnerException will tell you that there is a problem with source XML, and will specify the allegedly scrambled data which couldn’t be parsed as XML.
A failure is a failure, right? Not quite. The error that this has returned has nothing to do with an error that actually happened. Actually, you don’t have a clue if an error happened. Try changing the demo codeunit you’ve written above into this:
If you call Foo2, no runtime error will occur in NAV, and it will either return the last error message or an okay message.
Still, calling it from a Web Reference gives this: There is an error in XML document (1, 163).
At the same time, calling Foo Service Reference, throws the runtime error: “You cannot base a date calculation on an undefined date. Date: 0D Formula: 1", whereas calling Foo2 simply returns the expected text, without a runtime error. Just as expected.
So, what went wrong here? We have two different .NET ways of calling the same stuff, yet one fails, and one succeeds.
Taking the postulate from the beginning of this post, that NAV Web service did and returned exactly the same stuff (you can easily verify that by capturing the XML traffic), something must be failing at client side.
That something, in this specific case, is deserialization of XML-encoded binary information.
If you inspect the XML which NAV Web service sent as a response to the SOAP request of either of the approaches above, it included the date formula represented as 1. 1 is the same as it was, it’s the M part which was, internall in NAV, encoded as ASCII character 5, which is unprintable, therefore translated into it’s hexadecimal representation x5, and XML encoded as . The problem is that it was properly deserialized in case of a Service Reference, and not understood in case of a Web Reference.
In fact – that’s a problem in .NET itself, not in NAV. If you take the analysis further, you’ll realize that you can’t have any control whatsoever over the deserialization process in case of a Web Reference, as it happens within the SoapClientProtocol class, which is a built-in .NET object. In other words: there is nothing you can do about this.
If, for whatever reason, Web services you are calling return unformmatted DateFormulas or other binary data which would require XML encoding, don’t use Web References as they will not be able to deserialize such information.
The only workaround is to use Service References, which have no issues there.