Passing strongly-typed data to NAV Web services can be trickier than it seems. If you are lucky, you can make your method accept strongly-typed parameters, and you are good to go. However, if you just can’t avoid sending text data, your text must be encoded in EN-US format, otherwise it will cause problems (see this).
What the heck, just encode the data as EN-US, right? Not quite. There are a myriad of reasons why data can come in non-EN-US encoding, one of which is this: it’s the Web services, for Pete’s sake – anyone or anything can call them.
Are there real-life scenarios for this?
Actually, there are. The most common one, which we have encountered in Stratus as well (but I’ve seen it on Mibuso, as well), is that you might need to pass an obscene amount of data between NAV and the consumer, and sometimes that data contains a variable number of parameters. Values for all the fields of any table, for example. Natural way of passing such data is through XML, and the only way to pass XML is through text.
And there we are – the only way in NAV to obtain decimals, or integers, or dates, or strongly-typed data in general, from text, is to call EVALUATE. And this naughty little function unfortunately isn’t as smart as being able to apply any format. It can only apply the format of the currently active language, and in Web services it defaults to EN-US.
To switch from theory to practice, if you receive the string ‘1.000’ in HR (or apparently ES) locales, it would get EVALUATEd to 1, whereas the value actually meant 1000 in HR or ES locales. If you pass the date ‘13-08-2012’ in NL locale, you would apparently get an invalid date error, and EVALUATE would fail.
Not really something you’d like to have in your database.
How to pass the strongly typed data, then?
The best way to pass large chunks of variable-structured data to NAV is by using XML, which is text, and is prone to problems with EVALUATE’s dependency on the actual locale.
So, how to get around it? By using .NET interop.
.NET comes with a great capability which is called serialization. Serialization allows any object in memory (okay – this any comes with a disclaimer) to be streamed into binary or XML representation, which can then be deserialized, i.e. to instantiate the same object with the same state, from that binary or XML representation. Of course, serialization can work with other formats, as well, but binary and XML are the most common.
Imagine this:
And you then use this class in a function:
Serialization can turn this into the following XML:
Beauty of this is that it can be deserialized back into an instance of class Person, without losing any information, and without having to worry about current regional settings.
Serialization is a much more complex topic than just what I’m going to show, but to make it serializable, the only thing you need to do with your class is this:
Then simply call Serialize to return the string, or Deserialize to return an instance from the string.
How that you have that class, deploy it as a .NET add-in into your NAV instance, and write a function such as this:
Then simply test to make sure it really does exactly what it says on the tin:
You can download the .NET project and the required FOB file by clicking here.
I hope this was helpful. Please share your thoughts.
Errm,
Haven’t you heard of
EVALUATE(VarRef, TextStr, 9);
That accepts only i18n independent XSD formats for the values, just like your C# serialisation example.
Robert: no, I haven’t heard of EVALUATE, I must now re-evaluate my 10 years of NAV experience to check how possibly I have missed that 🙂 Now seriously, it really doesn’t help at all. It may accept only the independent XSD format, it has three major drawbacks as compared to .NET serialization: 1) it requires you to manually format the values at originating end, which was the problem in the first place; 2) data structures are future-proof – once you have a class which you serialize and deserialize, any modifications of the class won’t require absolutely any change in the code on the receiving end, whereas with EVALUATE I’d have to either remove or add more EVALUATEs as the data structure changes; and 3) if you have some data structure to pass around, isn’t it better to use exactly the same structure at both ends – in my example you are serializing and deserializing the same class, whereas with EVALUATE you may end up having totally different structures to work with.
Pingback: Passing strongly-typed data to Web services | Pardaan.com
Awesome! Thanks for taking the time to share Vjekoslav . I’ll make sure I bookmark this for future reference 🙂