Search code examples
c#json.netjson.net

Most effective way to Read/Write dynamic Newtonsoft.JSON


I`m trying to read and write JSON using Newtonsoft.Json on .NET Core 3.1 But my converter didn't work. This is my json file. Also props will be generate runtime (dynamic data) without model to parse.

Problem occurs when deserializer hits array in json and try to cast it.

JSON:
https://pastebin.com/h3Mi8RBD

 var data = File.ReadAllText(json);

 var settings = new JsonSerializerSettings()
        {
            Converters = { new DictionaryConverter() },
        };
var result = JsonConvert.DeserializeObject<IDictionary<string, object>>(data, settings);


private object ReadValue(JsonReader reader)
{
    while (reader.TokenType == JsonToken.Comment)
    {
        if (!reader.Read())
            throw JsonSerializationExceptionCreate(reader, "Unexpected end when reading IDictionary<string, object>.");
    }

    switch (reader.TokenType)
    {
        case JsonToken.StartObject:
            return ReadObject(reader);
        case JsonToken.StartArray:
            return ReadList(reader);
        default:
            if (IsPrimitiveToken(reader.TokenType))
                return reader.Value;

            throw JsonSerializationExceptionCreate(reader, string.Format(CultureInfo.InvariantCulture, "Unexpected token when converting IDictionary<string, object>: {0}", reader.TokenType));
    }
}

private object ReadList(JsonReader reader)
{
    List<object> list = new List<object>();

    while (reader.Read())
    {
        switch (reader.TokenType)
        {
            case JsonToken.Comment:
                break;
            default:
                object v = ReadValue(reader);

                list.Add(v);
                break;
            case JsonToken.EndArray:
                return list;
        }
    }

    throw JsonSerializationExceptionCreate(reader, "Unexpected end when reading IDictionary<string, object>.");
}

private object ReadObject(JsonReader reader)
{
    IDictionary<string, object> dictionary = new Dictionary<string, object>();
    while (reader.Read())
    {
        switch (reader.TokenType)
        {
            case JsonToken.PropertyName:
                string propertyName = reader.Value.ToString();

                if (!reader.Read())
                    throw JsonSerializationExceptionCreate(reader, "Unexpected end when reading IDictionary<string, object>.");

                object v = ReadValue(reader);

                dictionary[propertyName] = v;
                break;
            case JsonToken.Comment:
                break;
            case JsonToken.EndObject:
                return dictionary;
        }
    }

    throw JsonSerializationExceptionCreate(reader, "Unexpected end when reading IDictionary<string, object>.");
}

//based on internal Newtonsoft.Json.JsonReader.IsPrimitiveToken
internal static bool IsPrimitiveToken(JsonToken token)
{
    switch (token)
    {
        case JsonToken.Integer:
        case JsonToken.Float:
        case JsonToken.String:
        case JsonToken.Boolean:
        case JsonToken.Undefined:
        case JsonToken.Null:
        case JsonToken.Date:
        case JsonToken.Bytes:
            return true;
        default:
            return false;
    }
}

// based on internal Newtonsoft.Json.JsonSerializationException.Create
private static JsonSerializationException JsonSerializationExceptionCreate(JsonReader reader, string message, Exception ex = null)
{
    return JsonSerializationExceptionCreate(reader as IJsonLineInfo, reader.Path, message, ex);
}

// based on internal Newtonsoft.Json.JsonSerializationException.Create
private static JsonSerializationException JsonSerializationExceptionCreate(IJsonLineInfo lineInfo, string path, string message, Exception ex)
{
    message = JsonPositionFormatMessage(lineInfo, path, message);

    return new JsonSerializationException(message, ex);
}

// based on internal Newtonsoft.Json.JsonPosition.FormatMessage
internal static string JsonPositionFormatMessage(IJsonLineInfo lineInfo, string path, string message)
{
    if (!message.EndsWith(Environment.NewLine))
    {
        message = message.Trim();

        if (!message.EndsWith(".", StringComparison.Ordinal))
            message += ".";

        message += " ";
    }

    message += string.Format(CultureInfo.InvariantCulture, "Path '{0}'", path);

    if (lineInfo != null && lineInfo.HasLineInfo())
        message += string.Format(CultureInfo.InvariantCulture, ", line {0}, position {1}", lineInfo.LineNumber, lineInfo.LinePosition);

    message += ".";

    return message;
}

I think there are features need to add to the converter.


Solution

  • it is right c# class object:

    // Root myDeserializedClass = JsonConvert.DeserializeObject(myJsonResponse); public class Structure { public string Column { get; set; } public string Type { get; set; } public string InputType { get; set; } public string FromTable { get; set; } public int FromId { get; set; } public bool IsForeingTableDynamic { get; set; } }

    public class Table
    {
        public string name { get; set; }
        public int ShowForm { get; set; }
        public List<Structure> Structure { get; set; }
    }
    
    public class Root
    {
        public string SystName { get; set; }
        public string DisplayName { get; set; }
        public List<Table> Tables { get; set; }
    }