I'm trying to convert a string of JSON data into a C# class object. However I'm having an issue with a small part of the JSON which is dynamic in nature.
The part of the JSON is below:
"contact": [{
"comment": null,
"type": {
"id": "cell",
"name": "Example name"
},
"preferred": true,
"value": {
"country": "7",
"formatted": "+7 (702) 344-3423-3",
"number": "3498908",
"city": "702"
}
},
{
"type": {
"id": "email",
"name": "Email example"
},
"preferred": false,
"value": "name#mail.com"
}]
C# classes
public class Value
{
public string country { get; set; }
public string formatted { get; set; }
public string number { get; set; }
public string city { get; set; }
}
public class Type
{
public string id { get; set; }
public string name { get; set; }
}
public class Contact
{
public string comment { get; set; }
public Type type { get; set; }
public bool preferred { get; set; }
public string value { get; set; }
}
C# Code
Contact contact = JsonConvert.DeserializeObject<Contact>(result);
The format of "value" changes depending on the contact information. Is it possible to map value both as a string and also class Value.
Thanks for any help that can be provided.
You can literally just use dynamic, i.e.
public dynamic value { get; set; }
If it looks like an object, it will be materialized as a JObject, which can be used via the dynamic API, so .value.country will work, etc. If it looks like an integer, bool or string: it will be materialized as such. Arrays will also be handled suitably. So: you can check whether .value is string, etc. Note that this won't use your Value type, and doing so is more complex, but: meh; you get the data. You can always switch that out manually.
It will also behave like this if you use object instead of dynamic, but then it is harder to access the inner properties.
Try
Contact contact = JsonConvert.DeserializeObject<Contact>(result[0]);
As you can see in the JSON, it's
"contact": [
Indicating an array, currently you're just passing the entire array
Unless you're sure that the JSON comes always with the same structure, the best is to use a dynamic variable instead of deserialize it into a class.
If you like to work with classes you can always build your own on runtime using reflection. But that's like killing a fly with a cannon and you're probably won't need it, so just use a dynamic variable instead, it's the best to work with JSON strings.
Related
This is the JSON im receiving, already filtered. (its coming from the google places autocomplete API)
{
"predictions": [
{
"description": "Frankfurt am Main, Deutschland",
"place_id": "ChIJxZZwR28JvUcRAMawKVBDIgQ",
},
{
"description": "Frankfurt (Oder), Deutschland",
"place_id": "ChIJb_u1AiqYB0cRwDteW0YgIQQ",
},
{
"description": "Frankfurt Hahn Flughafen (HHN), Lautzenhausen, Deutschland",
"place_id": "ChIJX3W0JgQYvkcRWBxGlm6csj0",
}
],
"status": "OK"
}
And I need to get this JSON into this format:
{
"success":true,
"message":"OK",
"data":[
{
"description":"Frankfurt Hahn Flughafen (HHN), Lautzenhausen, Deutschland",
"id":"ChIJX3W0JgQYvkcRWBxGlm6csj0"
},
{
"description":"Frankfurt Airport (FRA), Frankfurt am Main, Deutschland",
"id":"ChIJeflCVHQLvUcRMfP4IU3YdIo"
},
{
"description":"Frankfurt Marriott Hotel, Hamburger Allee, Frankfurt am Main, Deutschland",
"id":"ChIJdag3xFsJvUcRZtfKqZkzBAM"
}
]
}
I would be very g
So predictions is just renamed to "data", we change rename status to message, move it up and add a success if the http-request that happened earlier was a success or not. This does not seem so hard on the first catch, but I can't seem to find resources to transform or rearrange JSON in C#.
I would be very grateful for any tips or resources, so I can get unstuck on this probably not so difficult task. I should mention I'm fairly new to all of this.
Thank you all in advance!
First create classes thats represent your jsons
public class Prediction
{
public string description { get; set; }
public string place_id { get; set; }
}
public class InputJsonObj
{
public Prediction[] predictions { get; set; }
public string status { get; set; }
}
public class Datum
{
public string description { get; set; }
public string id { get; set; }
}
public class OutPutJsoObj
{
public bool success { get; set; }
public string message { get; set; }
public List<Datum> data { get; set; }
public OutPutJsoObj(){
data = new List<Datum>();
}
}
Then mapped objects (manually or using any of mapping libraries like AutoMapper) and create final json.
using Newtonsoft.Json;
InputJsonObj inputObj = JsonConvert.DeserializeObject<InputJsonObj >(inputJson);
OutPutJsoObj outObj = new OutPutJsoObj ();
foreach(var p in inputObj)
{
outObj.Data.Add(new Datum() { descriptions = p.descriptions , id= p.place_id }
}
string outJson = = JsonConvert.SerializeObject(outObj);
Just parse the origional json and move the data to the new json object
var origJsonObj = JObject.Parse(json);
var fixedJsonObj = new JObject {
new JProperty("success",true),
new JProperty("message",origJsonObj["status"]),
new JProperty("data",origJsonObj["predictions"])
};
it is not clear from your question what should be a success value, but I guess maybe you need this line too
if (fixedJsonObj["message"].ToString() != "OK") fixedJsonObj["success"] = false;
if you just need a fixed json
json = fixedJsonObj.ToString();
or you can create c# class (Data for example) and deserilize
Data result= fixedJsonObj.ToObject<Data>();
I like the answer from #Serge but if you're looking for a strongly typed approach we can model the input and output structure as the same set of classes and the output structure is similar, with the same relationships but only different or additional names this try this:
The process used here is described in this post but effectively we create write-only properties that will receive the data during the deserialization process and will format it into the properties that are expected in the output.
public class ResponseWrapper
{
[JsonProperty("success")]
public bool Success { get;set; }
[JsonProperty("message")]
public string Message { get;set; }
[Obsolete("This field should not be used anymore, please use Message instead")]
public string Status
{
get { return null; }
set
{
Message = value;
Success = value.Equals("OK", StringComparison.OrdinalIgnoreCase);
}
}
[JsonProperty("data")]
public Prediction[] Data { get;set; }
[Obsolete("This field should not be used anymore, please use Data instead")]
public Prediction[] Predictions
{
get { return null; }
set { Data = value; }
}
}
public class Prediction
{
public string description { get; set; }
public string place_id { get; set; }
}
Then you can deserialize and re-serialize with this code:
using Newtonsoft.Json;
...
var input = JsonConvert.DeserializeObject<ResponseWrapper>(input);
var output = JsonConvert.SerializeObject(objs, new JsonSerializerSettings
{
Formatting = Newtonsoft.Json.Formatting.Indented,
NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore
});
This is a fiddle you can test with: https://dotnetfiddle.net/DsI5Yc
And the output:
{
"success": true,
"message": "OK",
"data": [
{
"description": "Frankfurt am Main, Deutschland",
"place_id": "ChIJxZZwR28JvUcRAMawKVBDIgQ"
},
{
"description": "Frankfurt (Oder), Deutschland",
"place_id": "ChIJb_u1AiqYB0cRwDteW0YgIQQ"
},
{
"description": "Frankfurt Hahn Flughafen (HHN), Lautzenhausen, Deutschland",
"place_id": "ChIJX3W0JgQYvkcRWBxGlm6csj0"
}
]
}
If you were going to go to the trouble of writing a converter for the deserialization then I find this solution is a bit simpler. I tend to use this type of solution when exposing additional properties to allow legacy data to map into a the current code base.
keeps the mapping and logic contained within the class
tells developers still writing code against the deprecated structures about the change
You can also augment this and implement a global converter to omit obsolete properties which would give you full backwards compatibility until you update the source to stop sending the legacy structure. This is a fiddle of such a solution: https://dotnetfiddle.net/MYXtGT
Inspired by these posts:
JSON.Net Ignore Property during deserialization
Is there a way to make JavaScriptSerializer ignore properties of a certain generic type?
Exclude property from serialization via custom attribute (json.net)
Json.NET: Conditional Property Serialization
I am building chunk of code(generic) which will return list of property and values from any structure of object (either list or single object or list within single object or single object within list or list within list or single object within object) in json based on input request.
Let me explain you the use case- I am getting list of properties in accordance with class name and I need to send back its values in json in list format.
For e.g. I am getting input request for following properties SPTeam.Name, SPRole.Name, SPTeam.AltName1, Client.Name and I want to process data retrieved from DB and send its values in list format in json like,
{
"SPTeam":[
{
"Name": "AUBERT & DUVAL Development",
"AltName1": "AUBERT & DUVAL Development",
"SPRole" : [
{
"Name": "Charter Full Stack Developer II"
},
{
"Name": "General Consulting Engineer"
}]
},
{
"Name": "SmartHands_Dedicated_Team",
"AltName1": "SmartHands_Dedicated_TeamAltName1",
"SPRole" : [
{
"Name": "Accountant"
},
{
"Name": "Senior accountant"
}]
}],
"Client" : [
{
"Name": "Davita Medical Group"
}
]}
The data model or the structure from which I need to get properties and values is-
Public class SPTeam
{
public int id { get; set; }
public string Name { get; set; }
public string AltName1 { get; set; }
public string AltName2 { get; set; }
public List<SPRole> SPRole { get; set; }
}
Public class SPRole
{
public int id { get; set; }
public string Name { get; set; }
public int AvgCostHr { get; set; }
public int SellPriceHr { get; set; }
public int GPPct { get; set; }
}
Public class Client
{
public int id { get; set; }
public string Name { get; set; }
}
The data model or structure and its relationship with other classes is dynamic (not any fixed class) and I need to retrieve data only for specific properties maintaining association/relationships between them.
Any help would be appreciated...
Thanks,
Well, it seems that a core portion of your question may be resolved by the following:
How to create json structure from list of data?
However, in your case I'm not sure what level of generic capability you are requiring. You mention that "The data model or structure and its relationship with other classes is DYNAMIC (not any fixed class)" on the one hand, then you mention: "I need to retrieve data only for SPECIFIC PROPERTIES maintaining association/relationships between them".
What is the level of generic capability between, what seems to me, to be conflicting requirements? If you only want to retrieve specific properties, then where are you tracking the properties (and associated class structures) you want to retrieve?
I believe the answer you're looking for will depend on how you answer this.
This question already has answers here:
Deserialize JSON with C#
(10 answers)
Closed 5 years ago.
So I'm creating an endpoint using a data model called Chat that will accept data in this JSON form and store it in the database.
[{
"ID": "123456",
"Chat": [{
"ID": "1",
"Message": "User: that's a nice car Dylan: thanks",
"PostedBy": "Dylan",
"PostedOn": "2018-01-23T18:25:43.511Z"
},
{
"ID": "2",
"Message": "User: that's a really nice car Terry: thanks ",
"PostedBy": "Terry",
"PostedOn": "2018-02-23T18:25:43.511Z"
},
{
"ID": "3",
"Message": "User: that's the best car Roger: thanks",
"PostedBy": "Roger",
"PostedOn": "2018-03-23T18:25:43.511Z"
}
]
}]
This is what I have currently and when I send data to the endpoint it only stores the ID, and nothing else in the database. Any thoughts/guidance is appreciated on how I could alter my model to accept the entirety of the data that is being sent.
public class Chat
{
public string ID { get; set; }
public string message { get; set; }
public string postedBy { get; set; }
public DateTime? postedOn { get; set;}
}
I may be wrong here, but it seems to me like you're using a class that represents a single message-instance (the class Chat) to attempt to store a whole list of Chat-data.
If I'm right, the only reason it actually stores ID is that it by chance happens to have the same name for two different levels in your data; one for the outer list (the whole set - and this is what is stored), and one for each of the inner chat-items.
Try to add this class, and use that instead (or rather in addition, since it actually contains a list of instances of your already existing class Chat):
public class ChatThread
{
public string ID { get; set; }
public IEnumerable<Chat> Chat { get; set; }
}
The ID which is being stored on your object is not the ID from the Chat object, but rather the higher ID definition which is common to your Chat objects.
You're were really close, if we discount the fact that you have not taken into consideration that C# is a case-sensitive language.
The "higher" layer is composed of a String ID, but also of an array of Chat objects, so you should create a Class that holds the definition of these two properties.
public class JsonClass
{
public string ID { get; set; }
public Chat[] Chat { get; set; }
}
public class Chat
{
public string ID { get; set; }
public string Message { get; set; }
public string PostedBy { get; set; }
public DateTime PostedOn { get; set; }
}
Since there exist multiple Chat objects for the JsonClass ID property, you have to make it into a collection of some sort. I chose an array, but you can use other Collection objects, such as a List.
I'm trying to parse the following json array
[
{
"email": "john.doe#sendgrid.com",
"timestamp": 1337197600,
"smtp-id": "<4FB4041F.6080505#sendgrid.com>",
"event": "processed"
},
{
"email": "john.doe#sendgrid.com",
"timestamp": 1337966815,
"smtp-id": "<4FBFC0DD.5040601#sendgrid.com>",
"category": "newuser",
"event": "clicked"
},
{
"email": "john.doe#sendgrid.com",
"timestamp": 1337969592,
"smtp-id": "<20120525181309.C1A9B40405B3#Example-Mac.local>",
"event": "processed"
}
]
I've not really used json format before, so it's all a little new. I found I can parse a single element easily, i.e.
{
"email": "john.doe#sendgrid.com",
"timestamp": 1337197600,
"smtp-id": "<4FB4041F.6080505#sendgrid.com>",
"event": "processed"
}
dynamic stuff = JsonConvert.DeserializeObject(json);
Response.Write(string.Format("{0} = {1}<br />", "timestamp", stuff.timestamp));
//etc
But i'm struggling with how to get the individual elements into an array to loop through.
I though about splitting the sting on },{ but didn't have much luck with that. I imagine there's an easier way i'm missing.
Thank you.
Just deserialize the JSON as is and loop it...
dynamic stuff = JsonConvert.DeserializeObject(json);
foreach (var s in stuff)
{
Console.WriteLine(s.timestamp);
}
Fiddle: http://dotnetfiddle.net/0SthDp
You can create a class like this one, to accept all properties from the json string:
public class MyClass
{
public string email { get; set; }
public long timestamp { get; set; }
[JsonProperty("smtp-id")]
public string smtpid { get; set; }
public string category { get; set; }
[JsonProperty("event")]
public string evt { get; set; }
}
As you can notice there is JsonProperty attribute on the smtpid and evt properties, because you can not use the names in the json string as properties in C#.
Then just call the following line:
var list = JsonConvert.DeserializeObject<List<MyClass>>(json);
and you'll get a strongly typed list of objects that matches the json string.
Use JSON.Net to do this for you:
Create a class to hold the data (notice the attribute I put on smtp-id to handle characters C# doesn't like):
public class EmailEvent
{
public string Email { get; set; }
public int TimeStamp { get; set; }
[Newtonsoft.Json.JsonProperty(PropertyName="smtp-id")]
public string SmtpId { get; set; }
public string Event { get; set; }
public string Category { get; set; }
}
Then just deserialize it:
var events = Newtonsoft.Json.JsonConvert.DeserializeObject<List<EmailEvent>>(System.IO.File.ReadAllText(#"z:\temp\test.json"));
foreach (var ev in events)
{
Console.WriteLine(ev.SmtpId);
}
Create these two classes to hold your data:
public class SMTPEvent {
public string Email { get; set; }
public long TimeStamp { get; set; }
public string SmtpId { get; set; }
public string EventType { get; set; }
}
public class SMTPEvents {
public List<SMTPEvent> Events { get; set; }
}
Then you can call the following:
dynamic stuff = JsonConvert.DeserializeObject<SMTPEvents>(json);
To iterate you can then use:
foreach(SMTPEvent sEvent in stuff)
{
//whatever you want to do.
}
The advantage to this approach is having more type safety at run-time whilst having reusable objects if you're going to use them in other parts of your system. If not, you might want to use the simpler dynamic approach as suggested by others.
Also, remember to use the JsonProperty attribute to specify the actual property name as specified in your JSON string if you cannot / are not going to create fields that have the exact name as in your JSON.
The first level - stuff - is an Array of objects. It is the objects, or elements in said array, which contain a timestamp field.
Consider the following:
dynamic items = JsonConvert.DeserializeObject(json);
foreach(dynamic item in items) {
/* use item.timestamp */
}
I've been trying to figure out why some of my tests haven't been working (TDD) and managed to track it down to serialization of a class, but I'm not sure why it's not working. There are two flavours, a simple version and a more complex version, the slightly more complicated one involves having an array of values within the Parameter.Value.
The simple version, I've got a class that can be serailzied using the JavaScriptSerializer (I'm assuming this is how MVC works when it generates JSON). The structure it produces looks like this:
{
"Name": "TestQuery",
"QueryId": 1,
"Parameters": [
{
"Name": "MyString",
"DataType": 0,
"Value": "A String",
"IsArray": false
}],
"Sql": "SELECT * FROM Queries"
}
There are 3 C# classes Query, ParameterCollection (which is a KeyedCollection<String, Parameter>) and a Parameter. All of these are marked up with DataContract/DataMember attributes and serialize via the DataContractSerializer without any problem.
The JavaScriptSerializer however, serializes the object correctly to the JSON above, but upon deserialization I have no Parameters, they just seem to get missed off.
Does anyone have any idea why these fails, and what I might be able to do to fix it?
Why KeyedCollection<String, Parameter>? You have an array, not dictionary, so your JSON should match the following structure:
public class Query
{
public int QueryId { get; set; }
public string Name { get; set; }
public string Sql { get; set; }
public Parameter[] Parameters { get; set; }
}
public class Parameter
{
public string Name { get; set; }
public int DataType { get; set; }
public string Value { get; set; }
public bool IsArray { get; set; }
}
and then you will be able to deserialize it without any problems:
var serializer = new JavaScriptSerializer();
var json = #"
{
""Name"": ""TestQuery"",
""QueryId"": 1,
""Parameters"": [
{
""Name"": ""MyString"",
""DataType"": 0,
""Value"": ""A String"",
""IsArray"": false
}],
""Sql"": ""SELECT * FROM Queries""
}";
var query = serializer.Deserialize<Query>(json);
Also you can get rid of [Data*] attributes from your view models, they are not used by the JavaScriptSerializer class.