【问题标题】:How to make sure that string is valid JSON using JSON.NET如何使用 JSON.NET 确保字符串是有效的 JSON
【发布时间】:2013-02-05 08:03:53
【问题描述】:

我有一个原始字符串。我只想验证字符串是否是有效的 JSON。我正在使用 JSON.NET。

【问题讨论】:

    标签: c# json.net


    【解决方案1】:

    通过代码:

    最好的办法是在 try-catch 中使用 parse 并在解析失败的情况下捕获异常。 (我不知道有任何TryParse 方法)

    (使用 JSON.Net)

    最简单的方法是使用JToken.ParseParse 字符串,并检查字符串是否以{[ 开头并分别以}] 结尾(添加来自answer):

    private static bool IsValidJson(string strInput)
    {
        if (string.IsNullOrWhiteSpace(strInput)) { return false;}
        strInput = strInput.Trim();
        if ((strInput.StartsWith("{") && strInput.EndsWith("}")) || //For object
            (strInput.StartsWith("[") && strInput.EndsWith("]"))) //For array
        {
            try
            {
                var obj = JToken.Parse(strInput);
                return true;
            }
            catch (JsonReaderException jex)
            {
                //Exception in parsing json
                Console.WriteLine(jex.Message);
                return false;
            }
            catch (Exception ex) //some other exception
            {
                Console.WriteLine(ex.ToString());
                return false;
            }
        }
        else
        {
            return false;
        }
    }
    

    添加{[ 等检查的原因是基于JToken.Parse 会将"1234""'a string'" 等值解析为有效令牌的事实。另一种选择可能是同时使用JObject.ParseJArray.Parse 进行解析并查看其中是否有人成功,但我相信检查{}[] 应该更容易。 (谢谢@RhinoDevel for pointing 出来)

    没有 JSON.Net

    您可以使用 .Net framework 4.5 System.Json namespace ,例如:

    string jsonString = "someString";
    try
    {
        var tmpObj = JsonValue.Parse(jsonString);
    }
    catch (FormatException fex)
    {
        //Invalid json format
        Console.WriteLine(fex);
    }
    catch (Exception ex) //some other exception
    {
        Console.WriteLine(ex.ToString());
    }
    

    (但是,你必须通过 Nuget 包管理器安装 System.Json,在包管理器控制台上使用命令:PM> Install-Package System.Json -Version 4.0.20126.16343(取自 here

    非编码方式:

    通常,当有一个小的 json 字符串并且您试图在 json 字符串中查找错误时,我个人更喜欢使用可用的在线工具。我通常做的是:

    【讨论】:

    • 如何在运行时做到这一点。我不想使用 try catch 进行验证
    • 您可以为您的 JSON 创建一个模式,然后根据该模式进行验证,请参阅:Json.NET 3.5 Beta 2 – JSON schema validation
    • 没有try块有什么办法吗?除非我处理未知数,否则我不会使用 try 块。我正在寻找类似 JsonConvert.TryDeserializeObject 的东西。可操作的 try catch 只是普通的错误代码。
    • 使用 JSON.Net:不会抛出异常:JToken.Parse("1234")!如果字符串以[{ 开头,最好先检查一下。另一种选择是使用JObject.Parse()JArray.Parse()
    • JToken.Parse("{a:1}") not 会抛出异常,即使这是无效的 JSON - a 应该被引用 (stackoverflow.com/q/949449/3116322)
    【解决方案2】:

    使用JContainer.Parse(str) 方法来检查str是否是一个有效的Json。如果这抛出异常,那么它不是一个有效的 Json。

    JObject.Parse - 可用于检查字符串是否为有效的 Json 对象
    JArray.Parse - 可用于检查字符串是否为有效的 Json 数组
    JContainer.Parse - 可用于检查 Json 对象和数组

    【讨论】:

    • 使用 JToken 类型而不是 JContainer 更有效,因为 Parse() 方法是在这个级别声明的
    • 我假设您在谈论 JSON.Net:JContainer 不是那样工作,因为它不会在所有需要的情况下抛出异常。示例:JContainer.Parse("1234");.
    • 1234 是有效的 JSON。某些特定来源可能需要用花括号括起来的完整键值“字典”,但在一般情况下,原语也可以。
    【解决方案3】:

    基于 Habib 的回答,您可以编写一个扩展方法:

    public static bool ValidateJSON(this string s)
    {
        try
        {
            JToken.Parse(s);
            return true;
        }
        catch (JsonReaderException ex)
        {
            Trace.WriteLine(ex);
            return false;
        }
    }
    

    然后可以这样使用:

    if(stringObject.ValidateJSON())
    {
        // Valid JSON!
    }
    

    【讨论】:

    • JToken.Parse(s); 返回true 即使JToken.Parse(123);
    • 为这个无效的JSON返回true{A:{"B": 1}}
    • 不错的扩展方法 :) 虽然它可能会更好地命名为“IsValidJson”。
    • 123 是有效的 JSON。它不必是完整的键值对象。
    • 请注意,这并不能完全检查更复杂 JSON 对象的完整性!
    【解决方案4】:

    只是为了在@Habib 的答案中添加一些内容,您还可以检查给定的 JSON 是否来自有效类型:

    public static bool IsValidJson<T>(this string strInput)
    {
        if(string.IsNullOrWhiteSpace(strInput)) return false;
    
        strInput = strInput.Trim();
        if ((strInput.StartsWith("{") && strInput.EndsWith("}")) || //For object
            (strInput.StartsWith("[") && strInput.EndsWith("]"))) //For array
        {
            try
            {
                var obj = JsonConvert.DeserializeObject<T>(strInput);
                return true;
            }
            catch // not valid
            {             
                return false;
            }
        }
        else
        {
            return false;
        }
    }
    

    【讨论】:

    • 我建议添加 if "strInput != null && ..." 因为 StartsWith 和 "EndsWith 会触发 ArgumentNullException。
    【解决方案5】:

    我发现 JToken.Parse 错误地解析了无效的 JSON,如下所示:

    {
    "Id" : , 
    "Status" : 2
    }
    

    将 JSON 字符串粘贴到 http://jsonlint.com/ - 无效。

    所以我使用:

    public static bool IsValidJson(this string input)
    {
        input = input.Trim();
        if ((input.StartsWith("{") && input.EndsWith("}")) || //For object
            (input.StartsWith("[") && input.EndsWith("]"))) //For array
        {
            try
            {
                //parse the input into a JObject
                var jObject = JObject.Parse(input);
    
                foreach(var jo in jObject)
                {
                    string name = jo.Key;
                    JToken value = jo.Value;
    
                    //if the element has a missing value, it will be Undefined - this is invalid
                    if (value.Type == JTokenType.Undefined)
                    {
                        return false;
                    }
                }
            }
            catch (JsonReaderException jex)
            {
                //Exception in parsing json
                Console.WriteLine(jex.Message);
                return false;
            }
            catch (Exception ex) //some other exception
            {
                Console.WriteLine(ex.ToString());
                return false;
            }
        }
        else
        {
            return false;
        }
    
        return true;
    }
    

    【讨论】:

    • 这不是无效的 JSON 字符串 ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf 这是 JSON 标准 ECMA 的文档,在第 5 点 JSON 值下,您可以看到一个值可以将 null 作为值。所以它只是 jsonlint 解释器中的一个错误
    • Dominik,根据我对您链接的规范的阅读,JSON 值必须具有一些有效的标记,文字空文本表示空值。根据您引用的规范,有效值为“对象、数组、数字、字符串、true、false 或 null”。 AFAICS 没有没有价值标记的有效价值。
    • 这看起来像这样{ name : "l am invalid JSON" }
    【解决方案6】:

    ⚠️使用System.Text.Json的替代选项⚠️

    对于.Net Core,也可以使用System.Text.Json 命名空间并使用JsonDocument 进行解析。示例是基于命名空间操作的扩展方法:

    public static bool IsJsonValid(this string txt)
    {
        try { return JsonDocument.Parse(txt) != null; } catch {}
    
        return false;
    }
    

    【讨论】:

    • JsonDocument 是一次性的。根据文档,不这样做会result in the memory not being returned to the (memory) pool, which will increase GC impact across various parts of the framework.。所以你需要在某处添加一个using
    • 诚然,很高兴知道,但相关文档从未被分配,因此没有 held 对其的引用,并且 GC 可能不会在方法已经完成,但是当系统决定它需要内存时,它会被懒惰地收集。话虽如此,如果使用此方法会遇到非常大的 json 项或其中许多项......那么将此 example 放入带有 using 的 dispose 模式将是一个好主意。
    • 在验证业务规则时抛出异常,就像检查 JSON 字符串一样司空见惯,这是对应用程序整体性能的不可接受的无视。从计算上讲,异常是昂贵的。
    • @SilvairL.Soares 我完全同意你的说法。幸运的是,每个会话的每个数据集只会执行一次此调用。如果有更好的方法......我希望有人在这里介绍它。 :-/
    【解决方案7】:

    关于汤姆·比奇的回答;我想出了以下内容:

    public bool ValidateJSON(string s)
    {
        try
        {
            JToken.Parse(s);
            return true;
        }
        catch (JsonReaderException ex)
        {
            Trace.WriteLine(ex);
            return false;
        }
    }
    

    使用以下内容:

    if (ValidateJSON(strMsg))
    {
        var newGroup = DeserializeGroup(strMsg);
    }
    

    【讨论】:

    • 这并不新奇——你让扩展方法不是扩展方法。 Tom Beech 的答案已经可以满足您的需要(一般来说,我也不赞成在string 上添加这种扩展方法,但这个答案真的应该要么a)不在这里,要么b)说“我用过@987654321 @" 没有this,即没有使其成为扩展成员) - 这个答案和引用的答案都具有相同的简洁性和弱点。如果您必须说明这一点,只需对其他答案发表评论即可。
    【解决方案8】:

    JToken.Type 在成功解析后可用。这可用于消除上述答案中的一些前言,并为更好地控制结果提供洞察力。完全无效的输入(例如,"{----}".IsValidJson(); 仍会引发异常)。

        public static bool IsValidJson(this string src)
        {
            try
            {
                var asToken = JToken.Parse(src);
                return asToken.Type == JTokenType.Object || asToken.Type == JTokenType.Array;
            }
            catch (Exception)  // Typically a JsonReaderException exception if you want to specify.
            {
                return false;
            }
        }
    

    JToken.Type 的 Json.Net 参考:https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Linq_JTokenType.htm

    【讨论】:

      【解决方案9】:

      此方法不需要外部库

      using System.Web.Script.Serialization;
      bool IsValidJson(string json)
          {
              try {
                  var serializer = new JavaScriptSerializer();
                  dynamic result = serializer.DeserializeObject(json);
                  return true;
              } catch { return false; }
          }
      

      【讨论】:

        【解决方案10】:

        这是一个基于 Habib 回答的 TryParse 扩展方法:

        public static bool TryParse(this string strInput, out JToken output)
        {
            if (String.IsNullOrWhiteSpace(strInput))
            {
                output = null;
                return false;
            }
            strInput = strInput.Trim();
            if ((strInput.StartsWith("{") && strInput.EndsWith("}")) || //For object
                (strInput.StartsWith("[") && strInput.EndsWith("]"))) //For array
            {
                try
                {
                    output = JToken.Parse(strInput);
                    return true;
                }
                catch (JsonReaderException jex)
                {
                    //Exception in parsing json
                    //optional: LogError(jex);
                    output = null;
                    return false;
                }
                catch (Exception ex) //some other exception
                {
                    //optional: LogError(ex);
                    output = null;
                    return false;
                }
            }
            else
            {
                output = null;
                return false;
            }
        }
        

        用法:

        JToken jToken;
        if (strJson.TryParse(out jToken))
        {
            // work with jToken
        }
        else
        {
            // not valid json
        }
        

        【讨论】:

          【解决方案11】:

          我正在使用这个:

            internal static bool IsValidJson(string data)
            {
               data = data.Trim();
               try
               {
                  if (data.StartsWith("{") && data.EndsWith("}"))
                  {
                     JToken.Parse(data);
                  }
                  else if (data.StartsWith("[") && data.EndsWith("]"))
                  {
                     JArray.Parse(data);
                  }
                  else
                  {
                     return false;
                  }
                  return true;
               }
               catch
               {
                  return false;
               }
            }
          

          【讨论】:

            【解决方案12】:

            即使返回异常也返回json字符串的扩展:

            公共静态字符串 OnlyValidJson(此字符串 strInput) { if (string.IsNullOrWhiteSpace(strInput)) { return @"[""Json 为空""]"; } strInput = strInput.Trim(); if ((strInput.StartsWith("{") && strInput.EndsWith("}")) || (strInput.StartsWith("[") && strInput.EndsWith("]"))) { 尝试 { 字符串 strEscape = strInput.Replace("\\n", "").Replace("\\r", "").Replace("\n", "").Replace("\r", "") ; JToken.Parse(strEscape); 返回strEscape; } 捕捉(JsonReaderException jex) { 返回@$"{{""JsonReaderException"":""{jex.Message}""}}"; } 捕捉(例外前) { Console.WriteLine(ex.ToString()); 返回@$"{{""异常"":""{ex.ToString()}""}}"; } } 别的 { return @"[""Json 不以 { 或 [.""]" 开头; } }

            【讨论】:

            • 这如何回答这个问题?
            猜你喜欢
            • 1970-01-01
            • 2011-09-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-02-13
            相关资源
            最近更新 更多