c# - 在序列化之前根据模式验证对象

标签 c# .net json json.net jsonschema

我想将 C# 对象作为 JSON 序列化到流中,但如果根据架构该对象无效,则要避免序列化。我应该如何使用 JSON.NET 和 Json.NET Schema 继续执行此任务?据我所知,JSON.NET 库中没有方法允许根据 JSON 模式验证 C# 对象。没有直接方法来验证 C# 对象而不对其进行编码,这似乎有些奇怪。您知道为什么此方法不可用吗?

最佳答案

此 API 目前似乎不可用。据猜测,这可能是因为递归生成要验证的 JSON 值涉及序列化对象的大部分工作。或者这可能只是因为 Newtonsoft 没有人 ever designed, specified, implemented, tested, documented and shipped that feature

如果你愿意,你可以file an enhancement request请求此 API,可能作为 SchemaExtensions class 的一部分.

同时,如果您确实需要测试验证 POCO 而不生成其完整的序列化(因为例如结果会非常大),您可以从 Reference to automatically created objects 获取 NullJsonWriter ,将其包装在 JSchemaValidatingWriter 中并测试序列化您的对象,如 Validate JSON with JSchemaValidatingWriter 中所示。 NullJsonWriter 实际上并不写入任何内容,因此使用它可以消除生成完整序列化(作为 string 或作为 JToken)。

首先,添加以下静态方法:

public static class JsonExtensions
{
    public static bool TestValidate<T>(T obj, JSchema schema, SchemaValidationEventHandler handler = null, JsonSerializerSettings settings = null)
    {
        using (var writer = new NullJsonWriter())
        using (var validatingWriter = new JSchemaValidatingWriter(writer) { Schema = schema })
        {
            int count = 0;
            if (handler != null)
                validatingWriter.ValidationEventHandler += handler;
            validatingWriter.ValidationEventHandler += (o, a) => count++;
            JsonSerializer.CreateDefault(settings).Serialize(validatingWriter, obj);
            return count == 0;
        }
    }
}

// Used to enable Json.NET to traverse an object hierarchy without actually writing any data.
class NullJsonWriter : JsonWriter
{
    public NullJsonWriter()
        : base()
    {
    }

    public override void Flush()
    {
        // Do nothing.
    }
}

然后像这样使用它:

// Example adapted from 
// https://www.newtonsoft.com/jsonschema/help/html/JsonValidatingWriterAndSerializer.htm
// by James Newton-King

string schemaJson = @"{
   'description': 'A person',
   'type': 'object',
   'properties': {
     'name': {'type':'string'},
     'hobbies': {
       'type': 'array',
       'maxItems': 3,
       'items': {'type':'string'}
     }
  }
}";         
var schema = JSchema.Parse(schemaJson);

var person = new
{
    Name = "James",
    Hobbies = new [] { ".Net", "Blogging", "Reading", "XBox", "LOLCATS" },
};

var settings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() };
var isValid = JsonExtensions.TestValidate(person, schema, (o, a) => Console.WriteLine(a.Message), settings);
// Prints Array item count 5 exceeds maximum count of 3. Path 'hobbies'.

Console.WriteLine("isValid = {0}", isValid); 
// Prints isValid = False

顺便提一下,请注意案件。 Json.NET 架构是 case sensitive因此,您在测试验证时需要使用适当的合约解析器。

样本fiddle .

关于c# - 在序列化之前根据模式验证对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47947461/

相关文章:

c# - Char[] 的子序列是否等于字符串的内容?

c# - 如何在 C# 中获取 Citrix 客户端接收器版本号

c# - CIDR 子网是否有原生 .NET 类型?

ruby-on-rails - Rails 从 JSON 数据访问散列中的键

json - 有没有一种简单的方法来托管您可以在 Google Cloud Platform 中读取和更新的 JSON 文档?

java - Bitfinex API 新订单的有效 JSON 是什么?

C# 设计问题

c# - 如果角色包含空格,如何编写 AuthorizeAttribute

c# - 如果配置在字符串中,是否使用 new ChannelFactory<TChannel>(string)?

c# - 列表框仅显示一项