一尘不染

以“ TryParse”方式反序列化json

json

当我向服务(我不拥有)发送请求时,它可能会以请求的JSON数据或看起来像这样的错误进行响应:

{
    "error": {
        "status": "error message",
        "code": "999"
    }
}

在这两种情况下,HTTP响应代码均为200 OK,因此我不能用它来确定是否存在错误-我必须反序列化响应以进行检查。所以我有这样的东西:

bool TryParseResponseToError(string jsonResponse, out Error error)
{
    // Check expected error keywords presence
    // before try clause to avoid catch performance drawbacks
    if (jsonResponse.Contains("error") &&
        jsonResponse.Contains("status") &&
        jsonResponse.Contains("code"))
    {
        try
        {
            error = new JsonSerializer<Error>().DeserializeFromString(jsonResponse);
            return true;
        }
        catch
        {
            // The JSON response seemed to be an error, but failed to deserialize.
            // Or, it may be a successful JSON response: do nothing.
        }
    }

    error = null;
    return false;
}

在这里,我有一个空的catch子句,该子句可能在标准执行路径中,这是一种难闻的气味……嗯,不仅仅是难闻的气味:它发臭。

您是否知道 “ TryParse” 响应的更好方法,以 避免 在标准执行路径中出现问题?

[编辑]

感谢Yuval Itzchakov的回答,我改进了这样的方法:

bool TryParseResponse(string jsonResponse, out Error error)
{
    // Check expected error keywords presence :
    if (!jsonResponse.Contains("error") ||
        !jsonResponse.Contains("status") ||
        !jsonResponse.Contains("code"))
    {
        error = null;
        return false;
    }

    // Check json schema :
    const string errorJsonSchema =
        @"{
              'type': 'object',
              'properties': {
                  'error': {'type':'object'},
                  'status': {'type': 'string'},
                  'code': {'type': 'string'}
              },
              'additionalProperties': false
          }";
    JsonSchema schema = JsonSchema.Parse(errorJsonSchema);
    JObject jsonObject = JObject.Parse(jsonResponse);
    if (!jsonObject.IsValid(schema))
    {
        error = null;
        return false;
    }

    // Try to deserialize :
    try
    {
        error = new JsonSerializer<Error>.DeserializeFromString(jsonResponse);
        return true;
    }
    catch
    {
        // The JSON response seemed to be an error, but failed to deserialize.
        // This case should not occur...
        error = null;
        return false;
    }
}

我保留了catch子句…以防万一。


阅读 406

收藏
2020-07-27

共1个答案

一尘不染

有了Json.NET您,您可以针对架构验证json:

 string schemaJson = @"{
 'status': {'type': 'string'},
 'error': {'type': 'string'},
 'code': {'type': 'string'}
}";

JsonSchema schema = JsonSchema.Parse(schemaJson);

JObject jobj = JObject.Parse(yourJsonHere);
if (jobj.IsValid(schema))
{
    // Do stuff
}

然后在TryParse方法中使用它。

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

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

然后做:

var myType = myJsonString.TryParseJson<AwsomeType>(schema);

更新:

请注意,架构验证不再是Newtonsoft.Json主程序包的一部分,您需要添加Newtonsoft.Json.Schema程序包。

更新2:

如评论中所述,“ JSONSchema”具有定价模型,这意味着 它不是免费的
。您可以在这里找到所有信息

2020-07-27