❔ Reading from a JSON file

I have a JSON file in the following format
{
"type" : {
"path" : "filename",
"path2" : "filename",
},
"type2" : {
"path" : "filename"
}
}
}
{
"type" : {
"path" : "filename",
"path2" : "filename",
},
"type2" : {
"path" : "filename"
}
}
}
where I don't know how many types I have or how many paths per type. How would I go about reading and storing this in C#?
92 Replies
PracticalPotato
PracticalPotato14mo ago
Or is there a different way that I could format this json file that retains the same information?
Thinker
Thinker14mo ago
You could probably use a Dictionary<string, Dictionary<string, string>>
PracticalPotato
PracticalPotato14mo ago
I'm at the point where I have the StreamReader for the json, would I deserialize it like this?
dic = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, string>>>(sr.ReadToEnd())
dic = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, string>>>(sr.ReadToEnd())
at this point it's getting confusing to me
cap5lut
cap5lut14mo ago
How to handle overflow JSON or use JsonElement or JsonNode in Syste...
Learn how to handle overflow JSON or use JsonElement or JsonNode while using System.Text.Json to serialize and deserialize JSON in .NET.
ero
ero14mo ago
you would want to avoid newtonsoft
PracticalPotato
PracticalPotato14mo ago
ok so.. as far as I'm reading, I can deserialize into a JsonElement object and go from there? How do I get values out of that?
ero
ero14mo ago
string filePath = /* */;
using var fs = File.OpenRead(filePath);
var dict = JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, string>>>(fs);
string filePath = /* */;
using var fs = File.OpenRead(filePath);
var dict = JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, string>>>(fs);
that's it and then you do dict[/* type */][/* path */]
cap5lut
cap5lut14mo ago
it has a lot of different Get... methods for the different types. if its really just that structure (no deeper nesting) and everything is a string, i would also go for that dictionary approach basically what Ero said ;p
PracticalPotato
PracticalPotato14mo ago
I'm getting
Argument 1: cannot convert from 'System.IO.FileStream" to 'Newtonsoft.Json.JsonReader'
Argument 1: cannot convert from 'System.IO.FileStream" to 'Newtonsoft.Json.JsonReader'
at line 3?
ero
ero14mo ago
.
PracticalPotato
PracticalPotato14mo ago
where are you getting your JsonSerializer then? if I uninstall newtonsoft it doesn't recognize it
Florian Voß
Florian Voß14mo ago
import using System.Text.Json and remove Newtonsoft @Ero uses the JsonSerializer from that said namespace because its not part of a third party lib but instead part of the .Net Class Library
cap5lut
cap5lut14mo ago
and much better ;p (personal opinion)
ero
ero14mo ago
not an opinion
Florian Voß
Florian Voß14mo ago
afaik Netwonsoft is still better in performance but I guess performance is not very important. Its more important that you wanna use builtin stuff rather than maintaining dependencies to nuget packages
ero
ero14mo ago
what imagine thinking newtonsoft is faster
Florian Voß
Florian Voß14mo ago
okay so apparently System.Text.Json has caught up in .net 7 good to know, thx I was using System.Text.Json anway cuz of this
cap5lut
cap5lut14mo ago
STJ uses source code generation nowadays, iirc Newtonsoft still uses reflection
ero
ero14mo ago
not sure if this benchmark uses the codegen
Florian Voß
Florian Voß14mo ago
well they advertise with being more performant than .Net's builtin serializer
cap5lut
cap5lut14mo ago
well, if not, it would just mean that it would even widen the gap in performance ;p
Florian Voß
Florian Voß14mo ago
but seems its not the case anymore
cap5lut
cap5lut14mo ago
afaik prior to 7 that was the case
Florian Voß
Florian Voß14mo ago
yep
PracticalPotato
PracticalPotato14mo ago
that seemed to work! thanks everyone
cap5lut
cap5lut14mo ago
glad we could help o7
ero
ero14mo ago
funniest thing is that some of newtonsoft doesn't use the generic overloads so you deserialize into dynamic which will hurt other parts of your code not just the deserialization
cap5lut
cap5lut14mo ago
its even in the subtitle of the linked article ;p
Did Microsoft finally catch up?
Florian Voß
Florian Voß14mo ago
I always wondered why people would ever choose to use dynamic 🤷 even if not using Generics you might rather deserialize to object tho? why throw away the typesystem
ero
ero14mo ago
it's difficult to rationalize, but there are some use cases but the code that gets compiled in place of dynamic is
Florian Voß
Florian Voß14mo ago
my general rule of thumb: Pref Generics over object and pref object over dynamic. I haven't faced a use case where I had to use dynamic yet
ero
ero14mo ago
well, see for yourself
cap5lut
cap5lut14mo ago
tbh, i dunno much about dynamic, never even wanted to touch it as it cant be good just from name ;p
Florian Voß
Florian Voß14mo ago
you mean in IL? I Will have a look
ero
ero14mo ago
not even
Florian Voß
Florian Voß14mo ago
wdym then
cap5lut
cap5lut14mo ago
lets move this somewhere else instead of abusing this help thread
MODiX
MODiX14mo ago
Ero#1111
sharplab.io (click here)
void M(dynamic d) {
Console.WriteLine(d.I);
}
class C {
public int I { get; }
}
void M(dynamic d) {
Console.WriteLine(d.I);
}
class C {
public int I { get; }
}
React with ❌ to remove this embed.
SuperBrain
SuperBrain14mo ago
If you can change your JSON file format, use an array of paths.
PracticalPotato
PracticalPotato14mo ago
unless I’m misunderstanding somehow, that doesn’t preserve the “type” information, and the path isn’t the path to the filename, I can’t combine them.
SuperBrain
SuperBrain14mo ago
That's beside the point, I'm talking about how you should use the values, I'm talking about how to format your JSON in order to support a more complex structure.
PracticalPotato
PracticalPotato14mo ago
??? how does that support a more complex structure? an array of strings is simpler and doesn’t have as much information. how tf is it besides the point when your solution doesn’t contain the information that I need?
SuperBrain
SuperBrain14mo ago
www.javatpoint.com
JSON Array - javatpoint
JSON Array for beginners and professionals with examples of JSON with java, json array of string, json array of numbers, json array of booleans, json srray of objects, json multidimentional array. Learn JSON array example with object, array, schema, encode, decode, file, date etc.
SuperBrain
SuperBrain14mo ago
You might want to use an array of objects instead of array of strings.
PracticalPotato
PracticalPotato14mo ago
what’s the benefit of using an array of objects over a dictionary of objects
SuperBrain
SuperBrain14mo ago
You can map that to a class. STJ works really well with classes. As in, instead of having to manually process JSON properties and values, you can serialize/deserialize an entire file with a single call.
PracticalPotato
PracticalPotato14mo ago
well, I am still doing it in one call as a dictionary of dictionaries, right?
string filePath = /* */;
using var fs = File.OpenRead(filePath);
var dict = JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, string>>>(fs); // this?
string filePath = /* */;
using var fs = File.OpenRead(filePath);
var dict = JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, string>>>(fs); // this?
cap5lut
cap5lut14mo ago
is the path, path2, etc information important? if not u can simply restructure it to
{
"type": {
"paths": ["...", "..."]
},
...
}
{
"type": {
"paths": ["...", "..."]
},
...
}
or even drop the paths property. can u tell more about the information itself? or more detailed example data
PracticalPotato
PracticalPotato14mo ago
the paths can have different filenames associated with each path. I’m actually on my phone by now, tbh. I got a working solution a while ago.
cap5lut
cap5lut14mo ago
so one path can have multiple file names or just one?
PracticalPotato
PracticalPotato14mo ago
each path is associated with one file, though the same file may have multiple paths. I guess i could flip it so that i have a file as a key and an array of paths as the value but it doesn’t really seem to reduce the complexity by much
cap5lut
cap5lut14mo ago
well, depends on what u want to do with the data afterwards. if u want to find possible paths for a given filename flip it, if u want it the file name for a given path keep it as is, if u want both it doesnt really matter in such situations i usually first work out a class hierarchy i wanna work with in code and then the json comes naturally ;p
PracticalPotato
PracticalPotato14mo ago
i need all of the keyvalue pairs so I guess I could make them tuples if I really wanted to shrugs I’m practically iterating through the dictionary under each type so whatever works works. so
Florian Voß
Florian Voß14mo ago
you can do the same thing with Dictionary 🤔 or am I missunderstanding something? All you'd have to do for this deserialization to work is modify the json slightly so that it has a wrapper object and a field called "types": holding all the content (which you would also have to do when using array or list or any other datastructure as a property here)
public class A{
public Dictionary<string, Dictionary<string, string>> Types { get; set; }
}
JsonSerializer.Deserialize<A>(fs);
public class A{
public Dictionary<string, Dictionary<string, string>> Types { get; set; }
}
JsonSerializer.Deserialize<A>(fs);
if you wanted to switch to an array but also keep the type information, you could make a field out of it:
[
{
"type": "type",
"path": "filename",
"path2": "filename"
},
{
"type": "type2",
"path": "filename"
}
]
[
{
"type": "type",
"path": "filename",
"path2": "filename"
},
{
"type": "type2",
"path": "filename"
}
]
but again, if we wanna map that to a type, its missing the wrapper object and "types" field holding the array, same thing as with Dictionary
cap5lut
cap5lut14mo ago
u couldnt really map it like that, would have to have another nesting, because there is an unknown amount of paths
Florian Voß
Florian Voß14mo ago
I don't see what you mean. we can deserialize this to a collection of dictionaries as we did before. I just replaced the outer dictionary with a List/Array and I did mention that you need another wrapper object to deserialize the json to a concrete custom type if thats what you mean by "another nesting"
cap5lut
cap5lut14mo ago
i mean that part:
{
"type": "type",
"path": "filename",
"path2": "filename"
}
{
"type": "type",
"path": "filename",
"path2": "filename"
}
the type is actually another hierarchy level by what OP explained. wiring that into some DTO would mean that u need a custom (de-)serializer
Florian Voß
Florian Voß14mo ago
hierarchy level by what OP explained.
the hierarchy is our choice. We design and structure our data for our needs wiring that into some DTO would mean that u need a custom (de-)serializer its litteraly just an additional key-valu pair in the dictionary there is no extra work
{
"types": [
{
"type": "type",
"path": "filename",
"path2": "filename"
},
{
"type": "type2",
"path": "filename"
}
]
}
{
"types": [
{
"type": "type",
"path": "filename",
"path2": "filename"
},
{
"type": "type2",
"path": "filename"
}
]
}
public class FooBarDTO{
public List<Dictionary<string, string>> Types { get; set; }
}
public class FooBarDTO{
public List<Dictionary<string, string>> Types { get; set; }
}
JsonSerializer.Deserialize<FooBarDTO>(fs)
cap5lut
cap5lut14mo ago
but the structure is
public class TypeDTO
{
public string Name { get; set; }
public List<(string Path, string FileName)> RelationsMappingWhatever { get; set; }
}
public class TypeDTO
{
public string Name { get; set; }
public List<(string Path, string FileName)> RelationsMappingWhatever { get; set; }
}
the type is grouping the path<->filename stuff
Florian Voß
Florian Voß14mo ago
yep, just like in my suggestion... I am grouping path and filename, I just pref using Dictionary over List of tuples...
cap5lut
cap5lut14mo ago
and where goes the type value info?
Florian Voß
Florian Voß14mo ago
???
cap5lut
cap5lut14mo ago
well, most likely it would be better to have some kind hashset or so looking at the original post there are different named types, how do u reflect that in ur FooBarDTO?
Florian Voß
Florian Voß14mo ago
good point, so I would also encapsulate the Dictionary<string, string> into its own TypeDTO and add a name property, just not using list of tuples
cap5lut
cap5lut14mo ago
in the end i think about this sturcture more or letss:
public record Mapping(string Path, string FileName);
public record TypeMappings(string TypeName, ISet<Mapping> mappings);
public record Mapping(string Path, string FileName);
public record TypeMappings(string TypeName, ISet<Mapping> mappings);
naming might be wrong tho
Florian Voß
Florian Voß14mo ago
looks great 😊 but I think as you had before with name on the inner type and List of tuples made more sense I'd go with:
public record TypeDTO(string name, Dictionary<string, string> pathToFileNameMappings);
public record WhatEverDTO(ISet<TypeDTO> types);
public record TypeDTO(string name, Dictionary<string, string> pathToFileNameMappings);
public record WhatEverDTO(ISet<TypeDTO> types);
then
cap5lut
cap5lut14mo ago
from the explanation i would go with that and
[
{
"name": "someTypeName",
"mappings":
[
{
"path": "...",
"fileName": "..."
}
]
},
...
]
[
{
"name": "someTypeName",
"mappings":
[
{
"path": "...",
"fileName": "..."
}
]
},
...
]
because from the explanation it seems that the type is relevant (thus its name), the other is a 1:1 binding (because they iterate over it all so it just has to be unique) to have it without custom implementations. urs makes sense too ofc i guess we just simply do not have enough information and are wildly guessing
Florian Voß
Florian Voß14mo ago
issue I see with this approach here is that you would have to create a third record that holds ISet<TypeMappings> Types because author of thread said he doesnt know how many types there are. Now you've created three types when we only ever wanted to deserialize a collection of objects
cap5lut
cap5lut14mo ago
because the iteration part i thought that the deserialization type would be TypeMappings[] or list, or whatever kind of collection it should be its hard to tell whats correct because neither the json structure nor the poco structure is defined
SuperBrain
SuperBrain14mo ago
Instead of trying to adjust JSON file format and contents, all you need to do is design a class that will hold your data and them simply use STJ to (de)serialize it.
Florian Voß
Florian Voß14mo ago
the author said he is free to adjust the json file format and contents, so why not play around with ideas what would be the best design to structure it?
SuperBrain
SuperBrain14mo ago
Sure, but I like simple solutions 👀
Florian Voß
Florian Voß14mo ago
well I like good design, even if it takes more time
SuperBrain
SuperBrain14mo ago
Yeah, but overthinking is also a bad thing.
cap5lut
cap5lut14mo ago
thats the point, we dont even know exactly what its used for, so we have neither nor ;p
Florian Voß
Florian Voß14mo ago
truuee
cap5lut
cap5lut14mo ago
we r just imagining possible solutions here
SuperBrain
SuperBrain14mo ago
I've worked with JSON enough to know what works best in most cases. And since OP is going to use STJ, focusing on class rather than the underlying JSON is the key.
Florian Voß
Florian Voß14mo ago
but the class design and the json design go hand in hand so in order to design good classes we gotta design good json first, no?
cap5lut
cap5lut14mo ago
the info we have: there are some kind of types types have a collection of relation between paths and file names over these relations will be iterated thats it edit: json and class structure can be adjusted
Florian Voß
Florian Voß14mo ago
ofc we can yeet everyting into FooBarDTO but that won't do us a favor
SuperBrain
SuperBrain14mo ago
Yes, because you only need to design the class ...
cap5lut
cap5lut14mo ago
we dont have the full knowledge about what happens with the data, thus we cant construct the pocos optimal
SuperBrain
SuperBrain14mo ago
The way I see it - Create a class - Serialize it - Check if resulting JSON is good for your use-case - If not, adjust the class and try again
Florian Voß
Florian Voß14mo ago
but he is not serializing he is deserializing. He receives json and he said he can modify the shape of json he receives so we start designing the json right? and then classes
cap5lut
cap5lut14mo ago
i think they do both, but dont have a clear design in mind. thus we need more info about the use case, which isnt clear yet
Florian Voß
Florian Voß14mo ago
Hmm
cap5lut
cap5lut14mo ago
with the limited info we have been given we designed some nice structures, i guess its time that the OP steps in and tells us what they want to achieve ;p @PracticalPotato i guess we need ur input ⤴️ xD
PracticalPotato
PracticalPotato14mo ago
I seem to have nerd sniped the C# community. honestly, all of these seem plausible, depending on use case. the only thing that seems constant is that if I don't know how many values I will have, I should shove it into a dictionary. The "type" is the name of a program that has many different versions. The path is a path to a registry key in the Windows uninstall registry. I'm using this registry key in order to find the location where the program is installed. Then, I use the name of the executable to start the program. the json structure that I posted originally was just what made the most sense to me. I wanted to be able to select a "type" and then my program will try each registry key, and when it's found, open the .exe
SuperBrain
SuperBrain14mo ago
Why use Dictionary when you have arrays? Yes, you can, but why complicate things? A simple array of strings will satisfy your need. Because, as far as I understand your requirement, you don't need to know whether something is path or path22 or path122, you just need to get all paths as some kind of list and process them all. This is why an array is best fit because it's simple. Dictionary is OK, but IMO it is an overkill for this use-case. That's all. Dictionary stores key-value pairs. If I'm not mistaking, you only need the values, and you don't care much for the keys. However, if you do need to know which key a particular value belongs to, that's different, but what you explained above doesn't suggest that, which is why I still recommend a simple array of strings. Personally, I would just use a List<string> and be done with it, because STJ knows how to serialize that.
Accord
Accord14mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.