在序列化之前根据模式验证对象
Validate object against a schema before serialization
我想将 C# 对象序列化为 JSON 到流中,但如果对象根据架构无效则避免序列化。我应该如何使用 JSON.NET 和 Json.NET 模式继续执行此任务?据我所知,JSON.NET 库中没有允许根据 JSON 模式验证 C# 对象的方法。似乎有些奇怪,没有直接的方法来验证 C# 对象而不对其进行编码。您知道为什么此方法不可用吗?
你不能从 JSON 字符串中做到这一点,你首先需要一个对象和一个模式来比较..
public void Validate()
{
//...
JsonSchema schema = JsonSchema.Parse("{'pattern':'lol'}");
JToken stringToken = JToken.FromObject("pie");
stringToken.Validate(schema);
这个 API 目前似乎不可用。猜测可能是因为递归生成 JSON 值以进行验证涉及序列化对象的大部分工作。或者可能只是因为 Newtonsoft ever designed, specified, implemented, tested, documented and shipped that feature 没有人。
如果你愿意,你可以file an enhancement request requesting this API, probably as a part of the SchemaExtensions
class。
与此同时,如果您确实需要测试验证 POCO 而不生成它的完整序列化(因为例如结果会非常大),您可以从 [=20= 中获取 NullJsonWriter
]. 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 架构是 因此您需要在测试验证时使用适当的合同解析器。
示例 fiddle.
我想将 C# 对象序列化为 JSON 到流中,但如果对象根据架构无效则避免序列化。我应该如何使用 JSON.NET 和 Json.NET 模式继续执行此任务?据我所知,JSON.NET 库中没有允许根据 JSON 模式验证 C# 对象的方法。似乎有些奇怪,没有直接的方法来验证 C# 对象而不对其进行编码。您知道为什么此方法不可用吗?
你不能从 JSON 字符串中做到这一点,你首先需要一个对象和一个模式来比较..
public void Validate()
{
//...
JsonSchema schema = JsonSchema.Parse("{'pattern':'lol'}");
JToken stringToken = JToken.FromObject("pie");
stringToken.Validate(schema);
这个 API 目前似乎不可用。猜测可能是因为递归生成 JSON 值以进行验证涉及序列化对象的大部分工作。或者可能只是因为 Newtonsoft ever designed, specified, implemented, tested, documented and shipped that feature 没有人。
如果你愿意,你可以file an enhancement request requesting this API, probably as a part of the SchemaExtensions
class。
与此同时,如果您确实需要测试验证 POCO 而不生成它的完整序列化(因为例如结果会非常大),您可以从 [=20= 中获取 NullJsonWriter
]. 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 架构是
示例 fiddle.