How to Deserialize a JSON array in List (C#) - c#

I am struggling with a subject that has a lot of variants in this forum but I can't seem to find one that suits me, and I think it's because of the way that my JSON array is :(
I'm not an expert but I already manage to "almost" get the end...
I need to get hand in "Success" and "Status" value. But also the different "Addresses".
My JSON (is called responseFromServer):
{
"success":true,
"addresses":
[
{"DPID":658584,"SourceDesc":"Postal\\Physical","FullAddress":"1/8 Jonas Street, Waimataitai, Timaru 7910"},
{"DPID":658585,"SourceDesc":"Postal\\Physical","FullAddress":"2/8 Jonas Street, Waimataitai, Timaru 7910"},
{"DPID":658583,"SourceDesc":"Postal\\Physical","FullAddress":"3/8 Jonas Street, Waimataitai, Timaru 7910"}
],
"status":"success"
}
Then, based on lot of examples in this forum, taking bits and pieces I created my classes:
public class jsonDataTable
{
public bool success { get; set; }
public IEnumerable<dtaddresses> addresses { get; set; }
public string status { get; set; }
}
public class dtaddresses
{
public int DPID { get; set; }
public string SourceDesc { get; set; }
public string FullAddress { get; set; }
}
Then I'm going to Deserialize:
public void _form_OnCallingAction(object sender, ActionEventArgs e)
{
...
...
JavaScriptSerializer js = new JavaScriptSerializer();
jsonDataTable jsonArray = js.Deserialize<jsonDataTable>(responseFromServer);
...
string tb = jsonArray.status.ToString();
string tb2 = jsonArray.success.ToString();
...
...
List<dtaddresses> _listAddresses = new List<dtaddresses>
{
new dtaddresses()
};
...
...
try
{
string tb3 = _listAddresses.Count.ToString();
string tb4 = _listAddresses[0].FullAddress;
}
catch (Exception ex)
{
CurrentContext.Message.Display(ex.Message + ex.StackTrace);
}
...
...
...
CurrentContext.Message.Display("Raw Response from server is: {0}", responseFromServer);
//Returns all the content in a string to check. OK! :)
CurrentContext.Message.Display("The success value is: {0} ", tb);
//Returns the Status Value (in this case "success") OK! :)
CurrentContext.Message.Display("The status value is: {0} ", tb2);
//Returns the Success Value (in this case "true") giggity giggity! All Right! :)
CurrentContext.Message.Display("The n. of addresses is: {0} ", tb3);
//Returns how many addresses ( in this case is returning 0) not ok... :(
CurrentContext.Message.Display("The address value is: {0} ", tb4);
// Returns the Fulladdress in index 0 (in this case nothing...) not ok... :(
Can any one help me to understand why I can access the values in the "dtaddresses" class?
This is the far that I went...

The following piece of code I copied from your question is creating a brand new list that has nothing to do with your deserialized data. Thus it's always going to be a single element list, where the first element contains only default values, which is what you are seeing in tb3 and tb4 later on.
List<dtaddresses> _listAddresses = new List<dtaddresses>
{
new dtaddresses()
};
Instead, assign jsonArray.addresses to _listAddresses, such as:
List<dtaddresses> _listAddresses = jsonArray.addresses.ToList()
Or you can forget about _listAddresses completely, and just simply reference jsonArray.addresses directly, such as:
string tb3 = jsonArray.addresses.Count().ToString();
string tb4 = jsonArray.addresses.First().FullAddress;

Related

Convert JSON containing `\u####` to Unicode string

I would need some help for a string conversion from unicode (\u03a9\u039c\u0395\u0393\u0391) to normal string (ΩΜΕΓΑ).
I made a function that theoretically should work but it doesn't work instead. I don't understand what I'm doing wrong.
I receive json data with webclient.DownloadString:
{"id": "94401626335", "username": "\u03a9\u039c\u0395\u0393\u0391"}
I get the \u03a9\u039c\u0395\u0393\u0391 and send it to the function:
DecodeFromUtf8(username)
public string DecodeFromUtf8(string utf8String)
{
try
{
var output = WebUtility.HtmlDecode(utf8String);
return output;
}
catch (Exception ex)
{
return utf8String;
}
}
the function always returns me: \u03a9\u039c\u0395\u0393\u0391
and not: ΩΜΕΓΑ
Why?
i can't use external libraries like system.text.json
Thanks
use a json deserializer , let it do the work
public class Ooo {
public string id { get; set; }
public string username { get; set; }
}
var json = #"{""id"": ""94401626335"", ""username"": ""\u03a9\u039c\u0395\u0393\u0391""}";
var ooo = System.Text.Json.JsonSerializer.Deserialize<Ooo>(json) ;
Console.WriteLine("string = " + ooo.username);
}
gives (my console has a glyph misssing, but its show correctly in the debugger)

Print the content from nested json in C#

I'm in the process of learning C# and now trying to learn how to work with JSON objects. For the purpose of that I'm writing a quiz game. I have managed to console writeline the content of simple JSON objects, but when they are more complex I only can log the object name. Example is shown below in the code.
The JSON object:
{
"QuestionId": "1",
"QuestionString": "What is blue?",
"Options": [
{
"Option": "The sky",
"Correct": false
},
{
"Option": "The limit",
"Correct": false
},
{
"Option": "A color",
"Correct": true
}
]
}
The class:
{
public class OptionType
{
public OptionType()
{
}
public string Option { get; set; }
public bool Correct { get; set; }
}
public class Question
{
public Question()
{
}
public string QuestionId { get; set; }
public string QuestionString { get; set; }
public List<OptionType> Options { get; set; }
}
}
And the code:
string fileName = #"C:\QuizGame\QuestionAnswer.json";
string jsonTxt = string.Empty;
using (StreamReader r = new StreamReader(fileName))
{
var json = r.ReadToEnd();
jsonTxt = json.ToString();
}
var question = JsonConvert.DeserializeObject<Question>(jsonTxt);
Console.WriteLine(question.Question)
// prints "What is blue?" // works like a charm
Console.WriteLine(question.OptionType)
// prints "System.Generic.List`1[QuizGame.OptionType]"
// and if I do a foreach:
foreach (object o in question.Options)
{
Console.WriteLine(o);
}
// prints QuizGame.OptionType x 3
My expected result is to be able to print the options for the question. It seems like at least something in the code is working since I'm able to see that there are 3 options for answer, so I guess it's something with my understanding of object oriented code / C# that is missing. Thankful for all replies.
Solved: I changed the "object" keyword to "var" (or "OptionType") and could then get to my nested objects. I've struggled for days with this. I googled and tried new things base on your input, so thanks alot!
foreach (var o in question.Options)
{
Console.WriteLine(o.Option); // loops through "Options"
Console.WriteLine(o.Correct); // loops through "Correct"
}
You are trying to print out a List. If you just want to print out all information then you maybe just want to add another foreach in your foreach-loop. Maybe sth. like this:
foreach (object o in question.Options)
{
foreach (object ob in o)
{
Console.WriteLine(ob.ToString());
}
}
But there are better approaches for that. You could for example override the ToString()-Method in your model-class and just call question.ToString().

Cannot get more than one result when using System.Linq.Dynamic.Core to query a list of objects that have a member dictionary

I am using System.Linq.Dynamic.Core v1.0.8.18
I am abbreviating the object I have--I have eliminated the JSON tags for serialization/deserialization as well as the constructor. Below is the abbreviated class for a line item on an order. Please note that this object is deserialized from JSON, and the purpose of the "other" dictionary is to capture any name/value pair that is not explicitly defined in the object (which works exactly as it should in testing and production):
public partial class OrderRequestItem
{
public string line_number { get; set; }
public decimal quantity { get; set; }
public string supplier_id { get; set; }
public string supplier_aux_id { get; set; }
public decimal unitprice { get; set; }
public string description { get; set; }
public string uom { get; set; }
public IDictionary<string, object> other;
public decimal extension
{
get
{
return unitprice * quantity;
}
}
public bool validated { get; set; }
public bool rejected { get; set; }
}
I am attempting to "split" an order using the following code based on a JSON config file entry that specifies which fields to split the order on (parameter 2):
private List<OrderRequest> SplitOrder(OrderRequest originalOrder, string[] orderSplitLineItemFields = null)
{
var retval = new List<OrderRequest>();
if (null == orderSplitLineItemFields || originalOrder.items.Count < 2) //Can't return more than one order if we don't have fields to split by, and we don't have at least 2 line items.
{
retval.Add(originalOrder);
}
else
{
var bareOrderHeader = (OrderRequest)originalOrder.DeepClone();
bareOrderHeader.items.Clear();
var firstLineItem = originalOrder.items[0];
var validOrderSplitLineItemFields = new List<string>();
var dynamicQueryBase = new List<string>();
int validFieldCount = 0;
foreach (var field in orderSplitLineItemFields)
{
if (firstLineItem.HasProperty(field))
{
validOrderSplitLineItemFields.Add(field);
dynamicQueryBase.Add(field + " = #" + validFieldCount++);
}
else if (null != firstLineItem.other[field])
{
validOrderSplitLineItemFields.Add("other[\"" + field + "\"]");
dynamicQueryBase.Add("other[\"" + field + "\"]" + " = #" + validFieldCount++);
}
}
if(validOrderSplitLineItemFields.Count<1) //Can't return more than one order if we don't have valid fields to split by.
{
retval.Add(originalOrder);
}
else //We have valid fields to split the order, so we might be able to return more than one order.
{
string distinctFields = String.Join(",", validOrderSplitLineItemFields);
var distinctFieldValues = originalOrder.items.AsQueryable().Select(distinctFields).Distinct();
var dynamicWhere = string.Join(" and ", dynamicQueryBase);
var originalLineItems = originalOrder.items.AsQueryable();
foreach (var distinctResult in distinctFieldValues)
{
var newOrderSplit = (OrderRequest)bareOrderHeader.DeepClone();
var results = originalLineItems.Where(dynamicWhere, distinctResult);
foreach (var lineitem in results)
{
newOrderSplit.items.Add(lineitem);
}
retval.Add(newOrderSplit);
}
}
}
return retval;
}
The field that I am attempting to split on is called "requested_delivery_date" which is being properly passed in to the SplitOrder function. Because this is not an actual property of OrderRequestItem, the split code checks (and in fact succeeds) in looking at/finding a dictionary entry in the "other" property and appropriately adds the field to the list of dynamic fields upon which to query--(I do it this way because the specifically defined properties are "required" and I won't be able to predict what additional fields we may be sent on future orders with other buyers).
I have a sample order file that contains 4 line items. The lines 1, 2, 3 all have a defined other["requested_delivery_date"] = 2018-09-29, and line 4 has a other["requested_delivery_date"] = 2018-09-30.
Based on the code, I would expect to return two orders, one with line items 1-3, and another with only line 4. However, what I am actually getting back is two orders, one with only line item #1, and another with only line item #4. It seems as though the line
var results = originalLineItems.Where(dynamicWhere, distinctResult);
only ever returns a single result when I query against the dictionary that is a member of OrderRequestItem.
I have been beating my head against the wall here for the better part of the day and I don't understand why I only get a single result when the debugger is showing me that the original list of items I am querying have more matches. I'm starting to think it is a bug in the current version of System.Linq.Dynamic.Core.
Any help/suggestions appreciated! Keep in mind that I need to use dynamic linq since I will be dealing with new or changed additional fields on the line items all the time--so going back to "regular linq" isn't an option here.
Changed this
dynamicQueryBase.Add("other[\"" + field + "\"]" + " = #" + validFieldCount++);
to this
dynamicQueryBase.Add("other[\"" + field + "\"].ToString()" + " = #" + validFieldCount++);
makes it work as expected.
I can't test right now, maybe the default return for "where" is only a single item.
Try
var results = originalLineItems.Where(dynamicWhere, distinctResult).ToList();
And check if it's working fine.

Newtonsoft.Json.JsonReaderException: 'Unexpected character encountered while parsing value: [.

I'm doing C# JSON <-> PHP JSON for the first time.
Thought I'd get on an easy road but seems like I've hit the rock.
I'm fairly sure that JSON from Newtonsoft allows "[" character but not sure why i have this error instead?
Here's my C# code:
public class SystemJSON
{
public bool Status { get; set; }
public string Message { get; set; }
public string ResponseData { get; set; }
}
public static class SystemCall
{
public static String Post(string uri, NameValueCollection pairs)
{
byte[] response = null;
using (WebClient wc = new WebClient())
{
response = wc.UploadValues(uri, pairs);
}
return Encoding.Default.GetString(response);
}
}
string system_Response = SystemCall.Post("http://127.0.0.1:8080/edsa-NEFS%20(PHP)/api.php", new NameValueCollection()
{
{"do_work", Functions.Get_Department_List.ToString()},
{"api_data", null }
});
**SystemJSON systemJSON = JsonConvert.DeserializeObject<SystemJSON>(system_Response);** //<-- Error happens here.
if(systemJSON.Status == true)
{
//do stuff here
}else
{
MessageBox.Show(this, systemJSON.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
And here's my PHP code:
<?php
// Load Request
$function_name = isset($_POST['do_work']) ? $_POST['do_work'] : '';
$api_data = isset($_POST['api_data']) ? $_POST['api_data'] : '';
// Validate Request
if (empty($function_name))
{
SystemResponse(false, 'Invalid Request');
}
if (!function_exists($function_name))
{
SystemResponse(false, 'API Method Not Implemented');
}
// Call API Method
call_user_func($function_name, $api_data);
/* Helper Function */
function SystemResponse($responseStatus, $responseMessage, $responseData = '')
{
exit(json_encode(array(
'Status' => $responseStatus,
'Message' => $responseMessage,
'ResponseData' => $responseData
)));
}
/* API Methods */
function Get_Department_List($api_data)
{
//Test ------------------------------------------START
$node = array();
$dept = array();
$responseData = array();
$dept['id'] = 1;
$dept['name'] = "General";
$dept['description'] = "Forms, Samples, Templates, Catalogs, etc";
$dept['status'] = 1;
array_push($node, $dept);
$dept['id'] = 2;
$dept['name'] = "Test";
$dept['description'] = "Testing";
$dept['status'] = 1;
array_push($node, $dept);
$responseData["dept"] = $dept;
SystemResponse(true, 'SUCCESS', $responseData);
//Test ------------------------------------------END
}
?>
And here's my error:
Newtonsoft.Json.JsonReaderException HResult=0x80131500
Message=Unexpected character encountered while parsing value: {. Path
'ResponseData', line 1, position 51.
The problem is that your C# SystemJSON class does not match the structure of the incoming JSON correctly.
ResponseData in your C# SystemJSON class is listed as a string but your PHP appears to be pushing out a complex object inside that property. You can't deserialise an object into a string - there is no way for the deserialiser to know how to translate the object structure into a suitable string, and anyway it's not generally a useful or logical thing to do. So instead it throws an error to say the object structure doesn't match.
The specific error you're seeing means the deserialiser is expecting a " to denote the start of a string but instead it's seeing { denoting the start of another object.
Why is this happening? Well, your PHP code will produce a JSON response which looks like this:
{
"Status": true,
"Message": "SUCCESS",
"ResponseData": {
"dept": {
"id": 2,
"name": "Test",
"description": "Testing",
"status": 1
}
}
}
Live demo here
As you can see, ResponseData contains an object, which has a "dept" which in turn is another object with four more properties.
To deserialise this properly, your SystemJSON class will need to be altered, and you'll also need two sub-classes to help it out:
public class SystemJSON
{
public bool Status { get; set; }
public string Message { get; set; }
public ResponseData ResponseData { get; set; }
}
public class ResponseData {
public Department dept {get; set; }
}
public class Department {
public string id {get; set; }
public string description {get; set; }
public int status {get; set; }
}
You will now be able to deserialise the JSON correctly. Here is a live demo of the deserialisation.
P.S the [ character appears to be irrelevant here...it's unclear why you referred to that in your question.
P.P.S. From looking at your PHP I'm guessing that you may be intending to return different data structures in ResponseData depending on which parameter was specified for do_work - i.e. depending on which PHP function is called. If so then you'll need to amend your C# accordingly so that it deserialises to a different concrete class depending on which API method it requests. Or you could possibly cheat and specify ResponseData as dynamic, which will then accept any data structure it received, albeit with the caveat that it's now effectively loosely-typed and so you lose certain benefits when compiling the code such as checking for valid usage of property names, data types etc.

Dictionary of Objects doesn't work as JSON

I have spent WAY too much time trying to figure out how to pull all the values I need to from my C# application using JS and JSON. It works fine when I just use simple structures, such as an array, but I need to be able to grow the list at runtime.
Right now, the best I could figure out was doing a Dictionary with an incrementing key value, and the other 3 values as a class object. However, this seems to crash out my C# application.
What would be the best way to do this?
Relevant C# Code:
public class ChatData
{
string userName;
string message;
System.DateTime timestamp;
public ChatData(string name, string msg)
{
userName = name;
message = msg;
timestamp = System.DateTime.Now;
}
}
else if (string.Equals(request, "getchat"))
{
//string since = Request.Query.since;
Dictionary<int, ChatData> data = new Dictionary<int, ChatData>();
data.Add(1, new ChatData("bob", "hey guys"));
data.Add(2, new ChatData("david", "hey you"));
data.Add(3, new ChatData("jill", "wait what"));
return Response.AsJson(data);
}
Relevant Javascript:
function getChatData()
{
$.getJSON(dataSource + "?req=getchat", "", function (data)
{
//$.each(data, function(key, val)
//{
//addChatEntry(key, val);
//})
});
}
You haven't explained what Response.AsJson is and how it is implemented but if it uses JavaScriptSerializer you will get the following exception:
Unhandled Exception: System.ArgumentException: Type
'System.Collections.Generic. Dictionary`2[[System.Int32, mscorlib,
Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089],[ChatData, Test, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null]]' is not supported for
serialization/deserialization of a dictionary, keys must be strings or
objects.
which is pretty self-explanatory. You cannot use integers as keys if you intend to JSON serialize this structure. Also because your ChatData class no longer has a default/parameterless constructor you won't be able to deserialize a JSON string back to this class (but I guess you don't need this yet).
So one possible solution to your problem would be to use:
Dictionary<string, ChatData> data = new Dictionary<string, ChatData>();
data.Add("1", new ChatData("bob", "hey guys"));
data.Add("2", new ChatData("david", "hey you"));
data.Add("3", new ChatData("jill", "wait what"));
Now of course this being said and looking at the javascript you commented out and what you intend to do, as I already explained you in your previous question, dictionaries are not serialized as javascript arrays, so you cannot loop over them.
Long story short, define a class:
public class ChatData
{
public string Username { get; set; }
public string Message { get; set; }
public DateTime TimeStamp { get; set; }
}
and then fill an array of this class:
var data = new[]
{
new ChatData { Username = "bob", Message = "hey guys" },
new ChatData { Username = "david", Message = "hey you" },
new ChatData { Username = "jill", Message = "wait what" },
};
return Response.AsJson(data);
and finally consume:
$.getJSON(dataSource, { req: 'getchat' }, function (data) {
$.each(data, function(index, element) {
// do something with element.Username and element.Message here, like
$('body').append(
$('<div/>', {
html: 'user: ' + element.Username + ', message:' + element.Message
})
);
});
});
Why not simply use a typed list? Also, you'll need a default constructor to serialize/deserialize it. Note how I've modified your class to use properties
as well. Note, as #rudolf_franek mentions, you can add an ID property to the ChatData class if you need to be able to link to it.
public class ChatData
{
public ChatData()
{
TimeStamp = DateTime.Now;
}
public int ID { get; set; }
public string Who { get; set; }
public string Said { get; set; }
public DateTime TimeStamp { get; set; }
}
...
var data = new List<ChatData>
{
new ChatData { ID = 1, Who = "bob", Said = "hey guys" },
...
};
return Response.AsJson( data );

Categories

Resources