-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
toJSON of a host object #122
Comments
After a little experimenting I can see that |
A difficult situation. I'm thinking, you can add implementation of |
It appears the main issue is that external JSON serializers don't understand the JSValue objects, even when they have base data types. For instance, calling NewtonSoft's serializer with a variable assigned with the number 9 results in |
Because we cannot modify external serializer, need to use public sealed class MyFirstDTO
{
public int Field1 { get; set; }
public int Field2 { get; set; }
}
public sealed class MySecondDTO
{
public int Field3 { get; set; }
public int Field4 { get; set; }
}
public sealed class MyDtoSerializer
{
public static object SerializeToJSObject(MyFirstDTO myDto)
{
// Some serializer
return serializeToJSObject(myDto);
}
public static object SerializeToJSObject(MySecondDTO myDto)
{
return serializeToJSObject(myDto);
}
private static object serializeToJSObject(object obj)
{
if (obj == null)
return null;
var result = JSObject.CreateObject();
var properties = obj.GetType().GetProperties();
foreach (var prop in properties)
{
result[prop.Name] = JSValue.Marshal(prop.GetValue(obj));
}
return result;
}
}
static void Main(string[] args)
{
var context = new Context();
var jsObject = JSObject.CreateObject();
jsObject["dto1"] = JSValue.Marshal(new MyFirstDTO { Field1 = 777, Field2 = 420 });
jsObject["dto2"] = JSValue.Marshal(new MySecondDTO { Field3 = 123, Field4 = 456 });
// this need to do only once
var serializerConstrucor = context.GlobalContext.GetConstructor(typeof(MyDtoSerializer));
var serializeFunction = serializerConstrucor["SerializeToJSObject"];
context.DefineVariable("serializeDtoFunction").Assign(serializeFunction);
var toJsonFunction = context.Eval("(function() { return serializeDtoFunction(this) })");
context.GlobalContext.GetConstructor(typeof(MyFirstDTO)).As<Function>().prototype["toJSON"] = toJsonFunction;
context.GlobalContext.GetConstructor(typeof(MySecondDTO)).As<Function>().prototype["toJSON"] = toJsonFunction;
context.DefineVariable("test").Assign(jsObject);
Console.WriteLine(context.Eval("JSON.stringify(test)")); // {"dto1":{"Field1":777,"Field2":420},"dto2":{"Field3":123,"Field4":456}}
} Is this solution appropriate? |
Not really. This assumes users are happy to create and assign an unknown number of these for every .NET object they want to be able to convert to JSON. |
Is there a problem with performing this within the JSON class? :
This recurses down the nested native objects properly, but will still have issues with things like Lists and Dictionaries which won't be serialised. |
It will break stringification for external types (and some from var s = new Set();
s[1] = 1;
JSON.stringify(s); // should be "{\"1\":1}", but will be "{\"size\":0}" I have already begun work on support of external "stringificators". I need a few days. |
Do your DTOs have a common base type other than |
We can't expect everyone to have a base class for every object they want to serialise to JSON.
This tells Newtonsoft to use the custom deserialize for JSValue objects, and that tells it to serialize the |
Hmm, that still has an issue with |
This problem is very complex. At this moment for external types engine tries to simulate behaviour as a native js types (constructor, |
Yes, although it doesn't matter if it's a DTO or any other type of .NET object, the same problem exists. The main issue I have is understanding what your stringify function does, particularly when the comments are in Russian :) |
As a reference object, here's the one we use for testing:
Info:
|
So, I implemented some solution. By default public class MyFirstDTO
{
public int Field1 { get; set; }
public int Field2 { get; set; }
}
public sealed class MySecondDTO : MyFirstDTO
{
public int Field3 { get; set; }
public int Field4 { get; set; }
public MyFirstDTO Child { get; set; }
}
private static void serialization()
{
var context = new Context();
var jsObject = JSObject.CreateObject();
jsObject["dto1"] = JSValue.Marshal(new MyFirstDTO { Field1 = 777, Field2 = 420 });
jsObject["dto2"] = JSValue.Marshal(new MySecondDTO { Field3 = 123, Field4 = 456, Child = new MyFirstDTO { Field1 = 789, Field2 = 101112 } });
context.GlobalContext.JsonSerializersRegistry.AddJsonSerializer(new JsonSerializer(typeof(MyFirstDTO)));
context.GlobalContext.JsonSerializersRegistry.AddJsonSerializer(new JsonSerializer(typeof(MySecondDTO)));
context.DefineVariable("test").Assign(jsObject);
Console.WriteLine(context.Eval("JSON.stringify(test)"));
} |
OK, but does this mean the developer has to add every framework object they may ever serialise to the JsonSerializerRegistry? |
Yes. Every object or them base class. |
Yeah, this isn't going to be a very practical option. Why not add:
Then the user can programmatically decide if they are able to serialize the object or not? |
Create your own serializer as a subclass of |
At the moment there doesn't seem to be any converting a native object to JSON. Adding
toJSON
to a .NET class results in a serialised string, and while you can do an externalJSON.stringify
of result.Value, this obviously fails for embedded javascript objects in the array.It might be best to provide a hook on the context that is called by the JSON.cs when it finds a value is not a JSValue, then the user can decide the serialised content to return?
There are a few places this is an issue, such as Lists of values coming back as
which is unrelated to the data contained in the List.
The text was updated successfully, but these errors were encountered: