Cómo asegurarse de que la cadena es JSON válida usando JSON.NET

147

Tengo una cuerda cruda. Solo quiero validar si la cadena es JSON válida o no. Estoy usando JSON.NET.

usuario960567
fuente

Respuestas:

207

A través del código:

Su mejor opción es usar el análisis dentro de ay try-catchcapturar una excepción en caso de un análisis fallido. (No conozco ningún TryParsemétodo) .

(Usando JSON.Net)

La forma más simple sería usar Parsela cadena JToken.Parsey también verificar si la cadena comienza con {o [y termina con }o ]respectivamente (agregado de esta respuesta ) :

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

La razón para agregar controles para {o [etc. se basó en el hecho de que JToken.Parseanalizaría los valores como "1234"o "'a string'"como un token válido. La otra opción podría ser usar ambos JObject.Parsey JArray.Parseanalizar y ver si alguno de ellos tiene éxito, pero creo que verificar {}y []debería ser más fácil. (Gracias @RhinoDevel por señalarlo )

Sin JSON.Net

Puede utilizar el espacio de nombres .Net framework 4.5 System.Json , como:

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

(Pero, debe instalar a System.Jsontravés del administrador de paquetes Nuget usando el comando: PM> Install-Package System.Json -Version 4.0.20126.16343en la Consola del Administrador de paquetes) (tomado de aquí )

Manera sin código:

Por lo general, cuando hay una pequeña cadena json y estás tratando de encontrar un error en la cadena json, yo personalmente prefiero usar las herramientas en línea disponibles. Lo que suelo hacer es:

Habib
fuente
3
¿Cómo puede hacer esto en tiempo de ejecución? No quiero usar try catch para fines de validación
user960567
1
Puede crear un esquema para su JSON y luego verificar con ese esquema; consulte: Json.NET 3.5 Beta 2 - Validación del esquema JSON
Habib
1
¿Alguna forma de hacerlo sin un bloque de prueba? No uso bloques de prueba a menos que esté tratando con un desconocido. Estoy buscando algo como JsonConvert. TryDeserializeObject. Las capturas de prueba operativas son simplemente un código incorrecto.
Jordania
1
Usando JSON.Net: Esto no una excepción: JToken.Parse("1234")! Puede ser una buena idea verificar primero, si la cadena comienza con [o {. Otra alternativa es el uso JObject.Parse()y JArray.Parse().
RhinoDevel
1
JToken.Parse("{a:1}")no no lanzar una excepción a pesar de que esto es válido JSON - adebe ser citado ( stackoverflow.com/q/949449/3116322 )
Ande
31

Use el JContainer.Parse(str)método para verificar si el str es un Json válido. Si esto arroja una excepción, entonces no es un Json válido.

JObject.Parse- Se puede usar para verificar si la cadena es un objeto Json válido
JArray.Parse- Se puede usar para verificar si la cadena es una matriz Json válida
JContainer.Parse- Se puede usar para verificar tanto el objeto Json como la matriz

Senthilkumar Viswanathan
fuente
17
En lugar de JContainer, es más válido usar el tipo JToken ya que el método Parse () se declara en este nivel
Denis The Menace
66
Supongo que está hablando de JSON.Net: JContainer no funciona de esa manera, porque no arrojará una excepción en todos los casos deseados. Ejemplo: JContainer.Parse("1234");.
RhinoDevel
Respuesta incorrecta, JContainer.Parse funciona en cualquier cosa
Toolkit
19

Sobre la base de la respuesta de Habib, podría escribir un método de extensión:

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

Que luego se puede usar así:

if(stringObject.ValidateJSON())
{
    // Valid JSON!
}
Tom Beech
fuente
1
JToken.Parse(s);vuelve trueincluso siJToken.Parse(123);
Haz Makeluv el
2
Regrese truepara este inválido JSON:{A:{"B": 1}}
Mehdi Dehghani
Buen método de extensión para tener :) Aunque probablemente sería mejor nombrarlo como "IsValidJson".
Mladen B.
11

Solo para agregar algo a la respuesta de @ Habib, también puede verificar si JSON dado es de un tipo válido:

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
fuente
7

Descubrí que JToken.Parse analiza incorrectamente JSON inválido como el siguiente:

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

Pegue la cadena JSON en http://jsonlint.com/ , no es válida.

Entonces uso:

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
fuente
Esa no es una cadena JSON no válida ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf aquí está la documentación de JSON Standard ECMA y bajo el punto 5 JSON Values ​​puede ver que un valor puede ser nulo como valor . Así que es solo un error en el intérprete jsonlint
Dominik Lemberger
44
Dominik, un valor JSON según mi lectura de la especificación que vinculó debe tener algún token válido, con el texto nulo literal que representa un valor nulo. Los valores válidos son "un objeto, matriz, número, cadena, verdadero, falso o nulo" según la especificación a la que hizo referencia. AFAICS no hay un valor válido sin token de valor.
Kirtlander
Esto parece que va a estar bien con JSON no válida que se parece a esto{ name : "l am invalid JSON" }
Jon49
2

⚠️ Opción alternativa que no usa JSON.Net ⚠️

Para .Net Core / .Net 5 ( en la vista previa al momento de escribir esto ) también se puede usar el System.Text.Jsonespacio de nombres y analizar usando JsonDocument. El ejemplo es un método de extensión basado en las operaciones de espacio de nombres:

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

    return false;
}
ΩmegaMan
fuente
1

Con respecto a la respuesta de Tom Beech; En su lugar, se me ocurrió lo siguiente:

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

Con un uso de lo siguiente:

if (ValidateJSON(strMsg))
{
    var newGroup = DeserializeGroup(strMsg);
}
HappyCoding
fuente
3
Esto no es novedoso: creó un método de extensión que no es un método de extensión. La respuesta de Tom Beech ya puede lograr lo que necesita (en general, también frunciría el ceño al agregar métodos de extensión de este tipo string, pero esta respuesta realmente debería a) no estar aquí o b) decir " Usé la respuesta de Tom Beech " sin el this, es decir, sin convertirlo en un miembro de extensión), tanto esta respuesta como la referenciada tienen una brevedad y debilidad idénticas. Si debe hacer este punto, simplemente ponga un comentario en la otra respuesta.
Ruben Bartelink
1

JToken.Typeestá disponible después de un análisis exitoso. Esto se puede utilizar para eliminar algunos de los preámbulos en las respuestas anteriores y proporcionar información para un control más preciso del resultado. Entrada completamente inválida (por ejemplo, "{----}".IsValidJson();todavía arrojará una excepción).

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

Referencia de Json.Net para JToken.Type: https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Linq_JTokenType.htm

Randy Larson
fuente
0

Este método no requiere bibliotecas externas

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
fuente
0

Aquí hay un método de extensión TryParse basado en la respuesta de Habib:

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

Uso:

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

Estoy usando este:

  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
fuente