How do I deserialize json string to object based on json content? - c#

How do I deserialize json string to object depends on json content?
I would like to do this with Newtonsoft.Json, since I am using it in the whole project and it is simple for use.
Let me explain by example:
I have json string which can have to be different property object. Content depends on the tool that generates the json files, and I cannot predict the content base on the filename or something like that.
For example, I can have json file:
{
"FileCreationDate":"29-08-2018 14:56:30",
"MessageType":2,
"Messages":[
{
"MessageSequenceNumber":1,
"ModalType":5,
"Message":{
"TransactionValue":5,
"ProductAmount":5
}
}
]
}
Or I can have something like this:
{
"FileCreationDate":"29-08-2018 14:56:30",
"MessageType":1,
"Messages":[
{
"MessageSequenceNumber":1,
"ModalType":5,
"Message":{
"TransactionBusinessDate":"29-08-2018 14:54:29",
"TransactionStatus":5,
"TicketNumber":5,
}
}
]
}
You can see that both json strings have same properties except message object in messages list.
I want to deserialize to this data structure:
public class EventFileDto
{
public string FileCreationDate { get; set; }
public MessageType MessageType { get; set; }
public IEnumerable<MessageDetailsDto> Messages { get; set; }
}
public class MessageDetailsDto
{
public int MessageSequenceNumber { get; set; }
public int ModalType { get; set; }
public EventMessageDto EventMessage { get; set; }
public TransactionMessage TransactionMessage { get; set; }
}
If json string is from the first example I want deserialize message object to EventMessage property, and TransactionMessage property should be null.
In the case of second json string, I want the opposite.
I don't want use dynamic type, since mapping to the entity would be more complicated.
How can this be done?
Thank you for your help.

Related

Why does Newtonsoft JsonConvert not deserialize Json array fields?

I am fetching a Json object which has a Details field that is an array of Detail objects, for example:
"details":"[{\"field_id\":\"1142488407\",\"response\":\"256\",\"field_type\":\"text\"},{\"field_id\":\"72403497\",\"response\":\"\",\"field_type\":\"text\"},{\"field_id\":\"845605582\",\"response\":\"Michael\",\"field_type\":\"text\"},{\"field_id\":\"987024660\",\"response\":\"157\",\"field_type\":\"dropdown\"}]"
The model I have for the Details field is:
[JsonProperty("details")]
public List<LogDetailModel> DetailModels { get; set; }
And the Detail object model is:
[JsonProperty("field_id")]
public string EditedFieldId { get; set; }
[JsonProperty("response")]
public string Response { get; set; }
[JsonProperty("field_type")]
public string FieldType { get; set; }
However, when I try to deserialize the results (an array of my base model), I get the following:
JsonSerializationException: Error converting value "[{"field_id":"1142488407","response":"256","field_type":"text"},{"field_id":"72403497","response":"","field_type":"text"},{"field_id":"845605582","response":"Michael","field_type":"text"},{"field_id":"987024660","response":"157","field_type":"dropdown"}]" to type 'System.Collections.Generic.List`1[KolHalev.Business.Breeze.Models.LogDetailModel]'. Path '[0].details', line 1, position 423.
And if I instead fetch that field as a string, and then deserialize thusly:
[JsonProperty("details")]
public string Details { get; set; }
public List<LogDetailModel> DetailModels { get { return JsonConvert.DeserializeObject<List<LogDetailModel>>(Details); } }
This works fine. What am I missing?
The reason why you could not deserialize it directly is because your json and your data model has a mismatch.
"details":"[{\"field_id\":\"1142488407\",\"response\":\"256\",\"field_type\":\"text\"},..]"
In this case your details data type is string
So, you can NOT parse it directly as a collection of objects
if your json would look like this:
"details":[{\"field_id\":\"1142488407\",\"response\":\"256\",\"field_type\":\"text\"},..]
the the data type of the details field would be a collection
So, the very reason why did your second approach worked is because you have first deserialized the details then you deserialized the json array.
try this
Details details = JsonConvert.DeserializeObject<Details>(json);
//Or more flexible
//Detail details = new Details
//{
// DetailsString = (string)JObject.Parse(json)["details"]
//};
classes
public class Details
{
[JsonProperty("details")]
public string DetailsString { get; set; }
public List<LogDetailModel> DetailModels { get { return JsonConvert.DeserializeObject<List<LogDetailModel>>(DetailsString); } }
}
public class LogDetailModel
{
[JsonProperty("field_id")]
public string EditedFieldId { get; set; }
[JsonProperty("response")]
public string Response { get; set; }
[JsonProperty("field_type")]
public string FieldType { get; set; }
}

string vs JRaw for JSON as a string

I have a JSON which has a property payload. It holds a JSON as a string like this.
// json schema
{
"id": "GUID",
"type": "some type",
"payload": "{\"name\": \"Smith\", \"age\": 30, ...}" // <- I get a json and serialize it to a string
}
// A C# class for the Json would be...
public class Item
{
public Guid Id { get; set; }
public CustomType Type { get; set; }
public string/JRaw/Anything else? { get; set; }
}
My question is what data type I should use for payload. string or JRaw can be used but
Is there anything else that's better than these types?
Is JRaw better than string? Why/Why not?
Item object will be returned by .NET Core API. A client app gets the response from the API then deserializes it to an object (Item).
payload value can be large. It can be more than 2 ~ 3MB or more.
Between JRaw and string this should be a string. JRaw is in Newtonsoft.Json.Linq namespace and this is not about Linq.
Having said that, you should just return the object:
public class Item<T>
{
public Guid Id { get; set; }
public CustomType Type { get; set; }
public T Data { get; set; }
}

parsing Json with weird attribute names [duplicate]

How can we parse if json fields contains a colon(:)? Like this:
{
"dc:creator":"Jordan, Micheal",
"element:publicationName":"Applied Ergonomics",
"element:issn":"2839749823"
}
In fact I wonder how to do this with a library like restsharp, for mapping?
Using Json.Net
string json = #"{
""dc:creator"":""Jordan, Micheal"",
""element:publicationName"":""Applied Ergonomics"",
""element:issn"":""2839749823""
}";
var pub = JsonConvert.DeserializeObject<Publication>(json);
public class Publication
{
[JsonProperty("dc:creator")]
public string creator { set; get; }
[JsonProperty("element:publicationName")]
public string publicationName { set; get; }
[JsonProperty("element:issn")]
public string issn { set; get; }
}
OR
Console.WriteLine(JObject.Parse(json)["dc:creator"]);
If you use DataContractJsonSerializer, DataMemberAttribute has property Name which can be used to override default name. This means that when you deserialize json value of property dc:creator is assigned to Publication::Creator property and on the contrary when you serialize C# object.
For example:
public class Publication
{
[DataMember(Name="dc:creator")]
public string Creator { set; get; }
[DataMember(Name="element:publicationName")]
public string PublicationName { set; get; }
[DataMember(Name="element:issn")]
public string Issn { set; get; }
}
If you choose to use Json.Net, #L.B's answer is the way to go.

Json Deserialisation with subarrays doesn't contain values

I am trying to deserialise a json object. The Problem is that the the object also contains subarrays
http://i.imgur.com/WWwEVLR.png
Except for the subarrays everything is working.
I am using Newtonsoft.Json;
Here is my class
public string date_updated { get; set; }
public string date_expires { get; set; }
This is working fine.
For the subarray I did it that way:
public JsonArray contacts { get; set; }
This is my method to deserialise it:
var json = await webClient.GetAsync(new Uri(uri));
var result = await json.Content.ReadAsStringAsync();
Model = JsonConvert.DeserializeObject<Model>(result);
The Array is created well with all fields needed, but the values are not working.
The values are just: Windows.Json.JsonObject as on the picture below.
http://i.imgur.com/Q8bpCoD.png
Why is he not writing the values? How can I get them?
Thank you for your help.
The values are working fine. Using JsonArray tells the deserializer to convert the JSON data to something that is compatible with the type JsonArray. This type is simply a 1:1 representation of the JSON string underneath and is not deserialized into useful data automatically for you.
Also, JsonArray is not even part of the Json.Net library. As the debugger is telling you, it is part of the Windows.Data.Json namespace which is in a different library. You could still access the data directly from each JsonObjects using the various Get methods inside the class ( http://msdn.microsoft.com/en-us/library/windows.data.json.jsonobject.aspx ) but this is probably not the way you want to go.
In your case, you should create a class that represents the data you have inside each of those arrays. If not all entries in the array contains all of the properties of your class, don't worry. Json.Net will simply leave their value empty when deserializing. This will look like:
public class Contact
{
public string type { get; set; }
public string name { get; set; }
public string organization { get; set; }
public string full_address { get; set; }
etc.
}
For good measure, you should also respect the C# naming convention which states that properties should use CamelCase names. To help you with this, you can use the JsonProperty attribute like so:
public class Contact
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("organization")]
public string Organization { get; set; }
[JsonProperty("full_address")]
public string FullAddress { get; set; }
etc.
}
Then, you can replace the type of your contacts property to List<Contact> and the data will be automatically deserialized to a format that you can easily use.
Define new class
class Contact {
public string type { get; set; }
public string name { get; set; }
// etc
}
and modify your ReqInfo_WhoIs_Model class
public string date_updated { get; set; }
public string date_expires { get; set; }
public List<Contact> contacts { get; set; }

Trying to deserialize JSON into object using JSON.NET

I cannot figure out why my model will not get populated with the data from my JSON string. Here is the model:
public class MidasReturnModel
{
public string status { get; set; }
public string msg { get; set; }
}
And here is my C# code:
MidasReturnModel rtn = JsonConvert.DeserializeObject<MidasReturnModel>(post_responseTemp);
And here is the JSON string post_responseTemp as it gets passed in to that function:
"{\"MidasReturnModel\": {\"status\":\"warn\", \"msg\":\"Customer does not have contract for this season\"}}"
Can anyone see what I am doing wrong? "rtn" is a Model with both status and msg being "null" when I run through the code.
Looking at your json, you are defining the MidasReturnModel in it.
When this is getting deserialized, it is looking for a property called MidasReturnModel on your class.
I would try your json as:
{
"status": "warn",
"msg": "Customer does not have contract for this season"
}
If you are wanting to keep your json the same, then it would have to be a case of wrapping your viewmodel in another class.
public class MidasWrapper
{
public MidasReturnModel MidasReturnModel { get; set; }
}
public class MidasReturnModel
{
public string status { get; set; }
public string msg { get; set; }
}
var rtn = JsonConvert.DeserializeObject<MidasWrapper>(post_responseTemp);

Categories