Passing JSON from JavaScript to C/AL

Yesterday, I said I was closing this year of blogging, but I wasn’t really. Closing a year with 39 posts, and leaving a question lingering, wouldn’t be too fair, would it? If you read my last postabout how to pass objects from C/AL to JavaScript, you must have wondered if it’s possible to also pass objects from JavaScript back to C/AL.

Wonder no more. It is. And here’s how.

Again, a bit of theory. JavaScript uses JSON to represent objects. Any object that resides in memory of a JavaScript runtime environment can be represented as JSON. For example:

var person = {

  FirstName: "John",

  LastName: "Doe"

};

 

 

This is almost equivalent to:

Person = function(firstName, lastName) {

  this.FirstName = firstName;

  this.LastName = lastName;

};

var person = new Person("John", "Doe");

 

At least, JSON representations of both of these objects are equivalent.

Now, imagine that you want to pass either of these on to NAV. Obviously, JavaScript won’t complain if you do this:

Microsoft.Dynamics.NAV.InvokeExtensibilityMethod("SendDataToCAL", [person]);

 

or, for that matter, this:

Microsoft.Dynamics.NAV.InvokeExtensibilityMethod("SendDataToCAL", [{ FirstName: "John", LastName: "Doe" }]);

 

Is there anything you can do in C/AL to properly receive this information?

Of course, for that to work, you need to have a delegate of this signature:

public delegate void ObjectEventHandler(object data);

 

And an event for this delegate on your control add-in interface:

event ObjectEventHandler SendDataToCAL;

 

What exactly does this JavaScript object become when it is passed onto C/AL?

The easiest way to find out is to cast it to System.Object and inspect its type, something like this:

Obj := data;

MESSAGE('%1', Obj.GetType());

 

 

This is what you get:

image

Obviously, JavaScript passes the object as JSON, and your .NET interop layer simply receives it as a kind of JSON representation as well. Here, the NST uses Json.NET, a popular open-source .NET JSON framework. You can declare its JObject variables if you copy the Newtonsoft.Json.dll assembly from the Service folder to the Add-ins subfolder.

However, using it to properly deserialize the JObject into a specific object type can be tricky, because it uses generics.

A simpler way is to use .NET built-in functionality for JSON serialization, that you can find in the DataContractJsonSerializer class. To use it, declare the following variables:

Variable Type
Serializer System.Runtime.Serialization.Json.DataContractJsonSerializer.’System.Runtime.Serialization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′
MemStream System.IO.MemoryStream.’mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′
Encoding System.Text.Encoding.’mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′
Person <your Person class from a custom assembly>

This Person class must be declared in your assembly like this:

[DataContract, Serializable]

public class Person

{

  [DataMember]

  public string FirstName { get; set; }

  [DataMember]

  public string LastName { get; set; }

}

 

 

Then, you deserialize your JObject into an instance of the Person class like this:

Person := Serializer.DataContractJsonSerializer(GETDOTNETTYPE(Person)).ReadObject(MemStream.MemoryStream(Encoding.UTF8.GetBytes(FORMAT(data))));

This data variable, is obviously, the object you received as a parameter to this event trigger in C/AL. FORMATting it calls its ToString method, and when you call the ToString method on the JObject class, it returns the string JSON representation of the object.

The trick with the Person class is that you must first make it JSON-serializable, which you do with the DataContract attribute. However, you must also make it explicitly Serializable, otherwise the NST layer will have issues properly deserializing the implicitly defined properties. For some reason, JSON serialization works fine with explicitly defined properties (backed with private fields), or directly with fields, but not with implicitly defined properties. Once you make your class explicitly Serializable, you work around this limitation.

And that’s, it, from that moment on, your Person is correctly deserialized from JSON you got from JavaScript, and you can use it as any other object:

MESSAGE('Hello, ' + Person.FirstName + ' ' + Person.LastName);

 

Being able to pass objects between JavaScript and C/AL is essential, as it simplifies the signatures of your functions, and allows you to handle data in the semantically clearest way.

And that would be it for this year, I hope the next one brings a lot of new content to this blog. Now, let’s pop the cork, and celebrate!

Vjeko

Vjeko has been writing code for living since 1995, and he has shared his knowledge and experience in presentations, articles, blogs, and elsewhere since 2002. Hopelessly curious, passionate about technology, avid language learner no matter human or computer.

This Post Has 4 Comments

  1. Tomi Koskela

    Thank you for your blog and happy new year!

    1. Vjeko

      Thanks! All the best to you, too!

Leave a Reply