Deserialize JSON and assign to model - c#

As part of my web api, I'm getting the following JSON returned.
["{\"InputType\":17,\"EngineSubType\":4,\"Filename\":\"targetFile.csv\",\"FileExtensionType\":\".csv\",\"IsLoadFile\":true,\"LoadContextId\":4121,\"ReportingDate\":\"2019-05-31T00:00:00\",\"IsSuccess\":false}"]
What I'm wanting to do is grab the value next to Filenameand assign it to my models Filename parameter.
In my project I've created a unit test to experiment with grabbing that value, but each attempt I've making is failing.
In my test I have following DTO Model:
public class HangfireTestDTO
{
public string InputType { get; set; }
public string Filename { get; set; }
}
Then my text logic is this:
[Fact]
public void TestDTO()
{
string data =
"[\"{\\\"InputType\\\":12,\\\"EngineSubType\\\":2,\\\"Filename\\\":\\\"targetFile.csv\\\",\\\"FileExtensionType\\\":\\\".csv\\\",\\\"IsLoadFile\\\":true,\\\"LoadContextId\\\":4120,\\\"ReportingDate\\\":\\\"2019-05-31T00:00:00\\\",\\\"IsSuccess\\\":false}\"]";
// fails here
var arguments = System.Text.Json.JsonSerializer.Deserialize<HangfireTestDTO>(data);
// This is wrong - ignore for now
Assert.Equal("targetFile.csv", arguments.ToString());
}
When I debug the above in my test it tells me the following:
The JSON value could not be converted to MyProject.HangfireTestDTO
My thinking then led me to try again by modifying the deserialize line to the following:
var arguments = System.Text.Json.JsonSerializer.Deserialize<IEnumerable<HangfireTestDTO>>(data).FirstOrDefault();
But when running it with the new line, I get the following error:
The JSON value could not be converted to System.Collections.Generic.List
What is it I'm doing wrong?

Your current JSON string is an array of strings. You need to first deserialize the JSON into a list of strings, then deserialize each of those strings as a DTO. Here's a complete example using your JSON:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
public class HangfireTestDTO
{
public int InputType { get; set; }
public int EngineSubType { get; set; }
public string Filename { get; set; }
public string FileExtensionType { get; set; }
}
class Program
{
static void Main()
{
string data =
"[\"{\\\"InputType\\\":12,\\\"EngineSubType\\\":2,\\\"Filename\\\":\\\"targetFile.csv\\\",\\\"FileExtensionType\\\":\\\".csv\\\",\\\"IsLoadFile\\\":true,\\\"LoadContextId\\\":4120,\\\"ReportingDate\\\":\\\"2019-05-31T00:00:00\\\",\\\"IsSuccess\\\":false}\"]";
// First deserialize the single string to a list of strings
List<string> jsonStrings = JsonSerializer.Deserialize<List<string>>(data);
// Then deserialize each of the strings to a DTO.
List<HangfireTestDTO> dtos = jsonStrings
.Select(json => JsonSerializer.Deserialize<HangfireTestDTO>(json))
.ToList();
Console.WriteLine(dtos.Count);
Console.WriteLine(dtos[0].Filename);
}
}

firstly your JSON is wrong
i would expect it too look more like
string data = #"[{""InputType"":12,""EngineSubType"":2,""Filename"":""targetFile.csv"",""FileExtensionType"":"".csv"",""IsLoadFile"":true,""LoadContextId"":4120,""ReportingDate"":""2019-05-31T00:00:00"",""IsSuccess"":false}]"
or
string data = "[{\"InputType\":17,\"EngineSubType\":4,\"Filename\":\"targetFile.csv\",\"FileExtensionType\":\".csv\",\"IsLoadFile\":true,\"LoadContextId\":4121,\"ReportingDate\":\"2019-05-31T00:00:00\",\"IsSuccess\":false}]"
second you have wrapped your JSON in [] this means a list of docs so Deserialize<HangfireTestDTO>(data); would be Deserialize<List<HangfireTestDTO>>(data); or some other IEnumerable
then you have serveral data mismatches 12 is a number not a string so InputType should be an int or double, IsSuccess is a bool, etc
finally you have lots of fields in your JSON that aren't on your object you need to explain to c# what to do with them either create the extra properties or provide a KeyValue store it can put them in
ie
[JsonExtensionData]
public Dictionary<string, object> ExtensionData { get; set; }
EDIT following the comment you made if that is really how the data is coming out your DB then its an array of strings where the strings are JSON encoded
in which case you will need to read the strings then parse them after
var jsonlist = JsonSerializer.Deserialize<List<string>>(data);
foreach(string json in jsonlist )
var dto = JsonSerializer.Deserialize<HangfireTestDTO>(json);

The first error is because of InputType. It should be int
public class HangfireTestDTO
{
public int InputType { get; set; }
public string Filename { get; set; }
}
The second error is because of JSON. There is an addition quotation between [ and {. I have tried with below JSON and it worked. Because of this quotation it becomes List<string> and not List<HangfireTestDTO>
[
{
"InputType": 12,
"EngineSubType": 2,
"Filename": "targetFile.csv",
"FileExtensionType": ".csv",
"IsLoadFile": true,
"LoadContextId": 4120,
"ReportingDate": "2019-05-31T00:00:00",
"IsSuccess": false
}
]
And looking at the JSON it should be IEnumerable<HangfireTestDTO>
var arguments = JsonSerializer.Deserialize<IEnumerable<HangfireTestDTO>>(data);

Related

Extract specific data from JSON

I have the following code in my app (using Newton.Json):
var data = JsonConvert.DeserializeObject(responseValue).ToString();
Using the following code:
Console.WriteLine(data);
I get:
{
"result": "some random string goes here",
"error": null,
"id": "1"
}
How do I get the string from the result part of the JSON in the data variable, and put it into its own variable for later use?
If you have a C# class that corresponds to the "shape" of the JSON (same properties with the same data type):
public class ResponseType
{
public string Result { get; set; }
public string Error { get; set; }
public int Id { get; set; }
}
you can do:
ResponseType data = JsonConvert.DeserializeObject<ResponseType>(responseValue);
and then access each property of that class:
string result = data.Result;
This can be done without deserialization.
var json = JObject.Parse(responseValue);
var result = json["result"];
Open namespace.
using Newtonsoft.Json.Linq;

How do I parse JSON data which contains only arrays and nested arrays with no property names?

So I've looked around for tutorials on this and all the tutorials I've found doesn't have JSON that looks like the one I'm trying to parse.
I'm trying to parse JSON from this website https://www.steamcardexchange.net/api/request.php?GetBadgePrices_Guest
Since it doesn't have any identifiers for each thing like name, id etc I'm not sure how I will go about extracting data from it.
My only interest is really getting the first number of each item
[["449940","! That Bastard Is Trying To Steal Our Gold !"],5,"$0.64","1519294200"]
so what I want to extract from this item would be "449940".
This is what I've got so far
using (var client = new WebClient())
{
client.DownloadFile("https://www.steamcardexchange.net/api/request.php?GetBadgePrices_Guest", "data.json");
}
using (StreamReader r = new StreamReader("data.json"))
{
string json = r.ReadToEnd();
//Parse somehow
}
Any tips?
I took this up out of sheer curiosity because I had no idea how to parse this either. Perhaps there's a much better way.
I started by pasting a fragment of this into json2csharp.com.
The class it generates is
public class RootObject
{
public List<List<object>> data { get; set; }
}
From there I wrote some classes that correspond to what I think the data is supposed to look like. The names of the classes and properties are meaningless, so change them to whatever these actually represent.
public class OutputItem
{
public Message Message { get; set; }
public long Int64Value { get; set; } // 5
public string StringThatLooksLikeCurrency { get; set; } // "$0.64"
public string StringThatLooksNumeric { get; set; } // "1519294200"
}
public class Message
{
public string MessageId { get; set; } // "449940"
public string MessageText { get; set; } // "! That Dude..."
}
And finally, some sample code that takes a fragment of that JSON and converts it to a list of OutputItem. In order to figure this out I first deserialized the JSON to RootObject, then I inspected the deserialized object in the debugger to make sense of what it looked like.
var json = #"{ ""data"": [[[ ""449940"", ""! That Dude Is Trying To Steal Our Gold !"" ], 5, ""$0.64"", ""1519294200"" ], [[ ""303720"", ""#killallzombies"" ], 5, ""$0.56"", ""1519322799"" ]]}";
var parsed = JsonConvert.DeserializeObject<RootObject>(json);
var outputItems = new List<OutputItem>();
foreach (var listOfObject in parsed.data)
{
var outputItem = new OutputItem();
var message = (JArray) listOfObject[0];
outputItem.Message = new Message {MessageId = (string) message[0],
MessageText = (string) message[1]};
outputItem.Int64Value = (long) listOfObject[1];
outputItem.StringThatLooksLikeCurrency = (string) listOfObject[2];
outputItem.StringThatLooksNumeric = (string) listOfObject[3];
outputItems.Add(outputItem);
}

Deserializing json - wrong type

Here's how I try to deserialize my json:
new JavaScriptSerializer().Deserialize<Dictionary<int, MyModel>>(myData);
Here's the class:
public class MyModel
{
public Dictionary<int, ItemModel> Translation { get; set; }
public int Id { get; set; }
}
public class ItemModel
{
public string Name { get; set; }
public string ShortDescription { get; set; }
public string LongDescription { get; set; }
}
And here's the json:
"[[],[],{"Translation":{"1":{"Name":"Bla1","ShortDescription":"bla1","LongDescription":"bla1"},"2":{"Name":"BlaUS1","ShortDescription":"BlaUS1","LongDescription":"BlaUS1"}},"Id":"12"},{"Translation":{"1":{"Name":"Bla22","ShortDescription":"bla22","LongDescription":"bla22"},"2":{"Name":"Bla2US2","ShortDescription":"Bla2US2","LongDescription":"Bla2US2"}},"Id":"13"}]"
and I get the error that the type is not supported for deserialization of an array.
Where is my error?
First of all your JSON looks a bit wrong to me. It is and array of 4 elements and 1st two elements are empty arrays but other two objects? I suspect your JSON should be something like that:
"[{"Translation":{"1":{"Name":"Bla1","ShortDescription":"bla1","LongDescription":"bla1"},"2":{"Name":"BlaUS1","ShortDescription":"BlaUS1","LongDescription":"BlaUS1"}},"Id":"12"},{"Translation":{"1":{"Name":"Bla22","ShortDescription":"bla22","LongDescription":"bla22"},"2":{"Name":"Bla2US2","ShortDescription":"Bla2US2","LongDescription":"Bla2US2"}},"Id":"13"}]"
Another issue is that you have Dictionary<int, ItemModel> but for serialization/deserialization you must have key of String or Object type.
Working example (providing that you changed from Dictionary<int, ItemModel> to Dictionary<object, ItemModel>):
string input = "[{\"Translation\":{\"1\":{\"Name\":\"Bla1\",\"ShortDescription\":\"bla1\",\"LongDescription\":\"bla1\"},\"2\":{\"Name\":\"BlaUS1\",\"ShortDescription\":\"BlaUS1\",\"LongDescription\":\"BlaUS1\"}},\"Id\":\"12\"},{\"Translation\":{\"1\":{\"Name\":\"Bla22\",\"ShortDescription\":\"bla22\",\"LongDescription\":\"bla22\"},\"2\":{\"Name\":\"Bla2US2\",\"ShortDescription\":\"Bla2US2\",\"LongDescription\":\"Bla2US2\"}},\"Id\":\"13\"}]";
List<MyModel> myModels = new JavaScriptSerializer().Deserialize<List<MyModel>>(input);
Your string suggests that what you have is a JSON array, eg:- [1,2,3]
but you are trying to deserialize it into a dictionary for which the json representation is akin to
{"1":"Hai","2":"Hello"}
obviously the library is throwing an error. May be why dont you use the following to deserialize the string.
new JavaScriptSerializer().Deserialize<List<MyModel>[]>(myData)
However, to use it you can't have empty arrays in the json, you have to fill them with default values for the properties.
To prove that the above works, try
"[{"Translation":{"1":{"Name":"Bla1","ShortDescription":"bla1","LongDescription":"bla1"},"2": {"Name":"BlaUS1","ShortDescription":"BlaUS1","LongDescription":"BlaUS1"}},"Id":"12"},{"Translation":{"1":{"Name":"Bla22","ShortDescription":"bla22","LongDescription":"bla22"},"2":{"Name":"Bla2US2","ShortDescription":"Bla2US2","LongDescription":"Bla2US2"}},"Id":"13"}]"
with
new JavaScriptSerializer().Deserialize<List<MyModel>>(myData)

Parsing complex JSON text with Json.NET

I am writing a program to access Mediafire's web API and it's all going well, the only issue remaining is the response text in JSON format that I have difficulty parsing.
With API calls like creating a folder, I get a simple response which can be deserialized into a Dictionary<string,Dictionary<string,string>> and searched for values:
{"response":
{
"action":"folder\/create.php",
"name":"blargh",
"folder_key":"mmttuu769djo0",
"result":"Success",
"current_api_version":"2.14"
}
}
I would use it like this:
Dictionary<string,string> json = DeserializeJSON(text)["response"];
//DeserializeJSON is a method to shorten:
//JsonConvert.DeserializeObject<Dictionary<string,Dictionary<string,string>>(text)
I can then query for json["result"] and whatnot. With other API calls I get complex structures that I'm not sure how to handle. It's basically a bunch of key:value pairs, but some of the values are key:value pairs as well, which can't be put into a dictionary like I'm currently doing. I'm fairly new to C# so I'm not sure what to do here, is there some other data type like a Dictionary which doesn't have static types?
Here's the response:
{"response":
{
"action":"upload\/upload.php",
"doupload":
{
"result":"0",
"key":"89lh7760x4l"
},
"server":"live",
"result":"Success",
"current_api_version":"2.14"
}
}
My question would be: What is a good way to get this kind of data into a list that I can query for values?
What about creating a new class(s) to deal with the json? You can generate classes by using json2csharp using the example json.
public class Doupload
{
public string result { get; set; }
public string key { get; set; }
}
public class Response
{
public string action { get; set; }
public Doupload doupload { get; set; }
public string server { get; set; }
public string result { get; set; }
public string current_api_version { get; set; }
}
public class RootObject
{
public Response response { get; set; }
}
Then you can deserialise the json using:
JavaScriptSerializer serializer = new JavaScriptSerializer();
var something = serializer.Deserialize<RootObject>(jsonString);
I ended up finding out about the dynamic type - Deserializing the text into a Dictionary<string,dynamic> allows it to have multiple types where some can be dictionaries as well. I can query it as I would expect but I just need to be sure what values are returned with each API call, and I need to cast it to a string.
string upload_key = (string)json["response"]["doupload"]["key"] //89lh7760x4l

Parsing JSON data in C#

I have a JSON data as follows
{"id": "367501354973","from": {
"name": "Bret Taylor",
"id": "220439" }
which is returned by an object(result) of IDictionary[String, Object]
In my C# code:
I have made a class for storing the JSON value which is as follows
public class SContent
{
public string id { get; set; }
public string from_name { get; set; }
public string from_id { get; set; }
}
My main C# function which stores the parses the JSON data and stores the value inside the class properties is as follows:
List<object> data = (List<object>)result["data"];
foreach (IDictionary<string, object> content in data)
{
SContent s = new SContent();
s.id = (string)content["id"];
s.from_name = (string)content["from.name"];
s.from_id = (string)content["from.id"];
}
When i execute this code, i get an exception saying System cannot find the Key "from.name" and "from.id"
When i comment the two lines (s.from_name = (string)content["from.name"];s.from_id = (string)content["from.id"];) my code runs fine.
I think i am not able to refer the nested JSON data properly.
Can anyone just validate it and please tell me how to refer nested data in JSON in C#?
Thanks
I'm not sure how you are parsing the JSON string. Are you using a class in the Framework to do the deserialization?
You could use the JavaScriptSerializer Class defined in the System.Web.Script.Serialization Namespace (you may need to add a reference to System.Web.dll)
Using that class, you would write your code like this:
public class SContent
{
public string id { get; set; }
public SFrom from { get; set; }
}
public class SFrom
{
public string name { get; set; }
public string id { get; set; }
}
Then deserialization looks like this:
var json = new JavaScriptSerializer();
var result = json.Deserialize<SContent>(/*...json text or stream...*/);
See JavaScriptSerializer on MSDN. You might also want to check out this similar question.

Categories