0

I having some trouble while trying to deserialize some json, because it's comming with unnescaped double quotes from ther server. As I don't have access to fix this on the server side I'm trying to ignore problematic json. To do so, I've followed these answers https://stackoverflow.com/a/21542099/2779990 and Ignore parsing errors during JSON.NET data parsing. When I use errorArgs.ErrorContext.Handled = true; the response object is null.

So I implement my own converter:

public class FieldConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(FieldOperationDomain);
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            FieldDomain field = new FieldDomain();

            try
            {
                JObject jObject = JObject.Load(reader);

                JToken name = jObject["Name"];

                if (name.Type == JTokenType.String)
                {
                    field.Name = (string)name;
                }
                else
                {
                    field.Name = null;
                }

                JToken value = jObject["Value"];

                if (value.Type == JTokenType.String)
                {
                    field.Value = (string)value;
                }
                else
                {
                    field.Value = null;
                }

                return field;

            } catch (Exception e)
            {
                return new FieldDomain
                {
                    Name = "",
                    Value = ""
                };
            }
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }

My json looks like this:

[
 {
   "id": "1d5c9ea3-7eb3-4fff-b8da-0a4dec891054",
   "RecordType": 1,
   "Field": []
 },
 {
   "id": "1d5c9ea3-7eb3-4fff-b8da-0a4dec891054",
   "RecordType": 1,
   "Field": [
      {
       "Name": "something",
       "Value": "Other something"
      },
      {
       "Name": "something",
       "Value": "Problematic "Other something""
      }
   ]
 }
]

My domain objects look's like this:

    public class MainDomain
    {
        [JsonProperty("id")]
        public long RecordType { get; set; }
        
        [JsonProperty("RecordType")]
        public long RecordType { get; set; }
        
        [JsonProperty("Fields")]
        public IEnumerable<Field> Fields { get; set; }
    }
    
    [JsonConverter(typeof(FieldOperationConverter))]
    public class FieldDomain
    {
        [JsonProperty("Name")]
        public string Name { get; set; }
        
        [JsonProperty("Value")]
        public string Value { get; set; }

        [OnError]
        internal void OnError(StreamingContext context, ErrorContext errorContext)
        {
            errorContext.Handled = true;
        }
    }

I even also try to add this to the problematic object:

        [OnError]
        internal void OnError(StreamingContext context, ErrorContext errorContext)
        {
            errorContext.Handled = true;
        }

The problem is that even using the try catch block to catch any exception on JObject jObject = JObject.Load(reader);, this not prevent JsonConvert.DeserializeObject<IEnumerable<T>>(document, settings); from throwing an exception. It's possible to do something similar to errorArgs.ErrorContext.Handled = true; inside ReadJson method?

marcelo
  • 171
  • 3
  • 8

1 Answers1

1

Why not just remove the double quote? Is Json very large?

private static string NormalizeJson(string json)
{
    
    var sb = new StringBuilder(json.Length);
    var jsonLength = json.Length;
    for (int i = 0; i < jsonLength; i++)
    {
        var ch = json[i];
        switch (ch)
        {
            case '"':
                // found quot
                sb.Append(ch);
                i++;
                var quIndex = GetEndIndex(json, i);

                var length = quIndex - i;
                 if (length > 0)
                {
                    // replace to white space
                    var buf = json.Substring(i, length)
                        .Replace("\"", " ");
                    sb.Append(buf);
                }

                sb.Append(json[quIndex]);
                i = quIndex;

                break;
            default:
                sb.Append(ch);
                break;
        }
    }

    return sb.ToString();
}

private static int GetEndIndex(string json, int i)
{
    var jsonLength = json.Length;
    var quIndex = i;
    //scan forward, try find end
    var isEnd = false;
    for (int j = i; j < jsonLength; j++)
    {
        var c = json[j];
        switch (c)
        {
            case '"':
                isEnd = !isEnd;
                quIndex = j;
                break;
            case ',':
            case ':':
            case '}':
            case ']':
                if (isEnd)
                    j = jsonLength;
                break;
            default:
                if (isEnd && !Char.IsWhiteSpace(c))
                    isEnd = false;
                break;
        }
    }

    return quIndex;
}
Stanislav
  • 459
  • 3
  • 6
  • The collection can take up to 5000 register and I fear that using string replace could not work propely for all cases. – marcelo Nov 13 '20 at 15:29
  • try the code which I added to the answer, You can only call this code when you catch an error – Stanislav Nov 13 '20 at 20:10
  • 1
    Hi @Stanislav! I did try your solution but did not work as expected. I've find out that one reasons that was causing the issue is that string that my solution was receiving had unicode characters that was converted to ascii, so I used "await new StreamReader(req.Body, Encoding.UTF8).ReadToEndAsync()". It worked for some cases, but not all. Some I've came across this answer https://stackoverflow.com/questions/47779157/convertto-json-and-convertfrom-jason-with-special-characters/47779605#47779605. But still not solves the problem of ignoring specifics parts of json. – marcelo Nov 24 '20 at 16:40
  • Hi. I know why some of the data was parsed incorrectly, because I did not rule out the possibility that a comma or other symbols may enter the data between quotation marks. In the new version I fixed this – Stanislav Nov 24 '20 at 17:44
  • Now these cases will be processed correctly {"Value": "Problematic "Other,]} something""} – Stanislav Nov 24 '20 at 17:55
  • 1
    Hi your answer worked! Also, I did not mentioned, but there is a powershell script that pass this body to my method. So I added this "$Body | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii". The option '-EscapeHandling EscapeNonAscii' solve the problem as well. Thanks! – marcelo Nov 27 '20 at 13:50