Validating JSON with JSON Schema in C# using Newtonsoft - c#

Validate the JSON with JSON Schema return always true.
Newtonsoft is used for validation and tested here with schema and data.
It return always 'No errors found. JSON validates against the schema'.
Please find my JSON Schema.
{
"schema": {
"definitions": {
},
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/root.json",
"type": "object",
"widget": { "formlyConfig": { "type": "accordion" } },
"title": "The Root Schema",
"required": [
"accordion1",
"accordion2",
"accordion3"
],
"properties": {
"accordion1": {
"$id": "#/properties/accordion1",
"type": "object",
"title": "The Accordion1 Schema",
"required": [
"firstname",
"age"
],
"properties": {
"firstname": {
"$id": "#/properties/accordion1/properties/firstname",
"type": "string",
"title": "The Firstname Schema",
"default": "firstname pvr1"
},
"age": {
"$id": "#/properties/accordion1/properties/age",
"type": "integer",
"title": "The Age Schema",
"default": 21
}
}
},
"accordion2": {
"$id": "#/properties/accordion2",
"type": "object",
"title": "The Accordion2 Schema",
"required": [
"firstname",
"age"
],
"properties": {
"firstname": {
"$id": "#/properties/accordion2/properties/firstname",
"type": "string",
"title": "The Firstname Schema",
"default": "firstName2"
},
"age": {
"$id": "#/properties/accordion2/properties/age",
"type": "integer",
"title": "The Age Schema",
"default": 31
}
}
},
"accordion3": {
"$id": "#/properties/accordion3",
"type": "object",
"title": "The Accordion3 Schema",
"required": [
"firstname",
"age"
],
"properties": {
"firstname": {
"$id": "#/properties/accordion3/properties/firstname",
"type": "string",
"title": "The Firstname Schema",
"default": "firstnaem3"
},
"age": {
"$id": "#/properties/accordion3/properties/age",
"type": "integer",
"title": "The Age Schema",
"default": 10
}
}
}
},
'additionalProperties': false
}
}
Please find JSON
{
"accordion1":{
"firstname":"JSON ACCORD PALANIVELRAJAN",
"age":29
},
"accordion2":{
"firstname":"JSON ACCORD LAKSHMANAN",
"age":39
},
"accordion3":{
"firstname":null,
"age":49
}
}
I tried to change the first name to integer and remove the first in accordion1. It return true for all cases.
Please advise.
Please find the code which validate the JSON with JSON Schema.
model is a JObject and it is a valid JSON.
JsonSchema json_schema = JsonSchema.Parse(schema);
IList<string> messages;
bool valid = model.IsValid(json_schema, out messages);
return valid;

JsonSchema is deprecated, and has moved to a separate package: Newtonsoft.Json.Schema. Using this package, I was able to validate your JSON against your schema (I did remove the outer schema element, as it is actually invalid, and causes schema to not validate properly - I think you might've had it in there because the old JsonSchema class could not parse the schema otherwise!), and get error messages if I changed the JSON to an invalid shape, removed required elements, or changed data to invalid types:
string data = File.ReadAllText("data.json");
string schema = File.ReadAllText("data.schema.json");
var model = JObject.Parse(data);
var json_schema = JSchema.Parse(schema);
IList<string> messages;
bool valid = model.IsValid(json_schema, out messages); // properly validates
I am using .NET Core 2.2, Newtonsoft.Json 12.0.2, and Newtonsoft.Json.Schema 3.0.11, just in case it matters. Please note, the Newtonsoft.Json.Schema package has limitations for commercial use - check licensing!

Related

Deserialize Avro Schema field that is multiple union types

I am trying to integrate with salesforces new grpc change data capture event bus. Events are sent to clients via grpc with an avro encoded message of what the changes to the records were, so the client has to decode the message using an avro schema that is provided and unable to be changed.
I am able to easily decode the avro encoded message for objects with fields of two union types but fields with three types throw exceptions.
This is the Name field for the Account avro schema:
{
"name": "Name",
"type": [
"null",
"string",
{
"type": "record",
"name": "Switchable_PersonName",
"fields": [
{
"name": "Salutation",
"type": [
"null",
"string"
],
"default": null
},
{
"name": "FirstName",
"type": [
"null",
"string"
],
"default": null
},
{
"name": "LastName",
"type": [
"null",
"string"
],
"default": null
},
{
"name": "MiddleName",
"type": [
"null",
"string"
],
"default": null
},
{
"name": "InformalName",
"type": [
"null",
"string"
],
"default": null
},
{
"name": "Suffix",
"type": [
"null",
"string"
],
"default": null
}
]
}
],
"doc": "Data:Switchable_PersonName",
"default": null
},
As you can see the name can either be null, a string, or an object called Switchable_PersonName.
Using the avrogen cli tool, I was able to convert the avro schema into concrete c# classes of AccountChangeEvent, ChangeEventHeader, ChangeType, Address, Switchable_PersonName.
The Name field was created in the AccountChangeEvent class as:
private object _Name;
This is the method I made for decoding the avro message:
public static void DeserializeAccountConcrete(byte[] payload)
{
var accSchema = Avro.Schema.Parse(File.ReadAllText("./avro/AccountGRPCSchema.avsc"));
var unionSchema = accSchema as Avro.UnionSchema;
var cache = new ClassCache();
cache.LoadClassCache(typeof(AccountChangeEvent), unionSchema);
cache.LoadClassCache(typeof(Switchable_PersonName), unionSchema);
cache.LoadClassCache(typeof(Address), unionSchema);
var reader = new ReflectReader<AccountChangeEvent>(accSchema, accSchema, cache);
using var accStream = new MemoryStream(payload);
accStream.Seek(0, SeekOrigin.Begin);
var accDecoder = new BinaryDecoder(accStream);
var accEvent = reader.Read(accDecoder);
Console.WriteLine(accEvent.Name);
Console.WriteLine("Event " + accEvent.ChangeEventHeader.changeType);
}
This sort of deserialization works for other schemas but it fails for the Account schema with this exception being thrown.
Avro.AvroException: Class for union record type com.sforce.eventbus.Switchable_PersonName is not registered.Create a ClassCache object and call LoadClassCache
Looking at the documentation for avro my implementation looks correct but it seems it is not.
I have changed the field type to
private com.sforce.eventbus.Switchable_PersonName _Name;
and any other code that may rely on this field but the same error is still thrown.
I am new to avro so there may be many things that I do not know or am doing wrong.

web api post dynamic type and validation

I developing a method that accepts various messages and returns the some result. The main goal is that message formats can be added without rebuilding the project. Two types of the messages is below:
{
"PushToken": "ksjdfhskfhskdjfhskjdfhk",
"AlertŠµ": "ssffsdfsdfsdfsdfsdfsfs sfsdfsdf sfsdfsdfs",
"Priority": 5,
"IsBackground": false
}
and
{
"DeviceToken": "ksjdfhskfhskdjfhskjdfhkkh7khsdfjk8sdfsdfsddddddddddddddd",
"Message": "ssffsdfsdfsdfsdfsdfsfs sfsdfsdf sfsdfsdfs",
"Title": "asdasdas",
"Condition": "asfdasf"
}
I thinked how to validate messages and decided using json schema's. They are below:
{
"title":"IOS",
"description": "IOS Message",
"type": "object",
"properties": {
"PushToken": { "type": "string", "maxLength": 50 },
"Alert": { "type": "string", "maxLength": 2000 },
"Priority": { "type": "number", "default": 10 },
"IsBackground": { "type": "boolean", "default": true }
},
"required":[
"PushToken",
"Alert"
],
"additionalProperties": false
}
and
{
"title":"Android",
"description": "Android message",
"type": "object",
"properties": {
"DeviceToken": { "type": "string", "maxLength": 50 },
"Message": { "type": "string", "maxLength": 2000 },
"Title": { "type": "string", "maxLength": 255 },
"Condition": { "type": "string", "maxLength": 2000 }
},
"required":[
"DeviceToken",
"Message",
"Title"
],
"additionalProperties": false
}
For validating I using thomething like that:
JSchema schema = JSchema.Parse(iosJsonSchema);
IList<string> errorMessages;
bool valid = iosJsonMessage.IsValid(schema, out errorMessages); //iosJsonMessage - JObject type
In IList<string> messages I receive all errors. In bool valid variable I receive validation result.
Is there a way to check only properties names of the json request? And only those names that are declare in required section of the json schema. I want to do this for understanding the type of the message.
And a more general question. Is this an acceptable solution for task that I described above?
Thanks.

Validate JSON schema with other JSON schema in C#

I want to evaluate the json schema with another json schema. I am creating a form with the default json schema and adding some new properties. After that I am posting this new json schema. At this point I need to validate the new schema. Because I want to know that there are some properties in the new schema. I want to give an example
My default schema:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/product.schema.json",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "object",
"properties": {
"productId": {
"description": "The unique identifier for a product",
"type": "integer"
},
"productName": {
"description": "Name of the product",
"type": "string"
}
},
"required": [ "productId", "productName" ]
}
New successful schema:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/product.schema.json",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "object",
"properties": {
"productId": {
"description": "The unique identifier for a product",
"type": "integer"
},
"productName": {
"description": "Name of the product",
"type": "string"
},
"productType": {
"description": "Type of the product",
"type": "string"
},
"categoryId": {
"description": "Category id",
"type": "integer"
}
},
"required": [ "productId", "productName", "categoryId" ]
}
New error schema:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/product.schema.json",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "object",
"properties": {
"productId": {
"description": "The unique identifier for a product",
"type": "integer"
}
},
"required": [ "productId" ]
}
In a successful example, new properties with default properties were added. However, in the error example, the productName property, which should have been by default, has been removed. So how can I verify the schema with another schema?
Edit: #Relequestual fixed me. My question is how can I confirm my schema with meta-schema?

JSON Schema - Can not convert Array to Boolean

I'm testing NewtonSoft's JsonSchema package and have the following code
string schemaJson = File.ReadAllText("c:\\temp\\schema.txt");
JsonSchema schema = JsonSchema.Parse(schemaJson);
When I test the schema on https://www.jsonschemavalidator.net/ it executes correctly, but when I run the above code locally I get an ArgumentException "Can not convert Array to Boolean".
Here is the schema:
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "http://example.com/root.json",
"type": "object",
"title": "The Root Schema",
"description": "The root schema is the schema that comprises the entire JSON document.",
"default": {},
"required": [
"checked",
"dimensions",
"id",
"name",
"price",
"tags"
],
"properties": {
"checked": {
"$id": "#/properties/checked",
"type": "boolean",
"title": "The Checked Schema",
"description": "An explanation about the purpose of this instance.",
"default": false,
"examples": [
false
]
},
"dimensions": {
"$id": "#/properties/dimensions",
"type": "object",
"title": "The Dimensions Schema",
"description": "An explanation about the purpose of this instance.",
"default": {},
"examples": [
{
"height": 10.0,
"width": 5.0
}
],
"required": [
"width",
"height"
],
"properties": {
"width": {
"$id": "#/properties/dimensions/properties/width",
"type": "integer",
"title": "The Width Schema",
"description": "An explanation about the purpose of this instance.",
"default": 0,
"examples": [
5
]
},
"height": {
"$id": "#/properties/dimensions/properties/height",
"type": "integer",
"title": "The Height Schema",
"description": "An explanation about the purpose of this instance.",
"default": 0,
"examples": [
10
]
}
}
},
"id": {
"$id": "#/properties/id",
"type": "integer",
"title": "The Id Schema",
"description": "An explanation about the purpose of this instance.",
"default": 0,
"examples": [
1
]
},
"name": {
"$id": "#/properties/name",
"type": "string",
"title": "The Name Schema",
"description": "An explanation about the purpose of this instance.",
"default": "",
"examples": [
"A green door"
]
},
"price": {
"$id": "#/properties/price",
"type": "number",
"title": "The Price Schema",
"description": "An explanation about the purpose of this instance.",
"default": 0,
"examples": [
12.5
]
},
"tags": {
"$id": "#/properties/tags",
"minItems": 3,
"type": "array",
"title": "The Tags Schema",
"description": "An explanation about the purpose of this instance.",
"default": [],
"examples": [
[
"home",
"green"
]
],
"items": {
"$id": "#/properties/tags/items",
"type": "string",
"title": "The Items Schema",
"description": "An explanation about the purpose of this instance.",
"default": "",
"examples": [
"home",
"green"
]
}
}
}
}
and here is the (invalid) JSON that I use on the website to test the schema validation:
{
"checked": "false",
"dimensions": {
"width": 5,
"height": 10
},
"id": 1,
"name": "A green door",
"price": 12.5,
"tags": [
"home",
"green"
]
}
I was able to reproduce your problem here.
It appears that you are using the JsonSchema component from the Newtonsoft.Json package. As noted in the documentation, this component is obsolete and has been replaced by a newer JSchema component which is in a separate Newtonsoft.Json.Schema package.
If you use the newer component your schema loads as expected.

Convert c# class from JSON schema

I am working on project where I need to call Web API which on success send json data along with other data. Now i have JSON schema as per their documentation so I want to parse data as per Schema mentioned so that I get everything in c# .
I know I can create a class manually then parse using Newtonsoft etc.. but Is there any way I can create class from JSON schema and parse output based upon that.
I have tried online tool to convert JSON to c# but as my schema contains property of each filed like whither required or datatype etc.. So not getting exact result even after parsring..
Json schema is as below
{
"description": "Rightmove Realtime Datafeed Json Schema for GetBranchPerformance response",
"type": "object",
"properties": {
"request_id": {
"type": "string",
"required": true,
"description": "The unique ID of the request which this response is associated with"
},
"message": {
"type": "string",
"required": true,
"description": "The message content for the response"
},
"success": {
"type": "boolean",
"required": true,
"description": "Indicates whether or not the request was successful"
},
"request_timestamp": {
"type": "string",
"required": true,
"description": "The time at which the request was received in the format: dd-MM-yyyy HH:mm:ss"
},
"response_timestamp": {
"type": "string",
"required": true,
"description": "The time at which the response was sent in the format: dd-MM-yyyy HH:mm:ss"
},
"replication_lag": {
"type": ["integer", "null"],
"required": false,
"description": "The current lag time for replicating between the three Rightmove data centres in minutes"
},
"export_date": {
"type": ["string", "null"],
"required": false,
"description": "The date for the export period in the format: dd-MM-yyyy"
},
"branch": {
"type": ["object","null"],
"required": false,
"description": "Information about the branch for which the metrics are being generated",
"properties": {
"branch_id": {
"type": "integer",
"id": "branch_id",
"required": true,
"description": "Unique Rightmove ID for the branch for which the performance metrics are being generated"
}
},
"additionalProperties": false
},
"performance_data": {
"type": ["object","null"],
"required": false,
"description": "Branch performance data, for the selected export date",
"properties": {
"email_leads": {
"type": "integer",
"required": true,
"description": "The total number of email leads received for a given branch, on the specified day"
},
"phone_leads": {
"type": "integer",
"required": true,
"description": "The total number of phone leads received for a given branch, on the specified day"
},
"property_data": {
"type": [
"array",
"null"
],
"id":"property_data",
"required": false,
"description": "Details about performance by property on Rightmove",
"items": {
"type": "object",
"id": "each_property_data",
"required": true,
"properties": {
"agent_ref":{
"type":"string",
"required":true,
"description":"The agent's unique reference for the property"
},
"display_address": {
"type": "string",
"required": true,
"description": "The display address of the property on Rightmove"
},
"price": {
"type": "integer",
"required": true,
"description": "The current listed price for the property on Rightmove"
},
"channel":{
"type":["integer","null"],
"id":"channel",
"required":false,
"enum":[1, 2, null],
"description":"For dual branches it specifies the channel of the property: 1 Sales 2 Lettings"
},
"rightmove_id":{
"type":"integer",
"required":true,
"description":"Rightmove's unique reference for the property"
},
"rightmove_url":{
"type":"string",
"required":true,
"description":"The Rightmove URL for the property"
},
"featured_property":{
"type":"boolean",
"required":true,
"description":"Y/N - was the property a featured property on this date?"
},
"premium_listing":{
"type":"boolean",
"required":true,
"description":"Y/N - was the property a premium listing on this date?"
},
"summary_views": {
"type": ["object","null"],
"id": "summary_views",
"required": false,
"description": "Information on a property's summary views on Rightmove on the date specified",
"properties": {
"total_summary_views": {
"type":"integer",
"required":true,
"description":"The total number of times the property has appeared in a summary view on the requested date"
},
"desktop_summary_views": {
"type":"integer",
"required":true,
"description":"The total number of times the property has appeared in a summary view on the requested date, when viewed from a desktop PC"
},
"mobile_summary_views": {
"type":"integer",
"required":true,
"description":"The total number of times the property has appeared in a summary view on the requested date, when viewed from a mobile device"
}
}
},
"detail_views": {
"type": ["object","null"],
"id": "detail_views",
"required": false,
"description": "Information on a property's detail views on Rightmove on the date specified",
"properties": {
"total_detail_views": {
"type":"integer",
"required":true,
"description":"The total number of detail views of the property on the requested date"
},
"desktop_detail_views": {
"type":"integer",
"required":true,
"description":"The total number of detail views of the property on the requested date, when viewed from a desktop PC"
},
"mobile_detail_views": {
"type":"integer",
"required":true,
"description":"The total number of detail views of the property on the requested date, when viewed from a mobile device"
}
}
}
},
"additionalProperties": false
}
}
},
"additionalProperties": false
},
"errors": {
"type": [
"array",
"null"
],
"required": false,
"description": "The errors causing the request to fail",
"minItems": 0,
"items": {
"type": [
"object",
"null"
],
"required": false,
"properties": {
"error_code": {
"type": "string",
"id": "error_code",
"required": true,
"description": "The unique Rightmove code for the error causing the request to fail"
},
"error_description":{
"type":"string",
"id":"error_description",
"required":true,
"description": "The full description of the error associated with the error code which has been generated"
},
"error_value":{
"type":["string", "null"],
"id":"error_value",
"required":false,
"description": "The value that caused this error"
}
},
"additionalProperties": false
},
"additionalProperties": false
},
"warnings": {
"type": [
"array",
"null"
],
"required": false,
"description": "The warning generated by the request",
"minItems": 0,
"items": {
"type": [
"object",
"null"
],
"required": false,
"properties": {
"warning_code": {
"type": "string",
"id": "warning_code",
"required": true,
"description": "The unique Rightmove warning code generated due to failure to pass all of the business rules"
},
"warning_description":{
"type":"string",
"id":"warning_description",
"required":true,
"description": "The full description of the warning associated with the warning code which has been generated"
},
"warning_value":{
"type":["string", "null"],
"id":"warning_value",
"required":false,
"description": "The value that caused this warning"
}
},
"additionalProperties": false
},
"additionalProperties": false
}
},
"additionalProperties": false
}

Categories