How to Deserialize Json Array - c#

I have a Json Response to deserialize, after doing the deserialize I get error.
This is the Json array I want to deserialize:
{
"status": 200,
"success": true,
"message": "Success",
"data": [
{
"transaction_reference": "REF202301031128311645_1",
"virtual_account_number": "1234567890",
"principal_amount": "200.00",
"settled_amount": "199.80",
"fee_charged": "0.20",
"transaction_date": "2023-01-03T00:00:00.000Z",
"transaction_indicator": "C",
"remarks": "Transfer FROM Transfer | [1234567] TO Merchant Name",
"currency": "NGN",
"alerted_merchant": false,
"merchant_settlement_date": "2023-01-03T10:29:25.847Z",
"frozen_transaction": null,
"customer": {
"customer_identifier": "1234567"
}
}
]
}
From the Array, I want to get the following as variable:
status,
transaction_reference,
Virtual_account_number,
principal_amount,
customer_identifier,
below is what I tried:
string data = response.Content;
string dataT = data.Replace("", string.Empty);
dynamic stuff = JObject.Parse(dataT);
dynamic status = stuff.status;
var JsonResponse = stuff.data;
var ResponseX = JsonNode.Parse(JsonResponse); // Deserializing json Array
dynamic transaction_reference = ResponseX[0]["transaction_reference"];
dynamic virtual_account_number = ResponseX[1]["virtual_account_number"];
dynamic principal_amount = ResponseX[2]["principal_amount"];
dynamic customer = ResponseX[13]["customer_identifier"];
dynamic customer_identifier = customer.customer_identifier;
The error I got is as below
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException
HResult=0x80131500 Message=The best overloaded method match for
'System.Text.Json.Nodes.JsonNode.Parse(ref
System.Text.Json.Utf8JsonReader,
System.Text.Json.Nodes.JsonNodeOptions?)' has some invalid arguments
Source= StackTrace:
The error occurred at the line
var ResponseX = JsonNode.Parse(JsonResponse); // Deserializing json Array
What I really want achieve is to separate the following and get each as variable:
status,
transaction_reference,
Virtual_account_number,
principal_amount,
customer_identifier,
Please can someone point to me where my error is?

you have too much code that you don't need, if you don't want to deserialize to c# class, you can do it this way too
var ResponseX = JsonNode.Parse(response.Content); // Parse the response string
int status= (int)ResponseX["status"];
var data=ResponseX["data"][0];
string transaction_reference = (string) data["transaction_reference"];
string virtual_account_number = (string) data["virtual_account_number"];
string principal_amount = (string) data["principal_amount"];
string customer = (string) data["customer_identifier"];
int customer_identifier = Convert.ToInt32 ((string) data["customer"]["customer_identifier"]);
another way is to deserialize data to c# class
Datum d = System.Text.Json.JsonSerializer.Deserialize<Datum>(data.AsObject());
string transaction_reference = d.transaction_reference;
string virtual_account_number = d.virtual_account_number;
int customer_identifier = Convert.ToInt32( d.customer.customer_identifier);
public class Datum
{
public string transaction_reference { get; set; }
public string virtual_account_number { get; set; }
public string principal_amount { get; set; }
public string settled_amount { get; set; }
public string fee_charged { get; set; }
public DateTime transaction_date { get; set; }
public string transaction_indicator { get; set; }
public string remarks { get; set; }
public string currency { get; set; }
public bool alerted_merchant { get; set; }
public DateTime merchant_settlement_date { get; set; }
public object frozen_transaction { get; set; }
public Customer customer { get; set; }
}
public class Customer
{
public string customer_identifier { get; set; }
}

It would be nice to know what the specific error is but from inspecting the JSON it looks like you are stepping into the wrong parent node.
Try
dynamic transaction_reference = ResponseX["data"][0]["transaction_reference"];
dynamic virtual_account_number = ResponseX["data"][1]["virtual_account_number"];
dynamic principal_amount = ResponseX["data"][2]["principal_amount"];
dynamic customer = ResponseX["data"][13]["customer_identifier"];
dynamic customer_identifier = customer.customer_identifier;
Also, make sure the array has at least 14 entries under the parent data.

You are passing an invalid into JsonNode.Parse().
The error is thrown at runtime because you use dynamic as type and the compiler does not know the type at compile time.
In line dynamic stuff = JObject.Parse(dataT); you are using Newtonsoft to parse the data.
In Line var JsonResponse = stuff.data; you are writing a variable of type Newtonsoft.Json.Linq.JArray.
Then you try to call JsonNode.Parse(JsonResponse); which is not possible with the given argument, because the type of JsonResponse is not valid.
You will get this error on compile time, when you use the "real" types instead of dynamic.
To fix your issue, you should use the same function for parsing.

Related

How can parse dynamic json in c#?

Have some json and parse that whit this code:
dynamic json = JsonConvert.DeserializeObject(response.Content);
dynamic result =json.result;
after this line:
dynamic result =json.result;
have this output:
{
{
"321":{
"online_status":true,
"basic_info":{
"status":"Recharged",
"group_name":"IRN-UV002-M01",
"isp_name":"Main",
"creation_date":"2017-09-05 08:19:32",
"recharge_deposit":0.0,
"user_id":321,
"nearest_exp_date":"2018-02-22 10:21:00",
"credit":20387.775145462037,
"deposit":0.0,
"isp_id":0,
"group_id":72
},
"user_repr":"10001168-2100104f4Y8-FTTH",
}
}
}
and now want to get user_id from that json,how can i write code for that purpose?thanks.
The better way would be to deseralize this into a strongly typed object.
But for you you can use the JObject class to do something like the following (note not tested, but you should understand the concept):
dynamic result = JObject.Parse(source);
int id = result.321.basic_info.user_id;
You probably want to do something like this:
var yourInstance = JsonConvert.DeserializeObject<YourClass>(responseJson);
For that, you need to define a class YourClass and related sub-classes which have properties matching the values returned in the JSON data, i.e. something like:
public class YourClass {
public bool online_status { get; set; }
public BasicInfo basic_info { get; set; }
public string user_repr { get; set; }
}
public class BasicInfo {
public string status { get; set; }
public string group_name{ get; set; }
public string isp_name{ get; set; }
public DateTime creation_date{ get; set; }
public string group_name{ get; set; }
// ...etc.
}
With this in place, JsonConvert should be able to understand and parse your data to the correct object.
This is just a rough example, but it should get you on your way.
Another way is to use JObject to hold the string.
var str = "{\"321\":{\"online_status\":true,\"basic_info\":{\"status\":\"Recharged\",\"group_name\":\"IRN-UV002-M01\",\"isp_name\":\"Main\",\"creation_date\":\"2017-09-05 08:19:32\",\"recharge_deposit\":0.0,\"user_id\":321,\"nearest_exp_date\":\"2018-02-22 10:21:00\",\"credit\":20387.775145462037,\"deposit\":0.0,\"isp_id\":0,\"group_id\":72},\"user_repr\":\"10001168-2100104f4Y8-FTTH\"}}";
var obj = JObject.Parse(str);
var userId = obj["321"]["basic_info"]["user_id"].ToString();

Unable to use JSON data with Newtonsoft.Json in WPF

I am retrieving data from office365 api. The response is in JSON format. I want to get data like Id, DisplayName etc. into variables but not getting the right way to do it. Following this link. I'm new to API and JSON. Will Appreciate pointers as well towards best learning links.Sample JSON below for listing sub folders of Inbox folder.
Response JSON data.
{"#odata.context":"https://outlook.office365.com/api/v1.0/$metadata#Me/Folders('Inbox')/ChildFolders","value":
[
{"#odata.id":"https://outlook.office365.com/api/v1.0/Users('sample.user#demosite.com')/Folders('AAMkADBjMGZiZGFlLTE4ZmEtNGRlOS1iMjllLTJmsdfsdfdDSFSDFDFDF=')",
"Id":"AAMkADBjMdfgdfgDFGDFGDFGdfGDFGDFGDFGGDzrACAAB4xqMmAAA=",
"DisplayName":"SampleFolder","ParentFolderId":"AAMkADBjMGZiZGFlLTE4ZmEtNGRlOS1sdsDFSDFSDFSDFSDFSDFDFDFrACAAAAAAEMAAA=","ChildFolderCount":0,"UnreadItemCount":8,"TotalItemCount":94},
{"#odata.id":"https://outlook.office365.com/api/v1.0/Users('sample.user#demosite.com')/Folders('AAMkADBjMGZiZGFlLTE4ZmEasdasdasdASDASDASDASDSADDASDASDAB4xqMnAAA=')",
"Id":"AAMkADBjMGZiZGFlLTE4ZmEtNGRlOS1iMjllLTJmOGZkNGRhZmIzNQAuAasdASDASDASDASEDASDASDxSEHjzrACAAB4xqMnAAA=",
"DisplayName":"AnotherSampleFolder","ParentFolderId":"AAMkADBjMGZiZGFlLTE4ZmEtNGRlOS1sdsDFSDFSDFSDFSDFSDFDFDFrACAAAAAAEMAAA=","ChildFolderCount":0,"UnreadItemCount":21,"TotalItemCount":75}
]
}
The C# code using to parse JSON and find the required data.
HttpResponseMessage response = httpClient.SendAsync(request).Result;
if (!response.IsSuccessStatusCode)
throw new WebException(response.StatusCode.ToString() + ": " + response.ReasonPhrase);
string content = response.Content.ReadAsStringAsync().Result;
JObject jResult = JObject.Parse(content);
if (jResult["odata.error"] != null)
throw new Exception((string)jResult["odata.error"]["message"]["value"]);
//Attempt one - using dynamic [NOT WORKING - getting NULL values in the variables]
dynamic results = JsonConvert.DeserializeObject<dynamic>(content);
var folderName = results.Id;
var folderId = results.Name;
//Attempt two - [Not working - Throwing exception -
//Object reference not set to an instance of an object.]
var folderID = (string)jResult["odata.context"]["odata.id"][0]["Id"];
First create a class for your json object
public class RootObject
{
[JsonProperty(PropertyName = "#odata.context")]
public string context { get; set; }
public List<Value> value { get; set; }
}
public class Value
{
[JsonProperty(PropertyName = "#odata.id")]
public string dataId { get; set; }
public string Id { get; set; }
public string DisplayName { get; set; }
public string ParentFolderId { get; set; }
public int ChildFolderCount { get; set; }
public int UnreadItemCount { get; set; }
public int TotalItemCount { get; set; }
}
Then Json Convert the Json string to your RootObject if your are using Newtonsoft Json then Deserilaze by using
RootObject shortiee = JsonConvert.DeserializeObject<RootObject>("Your Json String");
private List<string> GetDisplayNames(JObject content)
{
var obj = Json.Parse(content);
var values = obj["value"].ToList();
var displayNames = new List<string>();
foreach (var value in values)
{
displayNames .Add(system["DisplayName"].ToString());
}
return displayNames;
}
This would return the names, for example, and you could do this for each value you need to retrieve. However, this does not require you to serialize/deserialize the json object before using it. It works, but is most likely not best practice.
if (jResult["odata.error"] != null)
throw new Exception((string)jResult["odata.error"]["message"]["value"]);
//Attempt one - using dynamic [NOT WORKING - getting NULL values in the variables]
dynamic results = JsonConvert.DeserializeObject<dynamic>(content);
Side note: There is no key called "odata.error" in your JSON data. So you're effectively calling something which will return null.
One of the ways to deserialise JSON is to create model classes for the objects you want to process and deserialise into them directly, eg. JsonConvert.DeserializeObject<Folder>(content). As you are talking to an Office365 API, you find documentation and examples here on how they are defined.
Taken your folder response as an example, your model for a single Folder could look like this:
public class Folder
{
[JsonProperty(PropertyName = "#odata.id")]
public string OdataId { get; set; }
public string Id { get; set; }
public string DisplayName { get; set; }
public string ParentFolderId { get; set; }
public int ChildFolderCount { get; set; }
public int UnreadItemCount { get; set; }
public int TotalItemCount { get; set; }
}
Note1: in your example, you get a response with list of folders, so have to adjust this accordingly.
Note2: you can use JsonProperty to define a mapping between a JSON property/key and a C# property as shwon for #odata.id.
However, you can also use the Outlook Client Library which would make it mostly unnecessary to deal with JSON data directly (which seems preferable, unless you have a very specific reason to deal with JSON directly).

Getting an exception when trying to deserialize JSON and display the results in a DataGridView

I have some C# code where I get JSON data from an API. The JSON looks like this:
{
"count": 32696,
"results": [{
"data_id": 0,
"name": "Extended Potion of Ghost Slaying",
"rarity": 0,
"restriction_level": 0,
"img": "",
"type_id": 0,
"sub_type_id": 0,
"price_last_changed": "2013-03-18 17:00:31 UTC",
"max_offer_unit_price": 0,
"min_sale_unit_price": 0,
"offer_availability": 0,
"sale_availability": 0,
"sale_price_change_last_hour": 0,
"offer_price_change_last_hour": 0
}]
}
(There is more than just one item in the results though.)
I have made 2 classes like this:
internal class MyClass
{
public int data_id { get; set; }
public string name { get; set; }
public int rarity { get; set; }
public int restriction_level { get; set; }
public string img { get; set; }
public int type_id { get; set; }
public int sub_type_id { get; set; }
public string price_last_changed { get; set; }
public int max_offer_unit_price { get; set; }
public int min_sale_unit_price { get; set; }
public int offer_availability { get; set; }
public int sale_availability { get; set; }
public int sale_price_change_last_hour { get; set; }
public int offer_price_change_last_hour { get; set; }
}
internal class RootObject
{
public int count { get; set; }
public List<MyClass> results { get; set; }
}
And here is the part where I get the JSON and deserialize it:
using (WebClient wc = new WebClient())
{
string URI = "a good url";
wc.Headers.Add("Content-Type", "text");
string HtmlResult = wc.DownloadString(URI);
MyClass[] result = JsonConvert.DeserializeObject<MyClass[]>(HtmlResult);
DataTable dt = (DataTable)JsonConvert.DeserializeObject(HtmlResult, (typeof(DataTable)));
this.dataGridView1.DataSource = dt;
}
But when I run this code I get an error:
Additional information: Cannot deserialize the current JSON object
(e.g. {"name":"value"}) into type 'gwspiderv2.MyClass[]' because the
type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
I already use this type of code on another API without errors. What am I doing wrong?
In your code it seems you are trying to deserialize the same JSON two different ways, which doesn't make a whole lot of sense:
MyClass[] result = JsonConvert.DeserializeObject<MyClass[]>(HtmlResult);
DataTable dt = (DataTable)JsonConvert.DeserializeObject(HtmlResult, (typeof(DataTable)));
You are getting the first error (in your question) because your JSON represents a single object, but you are trying to deserialize it into an array of MyClass. You have defined a RootObject class, but you are not using it. It seems that you should be, because it fits your JSON.
You are getting the second error (in the comments to #inan's answer) because the JSON is in the wrong format to be deserialized into a DataTable. Presumably you are trying to do that so you can display the data in your DataGridView. But you don't need to convert it to a DataTable in order to use it as a data source. You can just give your DataGridView an IList, which you already have in your RootObject.
Change your code to this:
RootObject result = JsonConvert.DeserializeObject<RootObject>(HtmlResult);
this.dataGridView1.DataSource = result.results;
Use RootObject for deserializing as below, it has the List of MyClass
RootObject result = JsonConvert.DeserializeObject<RootObject>(HtmlResult);

Turn string into json C#

I have this sample code that i am working with. The json is a result of the http post.
var json = #"{'user': {
'country':'US',
'email':'testapi#example.com',
'first_name':'Test',
'last_name':'API',
'phone':null,
'zip':null,
'login_url':'https://new.site.com/xlogin/12325/abd9832cd92'
}
}";
var jsonSerializer = new JavaScriptSerializer();
var itemsList = (IDictionary<string, object>)jsonSerializer.DeserializeObject(json);
var url = itemsList["user.login_url"];
On itemsList["user.login_url"] i am getting the following error:
The given key was not present in the dictionary.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
Source Error:
Line 545: var jsonSerializer = new JavaScriptSerializer();
Line 546: var itemsList = (IDictionary<string, object>)jsonSerializer.DeserializeObject(json);
Line 547: var url = itemsList["user.login_url"];
Line 548: }
Line 549:
Am i doing something wrong here? How should i access the first name, last name and url etc from this object?
Alternately, how can i tie this result to a class that has following properties? I just need a pointer to a good resource.
public class User
{
public string Country { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Phone { get; set; }
public string Zip { get; set; }
public string LoginUrl { get; set; }
}
Thanks.
Well I really don't understand why u are using IDictionary to parse json object.
Use Newtonsoft.Json instead of jsonSerializer much more essay to use.
Go on http://json2csharp.com/ and generate your class to define you json (copy json and result is C# class).
Now tie your json to new RootObject not user:
using System;
using Newtonsoft.Json;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var json = #"{'user': {
'country':'US',
'email':'testapi#example.com',
'first_name':'Test',
'last_name':'API',
'phone':null,
'zip':null,
'login_url':'https://new.site.com/xlogin/12325/abd9832cd92'
}
}";
RootObject userObj = JsonConvert.DeserializeObject<RootObject>(json.ToString());
}
}
//generated with http://json2csharp.com/
public class User
{
public string country { get; set; }
public string email { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public object phone { get; set; }
public object zip { get; set; }
public string login_url { get; set; }
}
public class RootObject
{
public User user { get; set; }
}
}
"user.login_url" is the property path you'd expect to use in JavaScript ... try accessing the dictionary keys instead
var user = itemsList["user"] as IDictionary<string,object>;
var url = user["login_url"] as string;
itemsList["user"] contains a second Dictionary. So you can navigate down to the login_url variable using
var user = (IDictionary<string, object>)itemsList["user"];
var login_url = user["login_url"];
Try using http://json.net/ it will give you a Dictionary with the types you want..

Parsing Json facebook c#

I am trying for many hours to parse a JsonArray, I have got by graph.facebook, so that i can extra values. The values I want to extract are message and ID.
Getting the JasonArry is no Problem and works fine:
[
{
"code":200,
"headers":[{"name":"Access-Control-Allow-Origin","value":"*"}],
"body":"{
\"id\":\"255572697884115_1\",
\"from\":{
\"name\":\"xyzk\",
\"id\":\"59788447049\"},
\"message\":\"This is the first message\",
\"created_time\":\"2011-11-04T21:32:50+0000\"}"},
{
"code":200,
"headers":[{"name":"Access-Control-Allow-Origin","value":"*"}],
"body":"{
\"id\":\"255572697884115_2\",
\"from\":{
\"name\":\"xyzk\",
\"id\":\"59788447049\"},
\"message\":\"This is the second message\",
\"created_time\":\"2012-01-03T21:05:59+0000\"}"}
]
Now I have tried several methods to get access to message, but every method ends in catch... and throws an exception.
For example:
var serializer = new JavaScriptSerializer();
var result = serializer.Deserialize<dynamic>(json);
foreach (var item in result)
{
Console.WriteLine(item.body.message);
}
throws the exception: System.Collections.Generic.Dictionary doesnt contain definitions for body. Nevertheless you see in the screenshot below, that body contains definitions.
Becaus I am not allowed to post pictures you can find it on directupload: http://s7.directupload.net/images/120907/zh5xyy2k.png
I don't havent more ideas so i please you to help me. I need this for a project, private, not commercial.
Maybe you could give me an phrase of code, so i can continue my development.
Thank you so far
Dominic
If you use Json.Net, All you have to do is
replacing
var serializer = new JavaScriptSerializer();
var result = serializer.Deserialize<dynamic>(json);
with
dynamic result = JsonConvert.DeserializeObject(json);
that's all.
You are not deserializing to a strongly typed object so it's normal that the applications throws an exception. In other words, the deserializer won't create an Anynymous class for you.
Your string is actually deserialized to 2 objects, each containing Dictionary<string,object> elements. So what you need to do is this:
var serializer = new JavaScriptSerializer();
var result = serializer.Deserialize<dynamic>(s);
foreach(var item in result)
{
Console.WriteLine(item["body"]["message"]);
}
Here's a complete sample code:
void Main()
{
string json = #"[
{
""code"":200,
""headers"":[{""name"":""Access-Control-Allow-Origin"",""value"":""*""}],
""body"":{
""id"":""255572697884115_1"",
""from"":{
""name"":""xyzk"",
""id"":""59788447049""},
""message"":""This is the first message"",
""created_time"":""2011-11-04T21:32:50+0000""}},
{
""code"":200,
""headers"":[{""name"":""Access-Control-Allow-Origin"",""value"":""*""}],
""body"":{
""id"":""255572697884115_2"",
""from"":{
""name"":""xyzk"",
""id"":""59788447049""},
""message"":""This is the second message"",
""created_time"":""2012-01-03T21:05:59+0000""}}
]";
var serializer = new JavaScriptSerializer();
var result = serializer.Deserialize<dynamic>(json);
foreach(var item in result)
{
Console.WriteLine(item["body"]["message"]);
}
}
Prints:
This is the first message
This is the second message
I am using this simple technique
var responseTextFacebook =
#"{
"id":"100000891948867",
"name":"Nishant Sharma",
"first_name":"Nishant",
"last_name":"Sharma",
"link":"https:\/\/www.facebook.com\/profile.php?id=100000891948867",
"gender":"male",
"email":"nihantanu2010\u0040gmail.com",
"timezone":5.5,
"locale":"en_US",
"verified":true,
"updated_time":"2013-06-10T07:56:39+0000"
}"
I have declared a class
public class RootObject
{
public string id { get; set; }
public string name { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string link { get; set; }
public string gender { get; set; }
public string email { get; set; }
public double timezone { get; set; }
public string locale { get; set; }
public bool verified { get; set; }
public string updated_time { get; set; }
}
Now I am deserializing
JavaScriptSerializer objJavaScriptSerializer = new JavaScriptSerializer();
RootObject parsedData = objJavaScriptSerializer.Deserialize<RootObject>(responseTextFacebook );

Categories

Resources