This project has moved and is read-only. For the latest updates, please go here.

Pass Javascript Object with Array to the host

May 21, 2016 at 3:13 AM
Here is my code:
using System;
using Microsoft.ClearScript.V8;
using Newtonsoft.Json;

namespace ConsoleApplication
{
    public class Test
    {
        public void Output(object o)
        {
            Console.WriteLine(JsonConvert.SerializeObject(o));
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var engine = new V8ScriptEngine();
            engine.AddHostObject("test", new Test());
            var script = "var o = {Persons: [{Name :\"John\"}, {Name :\"Joe\"}] }; test.Output(o);";
            engine.Execute(script);            
        }
    }
}
I expect that it output

{
"Persons": [
{
  "Name": "John"
},
{
  "Name": "Joe"
}
]
}

but it actually output

{
"Persons": {
"0": {
  "Name": "John"
},
"1": {
  "Name": "Joe"
}
}
}

I understand it use the dynamic V8ScriptItem to convert the javascript object to host object.

But is there a way to keep array of javascript as also a array or list of host object?
Coordinator
May 23, 2016 at 12:56 PM
Hello!

ClearScript doesn't convert script arrays to host arrays automatically. Instead, it lets you access script arrays directly from the host, and vice versa.

Can you say more about your requirements? If you just need to produce the correct JSON for your script object, then you probably want to use JavaScript's JSON object instead of Json.NET. Otherwise you may need to expose an array conversion function and invoke it manually.

Thanks!
May 23, 2016 at 3:25 PM
Thanks!

My requirement can be simplified like my example above, i want to expose Test.Output for the script side to output some debug information.

So I can pass any json object to the Test.Output, so that at the host side, it can Serialize it as string and output to the Console.

As you point out, I can stringify the object as string and pass it to the host side to output to the console, but just want to know if there is a way that I can let the host side serialize it correctly or as I expected before output to the Console.

Thanks again,
Coordinator
May 23, 2016 at 5:13 PM
Edited May 23, 2016 at 5:26 PM
Hi again,

One thing you could do is modify your Test class so that it converts arrays before passing them to Json.NET:
public class Test {
    private readonly V8Converter v8Converter = new V8Converter();
    public void Output(object o) {
        Console.WriteLine(JsonConvert.SerializeObject(o, v8Converter));
    }
    private class V8Converter : JsonConverter {
        public override bool CanConvert(Type type) {
            return type.Name == "V8ScriptItem";
        }
        public override void WriteJson(JsonWriter w, object o, JsonSerializer ser) {
            dynamic dynObj = o;
            if (dynObj.constructor.name == "Array") {
                var length = (int)dynObj.length;
                var array = Enumerable.Range(0, length).Select(i => dynObj[i]).ToArray();
                ser.Serialize(w, array);
            } else {
                var names = (IEnumerable<string>)dynObj.GetDynamicMemberNames();
                var dictionary = names.ToDictionary(name => name, name => dynObj[name]);
                ser.Serialize(w, dictionary);
            }
        }
        public override object ReadJson(JsonReader r, Type type, object o, JsonSerializer ser) {
            throw new NotImplementedException();
        }
    }
}
Checking the script item type this way is a bit hacky, but it works :)

Good luck!
May 23, 2016 at 6:24 PM
Perfect!

Thanks.