LateApexEarlySpeed.Json.Schema
1.0.9
See the version list below for details.
dotnet add package LateApexEarlySpeed.Json.Schema --version 1.0.9
NuGet\Install-Package LateApexEarlySpeed.Json.Schema -Version 1.0.9
<PackageReference Include="LateApexEarlySpeed.Json.Schema" Version="1.0.9" />
paket add LateApexEarlySpeed.Json.Schema --version 1.0.9
#r "nuget: LateApexEarlySpeed.Json.Schema, 1.0.9"
// Install LateApexEarlySpeed.Json.Schema as a Cake Addin #addin nuget:?package=LateApexEarlySpeed.Json.Schema&version=1.0.9 // Install LateApexEarlySpeed.Json.Schema as a Cake Tool #tool nuget:?package=LateApexEarlySpeed.Json.Schema&version=1.0.9
Lateapexearlyspeed.Json.Schema
This is a high performance Json schema .Net implementation library based on Json schema - draft 2020.12 (latest one by 2023.12).
This library also supports validator generation from your .net class code.
The json validation functionalities have passed official json schema test-suite for draft 2020.12 (except cases about limitation listed below)
High performance - this .Net library has good performance compared with existing more popular and excellent .Net implementations in common cases by BenchmarkDotnet result, but please verify in your use cases.
Some Benchmark result:
12th Gen Intel Core i7-12800H, 1 CPU, 20 logical and 14 physical cores
[Host] : .NET 6.0.25 (6.0.2523.51912), X64 RyuJIT AVX2
DefaultJob : .NET 6.0.25 (6.0.2523.51912), X64 RyuJIT AVX2
Valid data case: | Method | Mean | Error | StdDev | Gen0 | Gen1 | Allocated | |----------------------------------- |------------:|----------:|----------:|--------:|-------:|----------:| | ValidateByPopularSTJBasedValidator | 29.80 us | 0.584 us | 0.573 us | 4.4556 | 0.2441 | 55.1 KB | | ValidateByThisValidator | 15.99 us | 0.305 us | 0.300 us | 1.9531 | - | 24.2 KB |
Invalid data case: | Method | Mean | Error | StdDev | Median | Gen0 | Gen1 | Allocated | |----------------------------------- |------------:|----------:|-----------:|------------:|--------:|-------:|----------:| | ValidateByPopularSTJBasedValidator | 65.04 us | 2.530 us | 7.341 us | 66.87 us | 4.5776 | 0.1221 | 56.42 KB | | ValidateByThisValidator | 15.47 us | 1.160 us | 3.421 us | 17.14 us | 1.4954 | - | 18.45 KB |
Note: "STJ" means "System.Text.Json" which is built-in json package in .net sdk, this library is also based on it.
Benchmark Schema:
{
"$id": "http://main",
"type": "object",
"additionalProperties": false,
"patternProperties": {
"propB*lean": {
"type": "boolean"
}
},
"dependentRequired": {
"propNull": [ "propBoolean", "propArray" ]
},
"dependentSchemas": {
"propNull": {
"type": "object"
}
},
"propertyNames": true,
"required": [ "propNull", "propBoolean" ],
"maxProperties": 100,
"minProperties": 0,
"properties": {
"propNull": {
"type": "null"
},
"propBoolean": {
"type": "boolean",
"allOf": [
true,
{ "type": "boolean" }
]
},
"propArray": {
"type": "array",
"anyOf": [ false, true ],
"contains": { "type": "integer" },
"maxContains": 100,
"minContains": 2,
"maxItems": 100,
"minItems": 1,
"prefixItems": [
{ "type": "integer" }
],
"items": { "type": "integer" },
"uniqueItems": true
},
"propNumber": {
"type": "number",
"if": {
"const": 1.5
},
"then": true,
"else": true,
"enum": [ 1.5, 0, 1 ]
},
"propString": {
"type": "string",
"maxLength": 100,
"minLength": 0,
"not": false,
"pattern": "abcde"
},
"propInteger": {
"$ref": "#/$defs/typeIsInteger",
"exclusiveMaximum": 100,
"exclusiveMinimum": 0,
"maximum": 100,
"minimum": 0,
"multipleOf": 0.5,
"oneOf": [ true, false ]
}
},
"$defs": {
"typeIsInteger": { "$ref": "http://inside#/$defs/typeIsInteger" },
"toTestAnchor": {
"$anchor": "test-anchor"
},
"toTestAnotherResourceRef": {
"$id": "http://inside",
"$defs": {
"typeIsInteger": { "type": "integer" }
}
}
}
}
Valid benchmark data:
{
"propNull": null,
"propBoolean": true,
"propArray": [ 1, 2, 3, 4, 5 ],
"propNumber": 1.5,
"propString": "abcde",
"propInteger": 1
}
Invalid benchmark data:
{
"propNull": null,
"propBoolean": true,
"propArray": [ 1, 2, 3, 4, 4 ], // Two '4', duplicated
"propNumber": 1.5,
"propString": "abcde",
"propInteger": 1
}
Basic Usage
Install-Package LateApexEarlySpeed.Json.Schema
string jsonSchema = File.ReadAllText("schema.json");
string instance = File.ReadAllText("instance.json");
var jsonValidator = new JsonValidator(jsonSchema);
ValidationResult validationResult = jsonValidator.Validate(instance);
if (validationResult.IsValid)
{
Console.WriteLine("good");
}
else
{
Console.WriteLine($"Failed keyword: {validationResult.Keyword}");
Console.WriteLine($"ResultCode: {validationResult.ResultCode}");
Console.WriteLine($"Error message: {validationResult.ErrorMessage}");
Console.WriteLine($"Failed instance location: {validationResult.InstanceLocation}");
Console.WriteLine($"Failed relative keyword location: {validationResult.RelativeKeywordLocation}");
Console.WriteLine($"Failed schema resource base uri: {validationResult.SchemaResourceBaseUri}");
}
Output Information
When validation failed, you can check detailed error information by:
IsValid: As summary indicator for passed validation or failed validation.
ResultCode: The specific error type when validation failed.
ErrorMessage: the specific wording for human readable message
Keyword: current keyword when validation failed
InstanceLocation: The location of the JSON value within the instance being validated. The value is a JSON Pointer.
RelativeKeywordLocation: The relative location of the validating keyword that follows the validation path. The value is a JSON Pointer, and it includes any by-reference applicators such as "$ref" or "$dynamicRef". Eg:
/properties/width/$ref/minimum
SubSchemaRefFullUri: The absolute, dereferenced location of the validating keyword when validation failed. The value is a full URI using the canonical URI of the relevant schema resource with a JSON Pointer fragment, and it doesn't include by-reference applicators such as "$ref" or "$dynamicRef" as non-terminal path components. Eg:
https://example.com/schemas/common#/$defs/count/minimum
SchemaResourceBaseUri: The absolute base URI of referenced json schema resource when validation failed. Eg:
https://example.com/schemas/common
Performance Tips
Reuse instantiated JsonValidator instances (which basically represent json schema) to validate incoming json instance data if possible in your cases, to gain better performance.
External json schema document reference support
Besides of internal sub schema resource reference (inside current json schema document) support automatically, implementation supports external schema document reference support by:
- local schema text
var jsonValidator = new JsonValidator(jsonSchema);
string externalJsonSchema = File.ReadAllText("schema2.json");
jsonValidator.AddExternalDocument(externalJsonSchema);
ValidationResult validationResult = jsonValidator.Validate(instance);
- remote schema url (library will retrieve actual schema content by access network)
var jsonValidator = new JsonValidator(jsonSchema);
await jsonValidator.AddHttpDocumentAsync(new Uri("http://this-is-json-schema-document"));
ValidationResult validationResult = jsonValidator.Validate(instance);
Custom keyword support
Besides of standard keywords defined in json schema specification, library supports to create custom keyword for additional validation requirement. Eg:
{
"type": "object",
"properties": {
"prop1": {
"customKeyword": "Expected value"
}
}
}
ValidationKeywordRegistry.AddKeyword<CustomKeyword>();
[Keyword("customKeyword")] // It is your custom keyword name
[JsonConverter(typeof(CustomKeywordJsonConverter))] // Use 'CustomKeywordJsonConverter' to deserialize to 'CustomKeyword' instance out from json schema text
internal class CustomKeyword : KeywordBase
{
private readonly string _customValue; // Simple example value
public CustomKeyword(string customValue)
{
_customValue = customValue;
}
// Do your custom validation work here
protected override ValidationResult ValidateCore(JsonInstanceElement instance, JsonSchemaOptions options)
{
if (instance.ValueKind != JsonValueKind.String)
{
return ValidationResult.ValidResult;
}
return instance.GetString() == _customValue
? ValidationResult.ValidResult
: ValidationResult.CreateFailedResult(ResultCode.UnexpectedValue, "It is not my expected value.", options.ValidationPathStack, Name, instance.Location);
}
}
internal class CustomKeywordJsonConverter : JsonConverter<CustomKeyword>
{
// Library will input json value of your custom keyword: "customKeyword" to this method.
public override CustomKeyword? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
// Briefly:
return new CustomKeyword(reader.GetString()!);
}
public override void Write(Utf8JsonWriter writer, CustomKeyword value, JsonSerializerOptions options)
{
throw new NotImplementedException();
}
}
Format support
This library supports following formats currently:
- uri
- uri-reference
- date
- time
- date-time
- uuid
- hostname
- ipv4
- ipv6
- json-pointer
- regex
If require more format, implement an custom FormatValidator, and register it:
[Format("custom_format")] // this is your custom format name in json schema
public class TestCustomFormatValidator : FormatValidator
{
public override bool Validate(string content)
{
// custom format validation logic here...
}
}
// register it globally
FormatRegistry.AddFormatType<TestCustomFormatValidator>();
Other extension usage doc is to be continued .
Limitation
- This implementation focuses on json schema validation, currently not support Annotation
- Due to lack Annotation support, it also not support following keywords: unevaluatedProperties, unevaluatedItems
- Not support content-encoded string currently
Issue report
Welcome to raise issue and wishlist, I will try to fix if make sense, thanks !
More doc is to be written
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.1 is compatible. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- Microsoft.Extensions.Http (>= 8.0.0)
- System.Text.Json (>= 8.0.0)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on LateApexEarlySpeed.Json.Schema:
Package | Downloads |
---|---|
LateApexEarlySpeed.Xunit.Assertion.Json
Provide fluent json assertion for Xunit |
|
LateApexEarlySpeed.EntityFrameworkCore.V3.Json.Schema
Provide schema of json column for EntityFramework Core |
|
LateApexEarlySpeed.EntityFrameworkCore.V6.Json.Schema
Provide schema of json column for EntityFramework Core |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.2.0 | 103 | 12/2/2024 |
1.1.12 | 126 | 11/24/2024 |
1.1.11 | 2,343 | 8/30/2024 |
1.1.10 | 11,770 | 7/24/2024 |
1.1.9 | 432 | 7/23/2024 |
1.1.8 | 95 | 7/19/2024 |
1.1.7 | 3,529 | 6/24/2024 |
1.1.6 | 501 | 6/7/2024 |
1.1.5 | 413 | 5/13/2024 |
1.1.4 | 129 | 5/6/2024 |
1.1.3 | 321 | 4/22/2024 |
1.1.2 | 728 | 4/1/2024 |
1.1.1 | 269 | 3/4/2024 |
1.1.0 | 278 | 2/26/2024 |
1.0.9 | 146 | 2/22/2024 |
1.0.8 | 153 | 2/8/2024 |
1.0.7 | 113 | 2/1/2024 |
1.0.6 | 118 | 1/30/2024 |
1.0.5 | 120 | 1/18/2024 |
1.0.4 | 152 | 1/8/2024 |
1.0.3 | 145 | 12/29/2023 |
1.0.3-beta2 | 116 | 12/20/2023 |
1.0.3-beta1 | 131 | 12/19/2023 |
1.0.2 | 132 | 12/13/2023 |
1.0.1 | 115 | 12/8/2023 |
1.0.0 | 137 | 12/1/2023 |