Deserializing Json Schema to Json String or Object - c#

I have a json schema and I need to convert it to a C# object or at least into json string.
is there any way to do it by code or by using some tool?
for the Json I'm currently using Json.net.
this is one of my schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "UserGroupWsDTO",
"type": "object",
"properties":
{
"members":
{
"type": "array",
"items":
{
"type": "object",
"properties":
{
"uid":
{
"type": "string"
}
}
}
},
"uid":
{
"type": "string"
},
"name":
{
"type": "string"
}
}
}
I need this to create an Object for deserialize the json
EDIT
My Json schema version is 4 and JSON Schema to POCO doesn't support it

Have a look at JSON Schema to POCO which supports v3 JSON.

If you are just "browsing" key-values, then you don't need any extra libs...
just do:
var obj = (JObject)JsonConvert.DeserializeObject(json);
var dict = obj.First.First.Children().Cast<JProperty>()
.ToDictionary(p => p.Name, p =>p.Value);
var dt = (string)dict["title"];
but if instead you need an object of the string, then define a class and deserialize the string to that class... follow this example:
1st define the classes:
public class Uid
{
public string type { get; set; }
}
public class Properties2
{
public Uid uid { get; set; }
}
public class Items
{
public string type { get; set; }
public Properties2 properties { get; set; }
}
public class Members
{
public string type { get; set; }
public Items items { get; set; }
}
public class Uid2
{
public string type { get; set; }
}
public class Name
{
public string type { get; set; }
}
public class Properties
{
public Members members { get; set; }
public Uid2 uid { get; set; }
public Name name { get; set; }
}
public class RootObject
{
public string __invalid_name__$schema { get; set; }
public string title { get; set; }
public string type { get; set; }
public Properties properties { get; set; }
}
and this is the implementation:
string json = #"{...use your json string here }";
RootObject root = JsonConvert.DeserializeObject<RootObject>(json);
Console.WriteLine(root.title);
// UserGroupWsDTO

Related

Deserialize Json string with child objects

Got the following structure given:
public class TaskList
{
public string Name { get; set; }
public List<ToDoTask> ToDoTasks { get; set; }
}
public class ToDoTask
{
public string Name { get; set; }
public string Note { get; set; }
public DateTime LastEdit { get; set; }
public bool Finished { get; set; }
}
I'm using System.Text.Json in .NET 5.0 to serialize a List successfully into a json-file:
JsonSerializerOptions serializeOptions = new() { WriteIndented = true };
string json = JsonSerializer.Serialize(taskLists, serializeOptions);
the result looks fine:
{
"TaskLists": [
{
"Name": "List1",
"ToDoTasks": [
{
"Name": "Task1",
"Note": "",
"LastEdit": "2022-04-19T13:05:10.0415588+02:00",
"Finished": false
},
{
"Name": "Task2",
"Note": "",
"LastEdit": "2022-04-19T13:05:13.9269202+02:00",
"Finished": false
}
]
},
{
"Name": "List2",
"ToDoTasks": [
{
"Name": "Task3",
"Note": "",
"LastEdit": "2022-04-19T13:05:18.3989081+02:00",
"Finished": false
},
{
"Name": "Task4",
"Note": "",
"LastEdit": "2022-04-19T13:05:23.0949034+02:00",
"Finished": false
}
]
}
]
}
When I deserialize this json-file, I only got the TaskLists but the ToDoTasks, are empty.
List<TaskList> taskLists = JsonSerializer.Deserialize<List<TaskList>>(json);
What do I have to do, get also the ToDoTask-Childs included into the deserialized objects?
Whenever you cannot figure out your model class, you can use Visual Studio's Edit - Paste Special - Paste JSON as Class to check out.
Your model classes should be like this:
public class Rootobject
{
public Tasklist[] TaskLists { get; set; }
}
public class Tasklist
{
public string Name { get; set; }
public Todotask[] ToDoTasks { get; set; }
}
public class Todotask
{
public string Name { get; set; }
public string Note { get; set; }
public DateTime LastEdit { get; set; }
public bool Finished { get; set; }
}
And you can Deserialize it:
static void Main(string[] args)
{
var query = JsonSerializer.Deserialize<Rootobject>(File.ReadAllText("data.json"));
}
Your json has a root object containing the task list, so List<TaskList> does not represent it correctly. Try:
public class Root
{
public List<TaskList> TaskLists { get; set; }
}
var root = JsonSerializer.Deserialize<Root>(json);

C# Newtonsoft JSON map property to array sub item

I'm using Newtonsoft to deserialize JSON data to an object.
My JSON looks like this:
{
"id": "4aa50d01-41bd-45e3-803e-f479a948acf1",
"referenceNumber": "120064",
"status": "Application in Progress",
"borrowers": [
{
"name": "John Doe",
"type": "BORROWER"
},
{
"name": "Jane Doe",
"type": "COBORROWER"
}
],
"propertyAddress": {
"zipCodePlusFour": ""
}
}
The borrowers array can have up to 2 items. 1 with type == "BORROWER"and the other with type == "COBORROWER"
I have a LoanItem class I am deserializing to.
public class LoanItem
{
public string referenceNumber { get; set; }
public string status { get; set; }
}
I know I can mark the LoanItem property with the JSONProperty attribute but I'm wondering if there is a way I can add an array sub item with a condition.
Something maybe like
[JSONProperty("borrowers[WHERE type = 'BORROWER'].name")]
public string BorrowerName { get; set; }
[JSONProperty("borrowers[WHERE type = 'COBORROWER'].name")]
public string CoBorrowerName { get; set; }
Is this possible? Can I use the JSONProperty attribute?
Create a new class Borrower
public class Borrower
{
string Name { get; set; }
string Type { get; set; }
}
Update your LoanItem class to this
public class LoanItem
{
public string referenceNumber { get; set; }
public string status { get; set; }
public List<Borrower> Borrowers {get;set;}
public string BorrowerName { get { return Borrowers.Where(x=>x.Type == "BORROWER").FirstOrDefault().Name; }
public string CoBorrowerName { get { return return Borrowers.Where(x=>x.Type == "COBORROWER").FirstOrDefault().Name; } }
}
Now you can access the BorrowerName and CoborrowerName

What is the correct class structure in C# to convert this Json into?

I have the following Json below coming from a Rest service and I am trying to deserialize it into a C# object using this code:
var _deserializer = new JsonDeserializer();
var results = _deserializer.Deserialize<Report>(restResponse);
The deserialize method keeps returning null which tells me that my C# object is not structured correctly.
Below is the Json and my latest attempt at the C# definition.
{
"Report": [
{
"ID": "0000014",
"Age": "45",
"Details": [
{
"Status": "Approved",
"Name": "Joe"
},
{
"Status": "Approved",
"Name": "Bill"
},
{
"Status": "Submitted",
"Name": "Scott"
}
]
},
{
"ID": "10190476",
"Age": "40",
"Details": [
{
"Status": "Approved",
"Name": "Scott"
}
]
},
{
"ID": "10217480",
"Age": "40",
"Details": [
{
"Status": "Approved",
"Name": "Scott"
}
]
}
]
}
Here is my C# object:
public class Report
{
public List<WorkItem> Item= new List<WorkItem>();
}
public class WorkItem
{
public string ID { get; set; }
public int Age { get; set; }
public List<Details> Details { get; set; }
}
public class Details
{
public string Status { get; set; }
public string Name { get; set; }
}
Can someone advise what is wrong with my C# object definition to make this json deserialize correctly?
I would recommend using Json2Csharp.com to generate the classes.
public class Detail
{
public string Status { get; set; }
public string Name { get; set; }
}
public class Report
{
public string ID { get; set; }
public string Age { get; set; }
public List<Detail> Details { get; set; }
}
public class RootObject
{
public List<Report> Report { get; set; }
}
Try changing the Report class like so (The class name can be anything, the property must be Report)
public class WorkReport
{
public List<WorkItem> Report;
}
It should be trying to deserialize at the root into a class with an array/list of of workitem objects called Report.
You can try something like this. I have changed List to Dictionary You don't have a class defined at the root level. The class structure needs to match the entire JSON, you can't just deserialize from the middle. Whenever you have an object whose keys can change, you need to use a Dictionary. A regular class won't work for that; neither will a List.
public class RootObject
{
[JsonProperty("Report")]
public Report Reports { get; set; }
}
public class Report
{
[JsonProperty("Report")]
public Dictionary<WorkItem> Item;
}
public class WorkItem
{
[JsonProperty("ID")]
public string ID { get; set; }
[JsonProperty("Age")]
public int Age { get; set; }
[JsonProperty("Details")]
public Dictionary<Details> Details { get; set; }
}
public class Details
{
[JsonProperty("Status")]
public string Status { get; set; }
[JsonProperty("Name")]
public string Name { get; set; }
}
Then, deserialize like this:
Report results = _deserializer.Deserialize<Report>(restResponse);

JObject ToObject not Mapping

I have a part of some JSon that I am trying to map to a C# object. The rest of the JSon maps correctly to the object but only this part does not map anything and the objects values are null.
Here is the code that I am calling
var data = JObject.Parse(model.Data);
var dataModel = data.ToObject<MyModel>();
In MyModel I have this code
public class P
{
public string R { get; set; }
public IList<SavedSearch> SavedSearches { get; set; }
public class SavedSearch
{
public string A { get; set; }
public string B { get; set; }
public string CD { get; set; }
}
}
The corresponding JSon snippet is
"p": [
{
"r": "something",
"savedSearches": [
{
"saved-search": {
"#a": "blah",
"#b": "blahblah",
"#c-d": "blahblahblah"
}
}
]
}
]
R is correctly populated with the correct value, but A, B and CD are not. How must I change my C# model to fix this?
Your need to add an extra level of indirection for "saved-search", and also inform the serializer how to map the JSON property names to c# property names, since the JSON property names contain invalid characters (e.g. #) for c# properties. Thus:
[DataContract]
public class P
{
[DataMember(Name="r")]
public string R { get; set; }
[DataMember(Name="savedSearches")]
public IList<SavedSearch> SavedSearches { get; set; }
[DataContract]
public class SavedSearch
{
[DataMember(Name="saved-search")]
public SavedSearchItem SavedSearchItem { get; set; }
}
[DataContract]
public class SavedSearchItem
{
[DataMember(Name="#a")]
public string A { get; set; }
[DataMember(Name = "#b")]
public string B { get; set; }
[DataMember(Name = "#c-d")]
public string CD { get; set; }
}
}
And
public class MyModel
{
public List<P> p { get; set; }
}
When used as follows:
string json = #"
{""p"": [
{
""r"": ""something"",
""savedSearches"": [
{
""saved-search"": {
""#a"": ""blah"",
""#b"": ""blahblah"",
""#c-d"": ""blahblahblah""
}
}
]
}
]
}
";
var data = JObject.Parse(json);
var dataModel = data.ToObject<MyModel>();
Debug.WriteLine(JsonConvert.SerializeObject(dataModel, Formatting.Indented));
Produce
{
"p": [
{
"r": "something",
"savedSearches": [
{
"saved-search": {
"#a": "blah",
"#b": "blahblah",
"#c-d": "blahblahblah"
}
}
]
}
]
}
Incidentally, since you will be remapping the property names anyway, I'd suggest using more descriptive names in c# than R, A, B and CD.

How can you deserialize JSON data in C# (using DataContractJsonSerializer) without knowing all property names?

I have been using the DataContractJsonSerializer to convert data returned from the HubSpot API into strongly-typed objects, but I'm having some trouble with the user profile object.
In this example, I am able to get the Id and IsContact properties, but can't figure out how to get the list of properties since I don't know in advance what those can be. I would like to make Properties a Dictionary but I'm not sure how to do this. I don't care about the versions for each property, just the value.
This is a simplified example of the data that is returned by the API:
{
"vid": 72361,
"is-contact": true,
"properties": {
"city": {
"value": "Burlington",
"versions": [
{
"value": "Burlington",
"source-type": "SALESFORCE",
"source-id": "continuous",
"source-label": null,
"timestamp": 1384319976006,
"selected": false
}
]
},
"country": {
"value": "US",
"versions": [
{
"value": "US",
"source-type": "SALESFORCE",
"source-id": "continuous",
"source-label": null,
"timestamp": 1384319976006,
"selected": false
}
]
},
"company": {
"value": "Bridgeline Digital",
"versions": [
{
"value": "Bridgeline Digital",
"source-type": "SALESFORCE",
"source-id": "continuous",
"source-label": null,
"timestamp": 1384319976006,
"selected": false
}
]
}
}
}
This is the object I am trying to deserialize to:
[DataContract]
public class HubSpotUserProfile
{
[DataMember(Name = "vid")]
public int Id { get; set; }
[DataMember(Name = "is-contact")]
public bool IsContact { get; set; }
[DataMember(Name = "redirect")]
public string RedirectUrl { get; set; }
[DataMember(Name = "properties")]
public Dictionary<string, HubSpotUserProfileProperty> Properties { get; set; }
}
[DataContract]
public class HubSpotUserProfileProperty
{
[DataMember(Name = "value")]
public string Value { get; set; }
}
I call this method to perform the deserialization:
public static T Post<T>(string url, string postData) where T : class
{
string json = Post(url, postData);
if (!String.IsNullOrWhiteSpace(json))
{
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(json)))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
return (T)serializer.ReadObject(stream);
}
}
return null;
}
When I do this, no error is thrown, but Properties always has a Count of 0. Any idea on how I can accomplish this goal?
Use JsonObject type for your Properties property. In some very strange case DataContractJsonSerializer doesn't support Dictionary<> type in this case
If JSON.NET is an option then James has recently added ExtensionData support. See http://james.newtonking.com/archive/2013/05/08/json-net-5-0-release-5-defaultsettings-and-extension-data.
public class DirectoryAccount
{
// normal deserialization
public string DisplayName { get; set; }
// these properties are set in OnDeserialized
public string UserName { get; set; }
public string Domain { get; set; }
[JsonExtensionData]
private IDictionary<string, JToken> _additionalData;
[OnDeserialized]
private void OnDeserialized(StreamingContext context)
{
// SAMAccountName is not deserialized to any property
// and so it is added to the extension data dictionary
string samAccountName = (string)_additionalData["SAMAccountName"];
Domain = samAccountName.Split('\\')[0];
UserName = samAccountName.Split('\\')[1];
}
}
Depending on your chosen package for deserializing objects, your current models will work. We use JSon.Net for this exact purpose with HubSpot.
Here's samples of what we use...
[DataContract]
public class ContactHubSpotModel {
// snip for brevity
[DataMember(Name = "properties")]
public Dictionary<string, ContactProperty> Properties { get; set; }
}
[DataContract]
public class ContactProperty
{
[DataMember(Name = "value")]
public string Value { get; set; }
[DataMember(Name = "versions")]
List<ContactPropertyVersion> Versions { get; set; }
}
[DataContract]
public class ContactPropertyVersion
{
[DataMember(Name = "value")]
public string Value { get; set; }
[DataMember(Name = "source-type")]
public string SourceType { get; set; }
[DataMember(Name = "source-id")]
public string SourceId { get; set; }
[DataMember(Name = "source-label")]
public string SourceLabel { get; set; }
[DataMember(Name = "timestamp")]
public long Timestamp { get; set; }
[DataMember(Name = "selected")]
public bool Selected { get; set; }
}
Then you can dump a copy of your contact output into a file for validation like so...
string contactJson = GetContactString(); // pulls sample data stored in a .txt
ContactHubSpotModel contactModel = JsonConvert.DeserializeObject<ContactHubSpotModel>(contactJson);

Categories

Resources