【问题标题】:Validating JSON before deserializing into C# object在反序列化为 C# 对象之前验证 JSON
【发布时间】:2014-10-03 21:15:05
【问题描述】:

如果 JSON 中的 JavaScript 对象不会反序列化为我想要的 C# 对象,我如何询问它以提供错误消息来解释输入的问题? (假设JSON格式正确,只是数据无效。)

我的 C# 类:(简体)

public class Dependent
{
    public Dependent()
    {
    }
    public string FirstName { get; set; }
    public DateTime DateOfBirth { get; set; }
}

要反序列化的测试代码:

string dependents = @"[
                            {
                                ""FirstName"": ""Kenneth"",
                                ""DateOfBirth"": ""02-08-2013""
                            },
                            {
                                ""FirstName"": ""Ronald"",
                                ""DateOfBirth"": ""08-07-2011""
                            }
                      ]";

JavaScriptSerializer jss = new JavaScriptSerializer();

List<Dependent> deps = new List<Dependent>();
deps = jss.Deserialize<List<Dependent>>(dependents);

这一切都有效。除非传入非日期作为生日,否则将无法反序列化。

我想提供一条错误消息,例如“家属 2 的出生日期不是有效日期”。或“家属 2 必须未满 18 岁。”

如果 JSON 不会反序列化到我的对象中,我该如何验证它的详细信息?

可能的解决方案:

public class SerializableDependent
{
    public SerializableDependent()
    {
    }
    public string FirstName { get; set; }
    public string DateOfBirth { get; set; }
}

然后我不应该得到任何错误,将所有内容都作为字符串,我可以遍历对象并进行验证。但这似乎是错误的。

【问题讨论】:

  • 异常不能说明问题吗?

标签: c# json serialization javascriptserializer


【解决方案1】:

JavaScriptSerializer 不支持广泛的错误处理。我建议你使用Json.NET library。您可以使用JsonSerializerSettings 对象的Error 事件处理程序来捕获有关问题的更多详细信息。 documentation 中提供了有关使用此成员的信息。

对于上面的代码 sn-p,填充错误消息数组的处理程序可以编写如下:

public class Dependent
{
    public Dependent()
    {
    }
    public string FirstName { get; set; }
    public DateTime? DateOfBirth { get; set; } // Use a nullable object to hold the error value
}

void DeserializeTest()
{
   string dependents = @"[
                            {
                                ""FirstName"": ""Kenneth"",
                                ""DateOfBirth"": ""02-08-2013""
                            },
                            {
                                ""FirstName"": ""Ronald"",
                                ""DateOfBirth"": ""asdf""
                            }
                      ]";

    var messages = new List<string>();

    var settings = new JsonSerializerSettings(){
        Error = (s,e)=>{
            var depObj = e.CurrentObject as Dependent;
            if(depObj != null)
            {
                messages.Add(string.Format("Obj:{0} Message:{1}",depObj.FirstName, e.ErrorContext.Error.Message));
            }
            else 
            {
                messages.Add(e.ErrorContext.Error.Message);
            }
            e.ErrorContext.Handled = true; // Set the datetime to a default value if not Nullable
        }
    };
    var ndeps = JsonConvert.DeserializeObject<Dependent[]>(dependents, settings);
    //ndeps contains the serialized objects, messages contains the errors
}

【讨论】:

  • 我最终将 DateOfBirth 更改为字符串。感觉不对,但是当 DateTime 确实不应该为空时,它也可以为空。但我确实试过了,而且效果很好。谢谢!
【解决方案2】:

您可以使用JSON Schema(Newtonsoft 提供的框架)在C# 中验证JSON。它允许验证JSON 数据。下面是说明它的外观的代码。更多详情可以阅读文章Validating JSON with JSON Schema in C#

     string myschemaJson = @"{
        'description': 'An employee', 'type': 'object',
        'properties':
        {
           'name': {'type':'string'},
           'id': {'type':'string'},
           'company': {'type':'string'},
           'role': {'type':'string'},
           'skill': {'type': 'array',
           'items': {'type':'string'}
        }
     }";

     JsonSchema schema = JsonSchema.Parse(myschemaJson);

     JObject employee = JObject.Parse(@"{
        'name': 'Tapas', 'id': '12345', 'company': 'TCS',
        'role': 'developer',
        'skill': ['.NET', 'JavaScript', 'C#', 'Angular',
        'HTML']
     }");
     bool valid = employee.IsValid(schema);
     // True

     JsonSchema schema1 = JsonSchema.Parse(myschemaJson);

     JObject employee1 = JObject.Parse(@"{
        'name': null, 'id': '12345', 'company': 'TCS',
        'role': 'developer',
        'skill': ['.NET', 'JavaScript', 'C#', 'Angular',
        'HTML']
     }");

     IList<string> messages;
     bool valid1 = employee1.IsValid(schema1, out messages);
     // False
     // "Invalid type. Expected String but got Null. Line 2,
     // position 24."


     JsonSchema schema2 = new JsonSchema();
     schema2.Type = JsonSchemaType.Object;
     schema2.Properties = new Dictionary<string, JsonSchema>
     {
        { "name", new JsonSchema
           { Type = JsonSchemaType.String } },
        { "id", new JsonSchema
           { Type = JsonSchemaType.String } },
        { "company", new JsonSchema
           { Type = JsonSchemaType.String } },
        { "role", new JsonSchema
           { Type = JsonSchemaType.String } },
        {
           "skill", new JsonSchema
           {
              Type = JsonSchemaType.Array,
              Items = new List<JsonSchema>
                 { new JsonSchema
                    { Type = JsonSchemaType.String } }
           }
        },
     };

     JObject employee2 = JObject.Parse(@"{
        'name': 'Tapas', 'id': '12345',
        'company': 'TCS', 'role': 'developer',
        'skill': ['.NET', 'JavaScript', 'C#', 'Angular',
        'HTML']
     }");
     bool valid2 = employee2.IsValid(schema2);
     // True

【讨论】:

  • 这个库不是免费的,每小时超过 1000 个电话 : The free-quota limit of 1000 schema validations per hour has been reached. Please visit http://www.newtonsoft.com/jsonschema to upgrade to a commercial license.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-09
  • 2021-07-15
  • 1970-01-01
  • 2015-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多