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().
Related
I have int appsettings.js section like that:
"AccessKeys": {
"user1": {
"pass": ""
},
I created classes in C# to bind this section to these classes:
public class AccessKeys
{
public List Users = new List();
}
public class AccessKeyUserJson
{
public AccessKeyUser AccessKeyUser { get; set; }
}
public class AccessKeyUser
{
public string Pass { get; set; }
}
I bind above classes in Startup.cs:
services.Configure<AppSettingsConfig>(Configuration);
In AppSettingsConfig I have property AccessKeys and this property is binded correctly but Users is empty (0 items)
I changed structure:
"AccessKeys": [
{
"user1": "",
"pass": ""
},
]
Why don't you try something like this:
using (var ms = new System.IO.MemoryStream(Encoding.Unicode.GetBytes(myJSONstring)))
{
System.Runtime.Serialization.Json.DataContractJsonSerializer js = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(myStruct));
myStruct aux = (myStruct)js.ReadObject(ms);
}
This is a single level approach, and sincerely, I've never tried to cast anything in a sub-classing scheme but maybe it worths trying.
As you can see, here, the JSON string is taken by a Memory Stream and then casted into the final struct/class.
im completly new to programing,
im trying to create something like a manga organizing tool in windows forms, but im getting stuck in populating a listbox with data from a deserialized json string, it currently is only displaying boolean values correctly all other values are "0" even strings.
i have a button to do this:
using (OpenFileDialog openFileDialog = new OpenFileDialog() { Filter = "Json Files|*.json", ValidateNames = true, Multiselect = false })
{
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
var fileStream = openFileDialog.OpenFile();
using (StreamReader sr = new StreamReader(fileStream))
{
string fileContent = sr.ReadToEnd();
ComicList comics = JsonConvert.DeserializeObject<ComicList>(fileContent);
Manga_listBox.DataSource = DisplayComic.FullList;
//ignore this little bit it's just so i can see what's happening
label1.Text = Convert.ToString(comics.Comics.Count);
label1.Text = Convert.ToString(DisplayComic.FullList);
}
}
}
and i have the following classes like so:
public class Comic
{
private string Manga;
private int Chapters;
private bool isFinished;
private int LastReadCH;
public string Manga1 { get => Manga; set => Manga = value; }
public int Chapters1 { get => Chapters; set => Chapters = value; }
public bool IsFinished { get => isFinished; set => isFinished = value; }
public int LastReadCH1 { get => LastReadCH; set => LastReadCH = value; }
public Comic(Comic asd)
{
this.Manga = Manga1;
this.Chapters = Chapters1;
this.IsFinished = IsFinished;
this.LastReadCH = LastReadCH1;
}
public override string ToString()
{
return string.Format("{0}, {1}, {2}, {3}",
this.Manga, this.Chapters, this.IsFinished, this.LastReadCH);
}
}
and
public class ComicList
{
private List<Comic> comics;
public List<Comic> Comics { get => comics; set => comics = value; }
}
and
public class DisplayComic
{
static DisplayComic()
{
using (OpenFileDialog openFileDialog = new OpenFileDialog() { Filter = "Json Files|*.json", ValidateNames = true, Multiselect = false })
{
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
var fileStream = openFileDialog.OpenFile();
using (StreamReader sr = new StreamReader(fileStream))
{
string fileContent = sr.ReadToEnd();
ComicList comics = JsonConvert.DeserializeObject<ComicList>(fileContent);
FullList = comics.Comics;
}
}
}
}
private static List<Comic> fullList;
public static List<Comic> FullList { get => fullList; set => fullList = value; }
public static List<Comic> GetComcis()
{
return FullList;
}
}
code is probably quite messy, then again I'm completely new and have been following all kind of information online, also for some reason, the open dialog windows is opening twice I don't understand why.
here is the json file I'm using:
{
"Comics": [
{
"Manga": "MangaNumber1",
"Chapters": 85,
"isFinished": true,
"LastReadCH": 85
},
{
"Manga": "MangaNumber2",
"Chapters": 112,
"isFinished": true,
"LastReadCH": 112
},
{
"Manga": "MangaNumber3",
"Chapters": 117,
"isFinished": true,
"LastReadCH": 117
},
{
"Manga": "MangaNumber4",
"Chapters": 74,
"isFinished": true,
"LastReadCH": 74
}
]
}
I've tried pretty much anyone with my "expertise" could, changing all kind of variable names and so on, would really appreciate some help.
here's a screenshot of the problem:
as you can see only the boolean values are actually correct, otherwise they'd be false, all other values though...
EDIT:
the result im hopping for is to populate the listbox with the manga names, (thank you #beeker for that property thing) and once i select said manga then i want to create some other objects such as labels and text boxes to view and edit the values of the chapters etc, also i would like to be able to see what is being parsed by the json file how ever when i do this:
label1.Text = Convert.ToString(comics);
i get the label with the text "Manga_Organizer_2.ComicList"
By the way when i say im new, i mean i only ever did stuff with console apps using only "if" functions this whole parsing json, openfiledialog, and even classes usage is completly new. I also have no background in programing with any other language c# is the first and im loving it even though having terrible difficulties :)
Answer/Update:
All is good now :)
all i had to do was set
DisplayComic.FullList = comics.Comics;
in the openfiledialog right before setting the datasource for the listbox.
In the end it looks like this:
string fileContent = sr.ReadToEnd();
ComicList comics = JsonConvert.DeserializeObject<ComicList>(fileContent);
DisplayComic.FullList = comics.Comics;
Manga_listBox.DataSource = DisplayComic.FullList;
Manga_listBox.DisplayMember = "manga";
also removed the encapsulations alltogether in the comic class, in the end it looks like this:
public class Comic
{
public string Manga { get; set; }
public double Chapters { get; set; }
public bool IsFinished { get; set; }
public double LastReadCH { get; set; }
public string StartedOn { get; set; }
public string FinishedOn { get; set; }
}
and also the displaycomic class looks like this:
public class DisplayComic
{
public static List<Comic> FullList { get; set; }
public static List<Comic> GetComcis()
{
return FullList;
}
}
Also, after all this trouble came even more, i could deserialize the json, parse it to a string and then to a list, load, save and edit it and i also managed to serialize it back together, and with a savefiledialog create a file for it, however when i did, i would be unable to re-deserialize it once again, something about the json had changed (from object to array or vice versa), aside from that i also had problems with datetime stuff, couldn't load it correctly from a string and so on, anyway after a bunch of mishaps, and litteraly 17hours of looking at code with a puzzled face i finnaly finished my app :D!
It does all i want it to, load a json, save and edit it, put it back together, add and remove from it, and i learned a bunch from all this trouble, thank you all for helping, thanks to you guys learned how to set stuff to display on listboxes, and also very importantly "somewhat" learned how to debug code.
Thanks.
Try setting the listbox "DisplayMember" property so that the control knows which property of the class you want to see. Something like this...
Manga_listBox.DataSource = DisplayComic.FullList;
Manga_listBox.DisplayMember = "Manga";
Ref:
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.listcontrol.displaymember?view=netframework-4.8
Answer:
i removed that whole openfiledialog in the display comic class, renamed the encapsulations in the Comic class and done :D, now the openfiledialog only opens once and the values from the json are being correctly parsed to the comics list, thus enabling me to use them however i want, thank you, you pushed me in the right direction with the idea to learn debug stuff :D.
Now all that's left is learn how to create objects by selecting the different lines from the listbox, another challenge awaits this newcomer.
Let's say I have this example JSON:
"Test": {
"KIf42N7OJIke57Dj6dkh": {
"name": "test 1"
},
"xsQMe4WWMu19qdULspve": {
"name": "test 2"
}
}
I want to parse this into an Array of a custom class I have, which will be exampled below:
class Class1 {
public string Name { get; set; }
Class1(string name) {
Name = name;
}
}
How can I parse this using Json.NET's JObject.Parse?
You can achieve your goal with JPath query like this :
var myArray = JObject
.Parse(json)
.SelectTokens("$.Test..name")
.Values<string>()
.Select(s => new Class1(s))
.ToArray();
But probably not the best way to do it.
I personnaly prefere to create classes to represent the json structure and then apply transformations.
void Main()
{
var json = #"{""Test"": {
""KIf42N7OJIke57Dj6dkh"": {
""name"": ""test 1""
},
""xsQMe4WWMu19qdULspve"": {
""name"": ""test 2""
}
}
}";
var root = JsonConvert.DeserializeObject<Root>(json);
var array = root.Test.Select(i => i.Value).ToArray();
array.Dump();
}
public class Root
{
public Dictionary<string, Class1> Test { get; set; }
}
public class Class1
{
public string Name { get; set; }
public Class1(string name)
{
Name = name;
}
}
To begin with, your Json is missing starting/closing braces. The Json needs to have wrapping braces around the Test value.
{
'Test':
{
'KIf42N7OJIke57Dj6dkh': {'name': 'test 1'},
'xsQMe4WWMu19qdULspve': {'name': 'test 2'}
}
}
If you are missing it in the original Json, you could wrap the current input Json as following.
var correctedJson = $"{{{inputJsonString}}}";
If you want to parse the Json Objects to Array of Class1 without creating additional concrete data structures and using JPath Queries, you could use Anonymous Types for the purpose using the DeserializeAnonymousType Method proved by Json.Net. For example,
var sampleObject = new {Test = new Dictionary<string,Class1>()};
var data = JsonConvert.DeserializeAnonymousType(correctedJson,sampleObject);
var result = data.Test.Select(x=>x.Value).ToArray();
You could also achieve it using JPath Query or creating Concrete Data Structures as #Kalten as described in his answer.
I cant quite figure out the syntax on how to get the values of this list within a list.
public class Toppings
{
public List<string> PizzaToppings { get; set; }
}
static void Main(string[] args)
{
List<Toppings> items = new List<Toppings>();
using (StreamReader r = new StreamReader("C:\\pizzas.json"))
{
string json = r.ReadToEnd();
items = JsonConvert.DeserializeObject<List<Toppings>>(json);
}
I've populated my list as shown above but I am not sure how to print. This is one of the many things I've tried:
foreach (Toppings item in items)
{
foreach (List<string> s in item)
{
Console.WriteLine(s.PizzaToppings);
}
}
But I keep getting errors about not having a public instance definition of "GetNumerator" for "item.
The JSON looks like this
[
{
"toppings": [
"pepperoni"
]
},
{
"toppings": [
"feta cheese",
"bacon"
]
},
And when I tried doing foreach (String s in item.PizzaToppings I got an object reference not set to an instance of object error.
You'll need to make sure the object matches the JSON. Also you can do a SelectMany to collapse the list of list. The following code will print out all the toppings in the JSON:
void Main()
{
var json = File.ReadAllText("C:\\pizzas.json");
var obj = JsonConvert.DeserializeObject<List<PizzaToppings>>(json);
foreach(var topping in obj.SelectMany(o => o.Toppings))
{
Console.WriteLine(topping);
}
}
public class PizzaToppings
{
public List<string> Toppings {get;set;}
}
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;