How to make sure that NJsonSchema only includes required fields? - c#

I'm using NJsonSchema v2.6 for generating the JSON Schema for the following class:
[DataContract(Name = "Message", Namespace = "")]
public class AMessageModel
{
[DataMember]
internal Guid MessageId { get; set; }
internal DateTime MessageDate { get; set; }
}
[DataContract(Name = "Message", Namespace = "")]
public class AddUserMessage : AMessageModel
{
[DataMember]
public string AccountName { get; set; }
[DataMember]
public string FistName { get; set; }
[Range(2, 5)]
[DataMember]
public string LastName { get; set; }
[DataMember]
public string Email { get; set; }
[DataMember]
public string Password { get; set; }
}
The generated JSON Schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"typeName": "AddFitnessHubAccountMessage",
"additionalProperties": false,
"properties": {
"AccountName": {
"type": [
"null",
"string"
]
},
"FistName": {
"type": [
"null",
"string"
]
},
"LastName": {
"type": [
"null",
"string"
]
},
"Email": {
"type": [
"null",
"string"
]
},
"Password": {
"type": [
"null",
"string"
]
}
},
"allOf": [
{
"type": "object",
"typeName": "AMessageModel",
"additionalProperties": false,
"properties": {
"MessageId": {
"type": "string",
"format": "guid"
},
"MessageDate": {
"type": "string",
"format": "date-time"
}
}
}
]
}
Even though the MessageDate property is not marked as a DataMember, it is always included in the schema, also the generated schema includes two schema paths when it should only include one, it seems that the parser is not flattening the properties.
UPDATE
This fixes the issue with multiple schema paths being created
new JsonSchemaGeneratorSettings
{
FlattenInheritanceHierarchy = true
}
GitHub Issue: https://github.com/NJsonSchema/NJsonSchema/issues/53

I'm the author of the library NJsonSchema.
Ignored properties
There was a bug in the library and now (v2.7+) property ignore works as follows:
A property is ignored when either
The property is marked with the JsonIgnoreAttribute property
The class has an DataContractAttribute attribute and the property has no DataMemberAttribute and no JsonPropertyAttribute
https://github.com/NJsonSchema/NJsonSchema/wiki/JsonSchemaGenerator
Flatten inheritance hierarchy
As you already found out, you can flatten the inheritance hierarchy via the FlattenInheritanceHierarchy setting...
The library is mainly used for code generation, and thus the inheritance is usually needed.

Since NJsonSchema has a dependency on Newtonsoft.Json, have you tried this from the Newtonsoft.Json documentation?
Conditional Property Serialization
To conditionally serialize a property, add a method that returns
boolean with the same name as the property and then prefix the method
name with ShouldSerialize. The result of the method determines whether
the property is serialized. If the method returns true then the
property will be serialized, if it returns false then the property
will be skipped.

Related

How to mapping a multiple type javascript array to C# array

I use asp.net MVC model binding to accept the parameters for ajax.
I have an object, it's data structure like this:
{
"conditions": [
{
"field": "",
"opreator": "",
"value": ""
},[{
"field": "",
"opreator": "",
"value": ""
},
{
"field": "",
"opreator": "",
"value": ""
}]
],
"name": "query",
}
C# array can't has different types. (the property conditions is an arrray that has object and array).
So I defined an object array.
public class QueryVM
{
public class condition
{
public string field { get; set; }
public string opreator { get; set; }
public string value { get; set; }
}
public object[] conditions { get; set; }
public string name { get; set; }
}
But what I received the property conditions is just an object array. I can't access it's actual property, I even don't know it's actual type is(QueryVM.condition or array). I thinks the model binding even not set value of the properties. So this is a bad way.
I want know whether there is other way to do this?
UPDATE
The conditions property of QueryVM is an object array because it's contain object and array.
Conditions should be an array of type condition instead of simple object.
Try replacing
public object[] conditions { get; set; }
with
public condition[] conditions { get; set; }
actually you are sending list of type object because the type is not defined so you can do something like this
public List<object> conditions { get; set; }
this will get the list but your json should be like this
conditions:[{
"field": "",
"opreator": "",
"value": ""
},
{
"field": "",
"opreator": "",
"value": ""
}]
and your then your type will be
public List<condition> conditions { get; set; }

How to store C# objects with dynamic properties in RavenDB?

I'm having problems when trying to save an object that has a dynamic property in RavenDB
The object I'm trying to save represents an order. The order contains a list of orderlines so imagine the following Order class:
public class Order {
public int Id { get; set; }
public List<Orderline> Orderlines { get; set; }
}
And the Orderline class being:
public class Orderline {
public Product Product { get; set; }
public int Quantity { get; set; }
public dynamic Attributes { get; set; }
}
The object I'm trying to save (I'll display it with JSON);
{
"Id": 0,
"Orderlines": [
{
"Product": {
"Id": 0,
"Name": "Some product"
},
"Quantity": 1,
"Attributes": {
"color": "Red"
}
}
]
}
Saving it does not throw any errors
RavenDB stores the Order object as
{
"Id": 0,
"Orderlines": [
{
"Product": {
"Id": 0,
"Name": "Some product"
},
"Quantity": 1,
"Attributes": {
"$type": "Newtonsoft.Json.Linq.JObject, Newtonsoft.Json",
"color": {
"$type": "Newtonsoft.Json.Linq.JValue, Newtonsoft.Json",
"$values": []
}
}
}
]
}
Note that the values property of Order.Orderlines[0].Attributes.color is not set...
When I try to serialize the object back to my C# Order object I get the following exception;
Unable to cast object of type
'Raven.Imports.Newtonsoft.Json.Utilities.CollectionWrapper`1[Newtonsoft.Json.Linq.JToken]'
to type 'Newtonsoft.Json.Linq.JValue'.
What am I doing wrong, how can I store this object in the RavenDB database and retrieve it?
What is the type that you are actually saving into attributes?
Typically you'll use something that is actually dynamic, like ExpandoObject
Storing the dynamic property with type 'dynamic' apparently wasn't enough. When I gave the Attributes property the ExpandoObject type, RavenDB stored the Attributes property as normal JSON (without $type and $values, so clean as desired)
When retrieving it back from the RavenDB database it deserializes back to an ExpandoObject object.
Make sure to cast the ExpandoObject property to a dynamic (e.g. 'as dynamic') when trying to display the property in a Razor view.

Finding a column value where columnID equals xxxx in JSON using C#

I am using C# to grab values from a JSON file and put them into a database. I am new to JSON and so don't really know too much of how to work with it. I will do my best to explain the structure I have and what I am trying to do. But to sum up I am trying to call a variable from JSON in a similar way you would do in an SQL Where statement. So grab this value where this other value = x.
So the JSON format is as follows.
Firstly it idenfitifies the columns.
"columns": [
{
"id": 8098453499733892,
"index": 0,
"title": "Task Name",
"type": "TEXT_NUMBER",
"format": ",,,,,,2,,,,,,,,,1",
"primary": true,
"width": 378
},
{
"id": 780104105256836,
"index": 1,
"title": "KPI (RYG)",
"type": "PICKLIST",
"symbol": "RYG",
"options": [
"Red",
"Yellow",
"Green"
],.....
Then the rows and cells within that:
"id": 2157159933863812,
"rowNumber": 2,
"parentRowNumber": 1,
"parentId": 7786659468076932,
"expanded": false,
"format": ",,1,,,,,,,22,,,,,,",
"createdAt": "2015-03-04T15:58:28+13:00",
"modifiedAt": "2015-03-04T15:58:32+13:00",
"cells": [
{
"columnId": 8098453499733892,
"type": "TEXT_NUMBER",
"value": "GLH Toll MASTER FROM WEEK 47",
"displayValue": "GLH Toll MASTER FROM WEEK 47",
"format": ",,1,,,,2,,,22,,,,,,1"
},
{
"columnId": 2750428942231428,
"type": "CHECKBOX",
"value": true,
"format": ",,1,,,,,,,22,,,,,,"
},
Ok so for an example. What I want to do is grab the columnID value in the cell, and then use that to find the title value in the column. So in the above example, I would want to find 'title' where id in column equals 8098453499733892, which would give me the result of 'Task Name'.
I don't even know if this is possible but have struggled to find a working example on the web. FYI I am using smartsheets.
You need to create an equivalent object/class in your c# containing those properties in your JSON. In order to get the columnID column based on your JSON structure, you need to create the the class below:
class Class1 {
public string id { get; set; }
public int rowNumber { get; set; }
public int parentId { get; set; }
public bool expanded { get; set; }
public string format{ get; set; }
public List <Cells> cells {get; set;}
}
class Cells {
public string columnId {get; set;}
public string type{get; set;}
public bool value{get; set;}
public string format {get; set;}
}
You need to deserialize the JSON string from the API using the Class1 object and from there you can access whatever column that you need.
For anyone looking I used the where clause in the select token. Here is the code that I used to find the column title based on an id value.
var test = jObject.SelectToken("columns").Where(t => t["id"].Value<Int64>() == 5283703732627332).FirstOrDefault()["title"].Value<string>();

Creating Non-Nullable Array Types With JSchemaGenerator

I am using Newtonsoft.Json.schema v1.0.6 and I am trying to generate JSchema for custom type that has an array property that is similar to this:
public class MyClass {
public List<MyChild> Children { get; set; }
}
public class MyChild {
public string MyProperty { get; set; }
}
The default JSchemaGenerator generates a JSchema similar to this:
{
"type": "object",
"properties": {
"MyChildren": {
"type": "array",
"items": {
"type": [
"object",
"null"
],
...
}
}
},
...
}
I do not want to accept null items in the MyChildren array. I have tried adding the [JsonProperty(Required = Required.Always)] attribute but it just makes the MyChildren property itself required and I cannot add the attribute to the MyChild class.
I figure I'm going to have to implement a custom JSchemaGenerationProvider but the JSchema.Items property is readonly.
How do I generate JSON schema for an object that has an array property that should not accept null values?
JSchema.Items is readonly but the schema inside it can be modified. Just set its Type to JSchemaType.String.

Model to match this JSON for deserialization, field names with dashes

I am trying to create a model that would match the JSON.NET deserealization of this JSON structure:
First item...
{
"190374": {
"vid": 190374,
"canonical-vid": 190374,
"portal-id": 62515,
"is-contact": true,
"profile-token": "AO_T-mN1n0Mbol1q9X9UeCtRwUE1G2GFUt0VVxCzpxUF1LJ8L3i75x9NmhIiS0K9UQkx19bShhlUwlIujY4pSXAFPEfDG-k9n8BkbftPw6Y5oM3eU5Dc_Mm-5YNJTXiWyeVSQJAN_-Xo",
"profile-url": "https://app.hubspot.com/contacts/62515/lists/public/contact/_AO_T-mN1n0Mbol1q9X9UeCtRwUE1G2GFUt0VVxCzpxUF1LJ8L3i75x9NmhIiS0K9UQkx19bShhlUwlIujY4pSXAFPEfDG-k9n8BkbftPw6Y5oM3eU5Dc_Mm-5YNJTXiWyeVSQJAN_-Xo/",
"properties": {
"phone": {
"value": "null"
},
"hs_social_linkedin_clicks": {
"value": "0"
},
"hs_social_num_broadcast_clicks": {
"value": "0"
},
"hs_social_facebook_clicks": {
"value": "0"
},
"state": {
"value": "MA"
},
"createdate": {
"value": "1380897795295"
},
"hs_analytics_revenue": {
"value": "0.0"
},
"lastname": {
"value": "Mott"
},
"company": {
"value": "HubSpot"
}
},
"form-submissions": [],
"identity-profiles": []
},
"form-submissions": [],
"identity-profiles": []
},
**next similar entry**
Then I try to bind with List of this:
public class HubSpotEmailRqst
{
public int vid { get; set; }
public int canonical-vid { get; set; }
public int portal-id { get; set; }
public bool is-contact { get; set; }
public String profile-token { get; set; }
public String profile-url { get; set; }
public Dictionary<string, string> properties { get; set; }
public Dictionary<string,string> form-submissions { get; set; }
public Dictionary<string,string> identity-profiles { get; set; }
}
I am not sure this will bind either, but I cannot get past the fact we cannot have hyphen in the field names, how can I get around this?
There're two ways to use properties with hyphens:
Name properties according to C# rules, but decorate them with [JsonProperty("property-name")] attribute.
Use custom contract resolver which modifies property names. For example, if all properties in JSON are named consistently, you can use regex to change PascalCase C# property names to lower-case JSON property names. See CamelCasePropertyNamesContractResolver from Json.NET for example implementation.
If I'm understanding the question correctly, you are upset that you can't use a hyphen in a field name in a C# program? Why not use CamelCase to identify the fields? Instead of is-contact use 'isContact'. Instead of canonical-vid. use canonicalVid. Sure, the names may look different, but to the programmer the meaning should be clear.

Categories

Resources