【问题标题】:Ignore raised exceptions on jObject ReadJson on c# Custom Converter忽略 c# Custom Converter 上 jObject ReadJson 引发的异常
【发布时间】:2021-02-25 10:57:36
【问题描述】:

我在尝试反序列化某些 json 时遇到了一些麻烦,因为它带有来自服务器的非转义双引号。由于我无权在服务器端修复此问题,因此我试图忽略有问题的 json。为此,我遵循了这些答案https://stackoverflow.com/a/21542099/2779990Ignore parsing errors during JSON.NET data parsing。当我使用errorArgs.ErrorContext.Handled = true; 时,响应对象是null

所以我实现了自己的转换器:

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();
        }
    }

我的 json 看起来像这样:

[
 {
   "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""
      }
   ]
 }
]

我的域对象如下所示:

    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;
        }
    }

我什至还尝试将其添加到有问题的对象中:

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

问题是即使使用 try catch 块来捕获 JObject jObject = JObject.Load(reader); 上的任何异常,这也不能阻止 JsonConvert.DeserializeObject&lt;IEnumerable&lt;T&gt;&gt;(document, settings); 抛出异常。可以在ReadJson 方法中执行类似于errorArgs.ErrorContext.Handled = true; 的操作吗?

【问题讨论】:

    标签: c# json json.net deserialization


    【解决方案1】:

    为什么不直接去掉双引号呢? Json 很大吗?

    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;
    }
    

    【讨论】:

    • 该集合最多可以占用 5000 个寄存器,我担心使用字符串替换无法在所有情况下都正常工作。
    • 试试我添加到答案中的代码,你只能在遇到错误时调用此代码
    • 嗨@Stanislav!我确实尝试了您的解决方案,但没有按预期工作。我发现导致问题的一个原因是我的解决方案接收的字符串具有转换为 ascii 的 unicode 字符,因此我使用了“await new StreamReader(req.Body, Encoding.UTF8).ReadToEndAsync() ”。它适用于某些情况,但不是全部。有些我遇到了这个答案stackoverflow.com/questions/47779157/…。但仍然没有解决忽略json具体部分的问题。
    • 嗨。我知道为什么有些数据解析不正确,因为我不排除逗号或其他符号可能会在引号之间输入数据的可能性。在新版本中我修复了这个
    • 您好,您的回答有效!另外,我没有提到,但是有一个 powershell 脚本可以将此主体传递给我的方法。所以我添加了这个“$Body | ConvertTo-Json -Depth 100 -EscapeHandling EscapeNonAscii”。选项“-EscapeHandling EscapeNonAscii”也解决了这个问题。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-26
    • 2022-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多