Как убедиться, что строка является допустимой JSON, используя JSON.NET

147

У меня есть сырая строка. Я просто хочу проверить, является ли строка допустимым JSON или нет. Я использую JSON.NET.

user960567
источник

Ответы:

207

Через код:

Лучше всего использовать синтаксический анализ внутри a try-catchи перехватить исключение в случае неудачного анализа. (Я не знаю ни одного TryParseметода) .

(Используя JSON.Net)

Простейшим способом было бы Parseиспользовать строку JToken.Parse, а также проверить, начинается ли строка с {или [и заканчивается ли }или ]соответственно (добавлено из этого ответа ) :

private static bool IsValidJson(string strInput)
{
    if (string.IsNullOrWhiteSpace(stringValue)) { 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.Parseи JArray.Parseпри разборе, и посмотреть, удастся ли кому-нибудь из них, но я считаю, что проверка {}и []должна быть проще. (Спасибо @RhinoDevel за указание на это)

Без JSON.Net

Вы можете использовать пространство имен .Net framework 4.5 System.Json , например:

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

(Но вы должны установить System.Jsonчерез менеджер пакетов Nuget с помощью команды: PM> Install-Package System.Json -Version 4.0.20126.16343на консоли диспетчера пакетов) (взято отсюда )

Не кодовый способ:

Обычно, когда есть небольшая строка json, и вы пытаетесь найти ошибку в строке json, я лично предпочитаю использовать доступные инструменты онлайн. Что я обычно делаю, это:

  • Вставьте строку JSON в JSONLint Валидатор JSON и проверьте, является ли он допустимым JSON.
  • Позже скопируйте правильный JSON на http://json2csharp.com/ и сгенерируйте для него класс шаблона, а затем удалите его сериализацию с помощью JSON.Net.
Хабиб
источник
3
Как можно сделать это во время выполнения. Я не хочу использовать try catch для проверки
user960567
1
Вы можете создать схему для своего JSON, а затем проверить ее по следующей схеме: Json.NET 3.5 Beta 2 - проверка схемы JSON
Хабиб
1
Любой способ сделать это без блока try? Я не использую блоки try, если не имею дело с неизвестным. Я ищу что-то вроде JsonConvert.TryDeserializeObject. Оперативные попытки отлова - просто плохой код.
Иордания,
1
Использование Json.NET: Это не сгенерирует исключение: JToken.Parse("1234")! Хорошей идеей будет сначала проверить, начинается ли строка с [или {. Другой альтернативой является использование JObject.Parse()и JArray.Parse().
RhinoDevel
1
JToken.Parse("{a:1}")никак не кидать исключение , даже если это является недопустимым JSON - aдолжны быть указаны ( stackoverflow.com/q/949449/3116322 )
Ande
31

использование JContainer.Parse(str) метод, чтобы проверить, является ли str действительным Json. Если это вызывает исключение, то это не правильный Json.

JObject.Parse- Может использоваться для проверки, является ли строка допустимым объектом Json
JArray.Parse- Может использоваться для проверки, является ли строка допустимым массивом Json
JContainer.Parse- Может использоваться для проверки как объекта Json, так и массива

Сентилкумар Вишванатан
источник
17
Вместо JContainer более правильно использовать тип JToken, так как на этом уровне объявлен метод Parse ()
Denis The Menace
6
Я предполагаю, что вы говорите о JSON.Net: JContainer не работает таким образом, потому что он не будет генерировать исключение во всех разыскиваемых случаях. Пример: JContainer.Parse("1234");.
RhinoDevel
Неправильный ответ, JContainer.Parse работает на что угодно
Инструментарий
19

Основываясь на ответе Хабиба, вы можете написать метод расширения:

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!
}
Том Бич
источник
1
JToken.Parse(s);возвращается, trueдаже еслиJToken.Parse(123);
Make Makeluv
2
Возвращение trueдля этого недействительного JSON:{A:{"B": 1}}
Мехди Дехгани
Хороший метод расширения, чтобы иметь :) Хотя это, вероятно, лучше назвать как "IsValidJson".
Младен Б.
11

Просто чтобы добавить что-то в ответ @ Habib, вы также можете проверить, является ли данный JSON допустимым типом:

public static bool IsValidJson<T>(this string strInput)
{
    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;
    }
}
Жалал
источник
7

Я обнаружил, что 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 значений вы можете увидеть значение может иметь нулевое значение , как , Так что это просто ошибка в интерпретаторе jsonlint
Доминик Лембергер
4
Доминик, значение JSON в соответствии с моим прочтением спецификации, которую вы связали, должно иметь некоторый действительный токен, с литеральным нулевым текстом, представляющим нулевое значение. Допустимые значения: «объект, массив, число, строка, истина, ложь или ноль» в соответствии со спецификацией, на которую вы ссылались. AFAICS нет допустимого значения без значения токена.
Киртландер
Похоже, что все будет в порядке с недействительным JSON, который выглядит следующим образом{ name : "l am invalid JSON" }
Jon49
2

Option Альтернативный вариант, не использующий JSON.Net ⚠️

Для .Net Core / .Net 5 ( в предварительном просмотре на момент написания этой статьи ) можно также использовать System.Text.Jsonпространство имен и анализировать с помощью JsonDocument. Пример - метод расширения, основанный на операциях пространства имен:

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

    return false;
}
ΩmegaMan
источник
1

Относительно ответа Тома Бича; Вместо этого я придумал следующее:

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);
}
HappyCoding
источник
3
Это не ново - вы сделали метод расширения не методом расширения. Ответ Тома Бича уже может достичь того, что вам нужно (В общем, я бы тоже нахмурился, добавив методы расширения такого рода string, но этот ответ действительно должен либо а) не быть здесь, либо б) сказать: «Я использовал ответ Тома Бича » без this, т.е. без его удлинительного элемента) - и этот ответ и ссылки один имеют одинаковую краткость и слабые стороны. Если вы должны сделать это, просто оставьте комментарий к другому ответу.
Рубен Бартелинк
1

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

Ссылка на Json.Net для JToken.Type: https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Linq_JTokenType.htm

Рэнди Ларсон
источник
0

Этот метод не требует внешних библиотек

using System.Web.Script.Serialization;
bool IsValidJson(string json)
    {
        try {
            var serializer = new JavaScriptSerializer();
            dynamic result = serializer.DeserializeObject(json);
            return true;
        } catch { return false; }
    }
MostafaZ4
источник
0

Вот метод расширения 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
}
jaybro
источник
0

Я использую это:

  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;
     }
  }
Юша Алеауб
источник