Como garantir que a string seja JSON válida usando JSON.NET

147

Eu tenho uma string crua. Eu só quero validar se a string é JSON válida ou não. Estou usando o JSON.NET.

user960567
fonte

Respostas:

207

Através do código:

Sua melhor aposta é usar a análise dentro de try-catche capturar uma exceção em caso de falha na análise. (Não conheço nenhum TryParsemétodo) .

(Usando JSON.Net)

A maneira mais simples seria Parsea string usando JToken.Parse, e também para verificar se a string começa com {ou [e termina com }ou ]respectivamente (adicionado a partir desta resposta ) :

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

O motivo para adicionar verificações para {ou [etc foi baseado no fato de que JToken.Parseanalisaria os valores como "1234"ou "'a string'"como um token válido. A outra opção poderia ser usar ambos JObject.Parsee JArray.Parsena análise e ver se algum deles foi bem-sucedido, mas acredito que procurar {}e []deve ser mais fácil. (Obrigado @RhinoDevel por apontar )

Sem JSON.Net

Você pode utilizar o namespace System.Json do .Net framework 4.5 , 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());
}

(Mas você deve instalar System.Jsonatravés do gerenciador de pacotes Nuget usando o comando: PM> Install-Package System.Json -Version 4.0.20126.16343no Package Manager Console) (extraído daqui )

Maneira sem código:

Normalmente, quando há uma pequena string json e você está tentando encontrar um erro na string json, eu pessoalmente prefiro usar as ferramentas on-line disponíveis. O que eu costumo fazer é:

Habib
fonte
3
Como pode fazer isso em tempo de execução. Eu não quero usar try catch para fins de validação
user960567
1
Você pode criar um esquema para o seu JSON e depois verificar com esse esquema, consulte: Json.NET 3.5 Beta 2 - Validação do esquema JSON
Habib
1
Alguma maneira de fazer isso sem um bloco try? Não uso blocos de tentativa, a menos que esteja lidando com um desconhecido. Estou procurando algo como JsonConvert.TryDeserializeObject. As capturas experimentais operacionais são apenas códigos incorretos.
Jordan
1
Usando JSON.Net: Isso não lançar uma exceção: JToken.Parse("1234")! Pode ser uma boa idéia verificar primeiro, se a string começa com [ou {. Outra alternativa é usar JObject.Parse()e JArray.Parse().
RhinoDevel #
1
JToken.Parse("{a:1}")se não lançar exceção, embora este é JSON inválido - adeve ser citado ( stackoverflow.com/q/949449/3116322 )
Ande
31

Use o JContainer.Parse(str)método para verificar se o str é um Json válido. Se isso gera exceção, não é um Json válido.

JObject.Parse- Pode ser usado para verificar se a string é um objeto Json válido
JArray.Parse- Pode ser usado para verificar se a string é um Json Array válido
JContainer.Parse- Pode ser usado para verificar o objeto Json e a Matriz

Senthilkumar Viswanathan
fonte
17
Em vez de JContainer é mais válida para usar tipo JToken desde Parse () método é declarado neste nível
Denis The Menace
6
Suponho que você esteja falando sobre JSON.Net: JContainer não funciona dessa maneira, porque não lançará uma exceção em todos os casos desejados. Exemplo: JContainer.Parse("1234");.
RhinoDevel #
Resposta errada, JContainer.Parse funciona em qualquer coisa
Toolkit
19

Com base na resposta de Habib, você pode escrever um método de extensão:

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

Que pode ser usado assim:

if(stringObject.ValidateJSON())
{
    // Valid JSON!
}
Tom Beech
fonte
1
JToken.Parse(s);retorna truemesmo seJToken.Parse(123);
Faça Makeluv
2
Retornar truepara este inválido JSON:{A:{"B": 1}}
Mehdi Dehghani
Bom método de extensão para ter :) Embora provavelmente seria melhor nomeado como "IsValidJson".
Mladen B.
11

Apenas para adicionar algo à resposta do @ Habib, você também pode verificar se o JSON fornecido é de um 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
fonte
7

Descobri que o JToken.Parse analisa incorretamente o JSON inválido, como o seguinte:

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

Cole a sequência JSON em http://jsonlint.com/ - é inválida.

Então eu 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
fonte
Isso não é uma string JSON inválida ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf aqui está a documentação do JSON Standard ECMA e no ponto 5 JSON Values, você pode ver que um valor pode ser nulo como valor . Então é apenas um bug no interpretador jsonlint
Dominik Lemberger
4
Dominik, um valor JSON de acordo com minha leitura da especificação que você vinculou deve ter algum token válido, com o texto nulo literal representando um valor nulo. Os valores válidos são "um objeto, matriz, número, sequência, verdadeiro, falso ou nulo" de acordo com a especificação que você referenciou. AFAICS não há valor válido sem token de valor.
Kirtlander #
Parece que vai ficar bem com o JSON inválido, que se parece com isso:{ name : "l am invalid JSON" }
Jon49
2

Option️ Opção alternativa que não usa JSON.Net ⚠️

Para .Net Core / .Net 5 ( em pré-visualização até o momento em que este artigo foi escrito ), também é possível usar o System.Text.Jsonespaço para nome e analisar usando o JsonDocument. O exemplo é um método de extensão baseado nas operações do espaço para nome:

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

    return false;
}
ΩmegaMan
fonte
1

Em relação à resposta de Tom Beech; Eu vim com o seguinte:

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

Com o uso do seguinte:

if (ValidateJSON(strMsg))
{
    var newGroup = DeserializeGroup(strMsg);
}
HappyCoding
fonte
3
Isso não é novidade - você criou um método de extensão para não ser um método de extensão. A resposta de Tom Beech já pode alcançar o que você precisa (em geral, eu também desaprovaria adicionar métodos de extensão desse tipo string, mas essa resposta realmente deveria a) não estar aqui ou b) dizer "usei a resposta de Tom Beech " sem o this, isto é, sem torná-lo um membro de extensão) - tanto essa resposta quanto a referência têm brevidade e fraquezas idênticas. Se você precisar fazer isso, basta comentar a outra resposta.
Ruben Bartelink 27/03/19
1

JToken.Typeestá disponível após uma análise bem-sucedida. Isso pode ser usado para eliminar parte do preâmbulo nas respostas acima e fornecer informações para um controle mais preciso do resultado. Entrada totalmente inválida (por exemplo, "{----}".IsValidJson();ainda lançará uma exceção).

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

Referência do Json.Net para JToken.Type: https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Linq_JTokenType.htm

Randy Larson
fonte
0

Este método não requer 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
fonte
0

Aqui está um método de extensão TryParse com base na resposta 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
fonte
0

Eu estou 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
fonte