Serialization issue

After a day of work I’m quite frustrated over the Serialization options in TinyCLR which appears to be full of bugs and flaws that makes them useless…

What I’m trying to achieve:

Sending a base object containing information about what to expect with a DTO by JSON

 public class BaseObject
  {
      public Guid Id { get; set; }
      public JsonObjectType MessageType { get; set; } //enum
      public bool SendAck { get; set; }
      public object Value { get; set; }
  }

example of a DTO:

public class Identification
{
    public string DeviceIdentifier { get; set; }
    public string Identifier { get; set; }
}

This either results in a exception throwed by the JSON serializer in TinyCLR or a invalid JSON which makes the deserializer on the server side throw exceptions

I think I have found two flaws, first the JSON.serializer in the TinyCLR sends Guid as number instead of string value which I think is incorrect. Second I’m not sure if TinyCLR JSON.serializer likes the object property in my BaseObject. I tried changed Value to a string and serialized the DTO first and assigned this to Value and then serialize BaseObject however this again yield a invalid JSON and throws exceptions on the server side.

I have attempted the same with the BSON aswell which also throws exceptions on the server because of invalid formatting.

A quick attempt using the the binary Serializer with the code linked to for the PC side didin’t work either.

Am I attempting something crazy or is there something seriously wrong with the serialization options provided by TinyCLR ?

How have you handled the TinyClr incompatibility with desktop serialization?

Made an attempt with the method suggested on the documentation page but without success. Serialization

Hi, could you please send both PC and TinyCLR example, so we can see what we can do?

GUIDs are not serialized correctly because the interpreter fails when running .ToString() on structs, including GUIDs. This has to be fixed in the interpreter - not the JSON serializer. If that’s been fixed, then I can patch the serializer to support GUIDs.

Handling polymorphic types stored as base classes (like ‘object’) requires additional code helpers for deserialization on the TinyCLR side:

public delegate object InstanceFactory(string instancePath, JToken token, Type baseType, string fieldName, int length);

I do have test cases for polymorphic serialization, but perhaps something got missed. That happens sometimes in software. Injecting strings as nested JSON will not work because that string will be subjected to JSON escaping and end up all wonky, but but you should be able to inject a JToken tree into an existing JToken tree, prior to using .ToString() to render the full tree into textual JSON.

BTW, if you really need to serialize a GUID to a string, either convert it to a byte array first, or create a utility function to convert the underlying struct to a string - essentially, manually implement GUID.ToString(). The TinyCLR implementation is correct, it’s just that the interpreter throws because of some unsupported IL code that the newer compiler emits.

Sending a string or Guid doesn’t matter. Changed the type to string and called Guid.NewGuid().ToString() when inserting into the object. quick workaround.

Hmm not sure if you mean. Adding a serialized object into a string is not allowed or just not properly supported?

Run the string through this. Escapes JSON characters and makes it work.
borrowed from: c# - How to escape JSON string? - Stack Overflow

public string CleanForJSON(string s)
{
    if (s == null || s.Length == 0)
    {
        return "";
    }

    char c = '\0';
    int i;
    int len = s.Length;
    StringBuilder sb = new StringBuilder(len + 4);
    String t;

    for (i = 0; i < len; i += 1)
    {
        c = s[i];
        switch (c)
        {
            case '\\':
            case '"':
                sb.Append('\\');
                sb.Append(c);
                break;
            case '/':
                sb.Append('\\');
                sb.Append(c);
                break;
            case '\b':
                sb.Append("\\b");
                break;
            case '\t':
                sb.Append("\\t");
                break;
            case '\n':
                sb.Append("\\n");
                break;
            case '\f':
                sb.Append("\\f");
                break;
            case '\r':
                sb.Append("\\r");
                break;
            default:
                if (c < ' ')
                {
                    t = "000" + String.Format("X", c);
                    sb.Append("\\u" + t.Substring(t.Length - 4));
                }
                else
                {
                    sb.Append(c);
                }
                break;
        }
    }
    return sb.ToString();
}

For others that might communicate with a backend. note that some JsonSerializers over escapes JSON characters in strings by replacing them with unicode characters.
For using System.Text.Json.JsonSerializer.Serialize() this can be avoided by adding this option to the serializer.

JsonSerializerOptions options = new JsonSerializerOptions
{
    Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};

I occasionally still see JSON deserialize exception on the backend but haven’t investigated what cause this. I assumes it has something to do with the serialized object been sent as a string because it depends on the payload.

Ah - I was trying to suggest how to include the embedded json without escaping - that is, by blending two json AST trees. That should result in a legal serialization. Escaping the embedded JSON and emitting it in a string (as looks like you are doing) will work too. What won’t work is serializing a JSON object and just stuffing it in a string without escaping … all of which you seem to have discovered.