为什么 JObject 不转换 JSON 字符串?

Why isn't JObject converting the JSON string?

我不知道我这样做是否正确,但我有以下 class 来尝试验证和解析 JSON:

public static class JsonHelper
{
    internal const string UserResetDataScheme = @"{
      'title' : 'UserResetDataModel',
      'type' : 'object',
      'properties': {
        'Role' : {'type' : 'integer'},
        'Email' : {'type' : 'string'},
      },
      required: [ 'Role', 'Email']
    }";

    internal static T TryParseJson<T>(this string json, string schema) where T : new()
    {
        var parsedSchema = JSchema.Parse(schema);
        var jObject = JObject.Parse(json);

        return jObject.IsValid(parsedSchema) ? JsonConvert.DeserializeObject<T>(json) : default(T);
    }
}

大多数时候架构检查工作正常,但有时我需要像这样反序列化字符串:

"\"User sent null or empty data\""

在这种情况下,模式验证应该 return 为假。但是,当我调用 JObject.Parse 时出现错误:

Newtonsoft.Json.JsonReaderException: 'Error reading JObject from JsonReader. Current JsonReader item is not an object: String. Path '',

我正在使用上面显示的架构。

如果我没理解错,我不能解析成字符串?但是在这种情况下我该怎么办?如果无法解析 JSON,我该如何验证它是否正确?

(符合此架构的JSON 正确解析。)

您遇到错误,因为 "\"User sent null or empty data\"" 不是 JSON 对象,因此 JObject.Parse 无法解析它。相反,您应该使用 JToken.Parse. This method can handle any kind of JSON -- objects, arrays and simple values. The IsValid 扩展方法被定义为在 JToken 上工作,因此它应该仍然可以正常工作。

顺便说一句,当 JToken 验证成功时,您不需要使用 JsonConvert.DeserializeObject<T>() 再次反序列化 JSON。您可以使用 JToken.ToObject<T>() 直接将令牌转换为您的对象。

换句话说,更改此代码:

var jObject = JObject.Parse(json);
return jObject.IsValid(parsedSchema) ? JsonConvert.DeserializeObject<T>(json) : default(T);

为此:

var jToken = JToken.Parse(json);
return jToken.IsValid(parsedSchema) ? jToken.ToObject<T>() : default(T);

为了更加安全,您可以在解析周围放置一个 try/catch 块。这样,如果您得到的字符串甚至根本不是 JSON,您也可以处理它。那么你将有:

internal static T TryParseJson<T>(this string json, string schema) where T : new()
{
    var parsedSchema = JSchema.Parse(schema);
    try
    {
        var jToken = JToken.Parse(json);
        return jToken.IsValid(parsedSchema) ? jToken.ToObject<T>() : default(T);
    }
    catch (JsonException ex)
    {
        // optionally log the exception here
        return default(T);
    }
}