Jak upewnić się, że ciąg jest prawidłowym kodem JSON przy użyciu JSON.NET

147

Mam surowy sznurek. Chcę tylko sprawdzić, czy ciąg jest prawidłowym JSON, czy nie. Używam JSON.NET.

user960567
źródło

Odpowiedzi:

207

Poprzez kod:

Najlepszym rozwiązaniem jest użycie parsowania wewnątrz try-catchwyjątku i catch w przypadku niepowodzenia parsowania. (Nie znam żadnej TryParsemetody) .

(Przy użyciu JSON.Net)

Najprostszym sposobem byłoby Parseużycie łańcucha JToken.Parse, a także sprawdzenie, czy ciąg zaczyna się od {lub [i kończy odpowiednio na }lub (dodane z tej odpowiedzi ) :]

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

Powodem dodania czeków dla {lub [itp. Był fakt, JToken.Parseże przeanalizowałoby wartości, takie jak "1234"lub "'a string'"jako prawidłowy token. Inną opcją może być użycie obu JObject.Parsei JArray.Parsepodczas analizowania i sprawdzenie, czy komuś się powiedzie, ale uważam, że sprawdzanie {}i []powinno być łatwiejsze. (Dzięki @RhinoDevel za wskazanie tego)

Bez JSON.Net

Możesz wykorzystać przestrzeń nazw System.Json .Net framework 4.5 , na przykład:

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

(Ale musisz zainstalować System.Jsonprzez menedżera pakietów Nuget za pomocą polecenia: PM> Install-Package System.Json -Version 4.0.20126.16343w konsoli Menedżera pakietów) (pobrane stąd )

Sposób niekodowany:

Zwykle, gdy występuje mały ciąg json i próbujesz znaleźć błąd w łańcuchu json, wtedy osobiście wolę użyć dostępnych narzędzi on-line. Zwykle robię:

Habib
źródło
3
Jak można to zrobić w czasie wykonywania. Nie chcę używać try catch do walidacji
user960567
1
Możesz utworzyć schemat dla swojego formatu
Habib,
1
Jakikolwiek sposób na zrobienie tego bez bloku try? Nie używam bloków try, chyba że mam do czynienia z nieznanym. Szukam czegoś takiego jak JsonConvert.TryDeserializeObject. Operacyjne próby przechwytywania to po prostu zły kod.
Jordan,
1
Korzystanie Json.NET: To jest nie wyjątek: JToken.Parse("1234")! Warto najpierw sprawdzić, czy ciąg znaków zaczyna się od [lub {. Inną alternatywą jest użycie JObject.Parse()i JArray.Parse().
RhinoDevel,
1
JToken.Parse("{a:1}")czy nie rzucić wyjątek chociaż jest nieprawidłowy JSON - apowinny być cytowane ( stackoverflow.com/q/949449/3116322 )
Ande
31

Użyj JContainer.Parse(str)metody, aby sprawdzić, czy str jest prawidłowym plikiem Json. Jeśli zgłasza wyjątek, nie jest to poprawna Json.

JObject.Parse- Może być użyty do sprawdzenia, czy ciąg jest prawidłowym obiektem Json
JArray.Parse- Może być użyty do sprawdzenia, czy ciąg jest prawidłową tablicą Json
JContainer.Parse- Może być użyty do sprawdzenia zarówno obiektu Json, jak i tablicy

Senthilkumar Viswanathan
źródło
17
Zamiast JContainer bardziej poprawne jest użycie typu JToken, ponieważ metoda Parse () jest zadeklarowana na tym poziomie
Denis The Menace
6
Zakładam, że mówisz o JSON.Net: JContainer nie działa w ten sposób, ponieważ nie zgłosi wyjątku we wszystkich poszukiwanych przypadkach. Przykład: JContainer.Parse("1234");.
RhinoDevel,
Zła odpowiedź, JContainer.Parse działa na wszystkim
Toolkit
19

Opierając się na odpowiedzi Habiba, możesz napisać metodę rozszerzającą:

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

Które można następnie wykorzystać w następujący sposób:

if(stringObject.ValidateJSON())
{
    // Valid JSON!
}
Tom Beech
źródło
1
JToken.Parse(s);zwraca, truenawet jeśliJToken.Parse(123);
Make Makeluv
2
Zwróć trueza to nieważne JSON:{A:{"B": 1}}
Mehdi Dehghani
Niezła metoda rozszerzenia :) Chociaż prawdopodobnie lepiej byłoby nazwać ją „IsValidJson”.
Mladen B.
11

Aby dodać coś do odpowiedzi @ Habib, możesz również sprawdzić, czy podany JSON pochodzi z prawidłowego typu:

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;
    }
}
Jalal
źródło
7

Okazało się, że JToken.Parse niepoprawnie analizuje nieprawidłowy kod JSON, na przykład:

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

Wklej ciąg JSON do http://jsonlint.com/ - jest nieprawidłowy.

Więc używam:

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;
}
Andrew Roberts
źródło
To nie jest nieprawidłowy ciąg JSON ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf tutaj jest dokumentacja standardu JSON ECMA i w punkcie 5 Wartości JSON można zobaczyć, że wartość może przyjmować wartość null jako wartość . Więc to tylko błąd w tłumaczu jsonlint
Dominik Lemberger
4
Dominik, wartość JSON zgodnie z moim odczytaniem specyfikacji, którą połączyłeś, musi mieć jakiś ważny token, z literalnym tekstem null reprezentującym wartość null. Prawidłowe wartości to „obiekt, tablica, liczba, ciąg, prawda, fałsz lub null” zgodnie ze specyfikacją, do której się odwołujesz. AFAICS, nie ma prawidłowej wartości bez tokenu wartości.
Kirtlander
Wygląda na to, że będzie dobrze z nieprawidłowym JSON, który wygląda tak{ name : "l am invalid JSON" }
Jon49
2

⚠️ Alternatywna opcja bez użycia JSON.Net ⚠️

W przypadku .Net Core / .Net 5 ( w wersji zapoznawczej w chwili pisania tego tekstu ) można również użyć System.Text.Jsonprzestrzeni nazw i przeanalizować za pomocą JsonDocument. Przykład to metoda rozszerzenia oparta na operacjach w przestrzeni nazw:

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

    return false;
}
ΩmegaMan
źródło
1

Odnośnie odpowiedzi Toma Beecha; Zamiast tego wymyśliłem:

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

Korzystając z:

if (ValidateJSON(strMsg))
{
    var newGroup = DeserializeGroup(strMsg);
}
HappyCoding
źródło
3
To nie jest nowość - stworzyłeś metodę rozszerzającą, a nie metodą rozszerzającą. Odpowiedź Toma Beecha może już osiągnąć to, czego potrzebujesz (ogólnie rzecz biorąc, nie chciałbym również dodawać tego typu rozszerzeń string, ale ta odpowiedź naprawdę powinna albo a) nie być tutaj lub b) powiedzieć „Użyłem odpowiedzi Toma Beecha ” bez the this, czyli bez robienia z niej elementu rozszerzenia) - zarówno ta odpowiedź, jak i ta, do której się odwołujemy, mają identyczną zwięzłość i słabości. Jeśli musisz to zaznaczyć, po prostu dodaj komentarz do drugiej odpowiedzi.
Ruben Bartelink
1

JToken.Typejest dostępny po pomyślnym przeanalizowaniu. Można to wykorzystać do wyeliminowania części preambuły z powyższych odpowiedzi i zapewnienia wglądu w lepszą kontrolę wyniku. Całkowicie nieprawidłowe dane wejściowe (np. "{----}".IsValidJson();Nadal będzie zgłaszać wyjątek).

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

Dokumentacja Json.Net dla JToken.Type: https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Linq_JTokenType.htm

Randy Larson
źródło
0

Ta metoda nie wymaga bibliotek zewnętrznych

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
źródło
0

Oto metoda rozszerzenia TryParse oparta na odpowiedzi Habiba:

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

Stosowanie:

JToken jToken;
if (strJson.TryParse(out jToken))
{
    // work with jToken
}
else
{
    // not valid json
}
jaybro
źródło
0

Używam tego:

  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;
     }
  }
Yousha Aleayoub
źródło