Passing strongly typed data to a JavaScript control add-in

Many cool things often go undocumented. I’ve just stumbled upon one of those, and it comes in handy to close this year of blogging.

Imagine this situation: you have a server-side .NET object, that you want to pass on to the client. With the .NET System.Windows.Forms-based objects, you have to make the object serializable, deploy the object to the client-side Add-in folder, and then set the RunOnClient property on the C/AL variable to Yes.

However, if the client is not .NET-based, if it is a cross-client JavaScript-based one. You may think that it’s not possible to pass the custom object on to JavaScript code. And you may be wrong.

One of many beauties of JavaScript is that it can construct objects on the fly, using JSON notation. For example, if you want to have an object to represent a person, you can just do this:

 

 

.NET is not as flexible, it requires you to declare a class first. C/AL is even less flexible, because it doesn’t even have classes.

But imagine that you had the following C# class that you used on both client and server side in C/AL:

 

 

To pass it on to JavaScript, in your control add-in interface, simply declare a method:

 

Then, in your JavaScript script file, define the function:

 

 

And then, you don’t need to do anything at all. NAV runtime will take care of everything. As a matter of fact, you don’t need to have the assembly deployed to the client add-ins folder at all.

Why does it work?

It’s simple. As long as your class is serializable (for example, by decorating it with the [Serializable] attribute), the NST first serializes it to XML. Then, the client-side runtime (either the Web client ASP.NET application, or the Windows client) translates the XML to JSON, and then passes it on to your function as native JavaScript object.

And again – no deployment to client-side is required.

Pretty cool, if you ask me. I haven’t tested it with everything, but I can make an educated guess here: as long as it is serializable to XML, and as long as all data types you use can be mapped to JavaScript data types, you can pass just about anything.

This gives you a lot of flexibility when interacting between the client and the server, and it also allows you to port your .NET-based control add-ins to JavaScript much easier.

11 thoughts on “Passing strongly typed data to a JavaScript control add-in”

  1. Nice article but how would this work in the real world?
    You say ‘NAV runtime will take care of everything.’. What do you mean by that? What would call your ‘SendPerson’ method? How do I ‘feed’ it a NAV record that corresponds with the c# class?
    Do I instantiate a new object of class Person in c/al as a dotnet variable and pass it to the function?

    1. I am talking about serialization and deserialization to/from JSON here. That’s the part that is taken care of by NAV runtime. So, you have a class that you want to send to JavaScript, you (that’s the answer to your question “what would call the method”) call the SendPerson method. You cannot feed it a NAV record, because NAV records are not serializable (or assignable, or boxable to objects). So, you instantiate a new Person instance in C/AL as a DotNet variable (or receive it as a result from a .NET function call) and then pass it to the function, NAV runtime serializes it into JSON and passes onto JavaScript, which sees it as a JavaScript object.

  2. Do you know whether serialization also works the other way round? Your article describes the way from .NET to JavaScript, does it also work from a JavaScript object to a .NET object?

    1. Yes, it does – but depending on what exactly you are sending from JavaScript to what exactly in .NET, you may not get what you want. Check my examples from the TechDays 2015 – it’s all in there. If it still doesn’t work for you, post specific issue here and I’ll post a specific answer.

  3. Hi. Great article (the others are too :)).

    I’m quite new to NAV development (coming from .NET area).

    I’m trying to create a Javascript add-in that receives data from the C/AL. There is a class definition for the data in the dll. In the C/AL globals, I can see the type among the DotNet types, and I can call the constructor. The compiling is successful.

    But when I run it in the web client, I get the “Cannot load an instance of…” exception. I found out, that this is because of the RunOnClient is set to ‘No’. But web client doesn’t support RunOnClient…

    Is there any solution for this?

    Thanks in advance,
    Andras

    1. You must deploy that DLL to the service tier. When you create an instance at the service tier and pass it to JavaScript, it gets translated to JSON, however the NST must be able to instantiate the object. It’s happening on the server side, not the client. The client merely receives JSON (text) representation of it.

  4. Hi, thanks for the answer.

    (I’ve been on holiday, so I read your comment just recently.)

    By deploy you mean copy the dll and register as a control add-in? I’ve done it, but something didn’t fit. Maybe I just copied a wrong version of the dll, because recopying it healed the add-in… 🙂

    Thanks again.

    Andras

    1. Yes, it could have been an old version or something. Global Assembly Cache tends to interfere if you deploy your assemblies there. Glad it works now 🙂

      1. Hi. I’ve just played a bit with the dll and turned out, that GAC caused my original problem. Because it’s not enough to register the dll at the first time and then just overwrite it during the deployment. It needs to be reregistered after each deployment. So you were rigth again with GAC… 🙂

        Now I’m facing another problem. The add-in works fine with the Web Client, but in Windows Client it doesn’t load into the window. Instead I get an Internet Explorer-like error: “This page can’t be displayed. Make sure the web address is correct. Look for the page with your search engine…” etc.

        I tried to disable the firewall, the antivirus and lower the IE security level (I don’t now, that is it related to the NAV Windows Client or not), but nothing worked.

        Do you have any experience with this kind of problem?

        Thanks,
        Andras

Let me know what you think

This site uses Akismet to reduce spam. Learn how your comment data is processed.