C
C#2y ago
kyeede

Update JSON File with new values without overwriting existing data

Hello, So I'm currently developing a Discord bot that stores values such as 'settings' for each guild. I already got that part figured out very well but I would like to know how I should handle additions / removes. I have a class as followed:
public class GuildConfiguration
{
public string GuildPrefix { get; set; } = default!;
public bool EnableModeratorNotifications { get; set; } = default!;
public GuildCommandPermissions GuildCommandPermissions { get; set; } = default!;
}
public class GuildConfiguration
{
public string GuildPrefix { get; set; } = default!;
public bool EnableModeratorNotifications { get; set; } = default!;
public GuildCommandPermissions GuildCommandPermissions { get; set; } = default!;
}
As an example, currently, the json file doesn't have the public bool EnableModeratorNotifications included but it is a new feature I would like to add. If I add that to my class, how would I serialize it into the json file with a default value like true/false without overwriting the existing values there?
46 Replies
jcotton42
jcotton422y ago
are you deserializing the JSON into an instance of that before writing it back out?
kyeede
kyeedeOP2y ago
Yes.
jcotton42
jcotton422y ago
I think system.text.json will just use the default value then (btw, you don't need ! on that bool, that's only for nullable ref types)
kyeede
kyeedeOP2y ago
ah okay
jcotton42
jcotton422y ago
also, if you want those props to always be set, you might want
public required string GuildPrefix { get; set; }
public required string GuildPrefix { get; set; }
instead
kyeede
kyeedeOP2y ago
What does 'required' specifically do?
jcotton42
jcotton422y ago
the compiler yells at you if you try to create an instance without setting that prop
MODiX
MODiX2y ago
jcotton42#1663
REPL Result: Failure
class GuildSettings {
public required string GuildPrefix { get; set; }
}
var settings = new GuildSettings();
class GuildSettings {
public required string GuildPrefix { get; set; }
}
var settings = new GuildSettings();
Exception: CompilationErrorException
- Required member 'GuildSettings.GuildPrefix' must be set in the object initializer or attribute constructor.
- Required member 'GuildSettings.GuildPrefix' must be set in the object initializer or attribute constructor.
Compile: 489.636ms | Execution: 0.000ms | React with ❌ to remove this embed.
kyeede
kyeedeOP2y ago
ah okay makes sense
MODiX
MODiX2y ago
jcotton42#1663
REPL Result: Success
class GuildSettings {
public required string GuildPrefix { get; set; }
}
var settings = new GuildSettings() { GuildPrefix = "foo" };
class GuildSettings {
public required string GuildPrefix { get; set; }
}
var settings = new GuildSettings() { GuildPrefix = "foo" };
Compile: 553.507ms | Execution: 56.267ms | React with ❌ to remove this embed.
kyeede
kyeedeOP2y ago
So, I heard about [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] and DefaultValue() would that do something? or could I basically do public string GuildPrefix { get; set; } = "Value Here";
jcotton42
jcotton422y ago
that looks like Newtonsoft? are you using newtonsoft, or system.text.json?
kyeede
kyeedeOP2y ago
I think it is Newtonsoft if I am not mistaken Yep, it's Newtonsoft.Json;
jcotton42
jcotton422y ago
I'm not familiar with that part of it I always use STJ
kyeede
kyeedeOP2y ago
Is there a benefit of using STJ over Newtonsoft?
jcotton42
jcotton422y ago
faster, lower memory usage, etc. Newtonsoft has more features, but I don't find myself needing them it's also one less dependency to bundle, if you care about that
kyeede
kyeedeOP2y ago
oh, i did hear about STJ but I somehow always ended up using Newtonsoft.Json I will try your advice and check
jcotton42
jcotton422y ago
in any case, here's how STJ works by default
JsonConvert.DeserializeObject<GuildConfiguration>("""
{
"GuildPrefix": "foo",
"GuildCommandPermissions": 3
}
""").Dump();

public class GuildConfiguration
{
public string GuildPrefix { get; set; }
public bool EnableModeratorNotifications { get; set; } = true;
public int GuildCommandPermissions { get; set; }
}
JsonConvert.DeserializeObject<GuildConfiguration>("""
{
"GuildPrefix": "foo",
"GuildCommandPermissions": 3
}
""").Dump();

public class GuildConfiguration
{
public string GuildPrefix { get; set; }
public bool EnableModeratorNotifications { get; set; } = true;
public int GuildCommandPermissions { get; set; }
}
jcotton42
jcotton422y ago
gives
kyeede
kyeedeOP2y ago
Oh, so it serializes on it's own basically?
jcotton42
jcotton422y ago
err, oops meant NewtonSoft pretty sure STJ is the same, lemme try
kyeede
kyeedeOP2y ago
ohh
jcotton42
jcotton422y ago
oh huh
jcotton42
jcotton422y ago
I bet that's configurable...
kyeede
kyeedeOP2y ago
Hm I see
jcotton42
jcotton422y ago
yeah that's intended
kyeede
kyeedeOP2y ago
For some reason, for me .Dump(); isn't available
jcotton42
jcotton422y ago
ah sorry that's a LINQPad thing it's writes to the lower pane
kyeede
kyeedeOP2y ago
oh okay Instead of a string, is it possible to deserialize the object using a path to the json file? Because if so, I would simply add it to my loop when checking if each guild has the appropriate json file if it exists, simply update it
jcotton42
jcotton422y ago
STJ can take a stream to deserialize it looks like NewtonSoft can't, which is surprising so you'd need to read the file into memory as a string then deserialize
kyeede
kyeedeOP2y ago
So like this,
string guildJson = File.ReadAllText($"app1000/guilds/{getGuild.Id}/guilddata.json");
JsonConvert.DeserializeObject<GuildInformation>(guildJson);
string guildJson = File.ReadAllText($"app1000/guilds/{getGuild.Id}/guilddata.json");
JsonConvert.DeserializeObject<GuildInformation>(guildJson);
jcotton42
jcotton422y ago
yeah
kyeede
kyeedeOP2y ago
I did but for some reason the new value wasn't added to the json
jcotton42
jcotton422y ago
well, you're only deserializing you're not serializing back to it (also, if you're not that far in, you might want to consider using a database; managing tons of json files will get hairy pretty fast)
kyeede
kyeedeOP2y ago
oop i was told that json can be pretty tough but i get it, im deserializing it but i have to serialize it back
jcotton42
jcotton422y ago
it's not "json is tough" it's "when you have a ton of files spread about you're poorly approximating a database"
kyeede
kyeedeOP2y ago
I would use a database since I have worked with MySQL before a lot
jcotton42
jcotton422y ago
for a bot I'd use something like SQLite or PostgreSQL (I have... opinions about MySQL, tbh) EF Core makes interfacing with the db pretty easy
kyeede
kyeedeOP2y ago
The bot would handle a lot of cases at once and im not sure how the performance would be for the bot like, i once added a leveling system which means everytime a user types a message, it would change his score in the json which worked fine
jcotton42
jcotton422y ago
databases are obscenely fast even sqlite
kyeede
kyeedeOP2y ago
Would that mean I have to keep the connection to the database open 24/7 once it's open hm i see
jcotton42
jcotton422y ago
if you use EF it manages the connection for you I haven't done it manually in a long while
kyeede
kyeedeOP2y ago
i haven't worked with a DB in awhile yeah I still can't seem to figure out how to update the json file Setting a default value in the designer class works fine but actually adding that value into the json file doesn'twork :/ Nevermind, it worked using this code:
var getGuildDataPath = File.ReadAllText($"app1000/guilds/{getGuild.Id}/guilddata.json");
var getGuildData = JsonConvert.DeserializeObject<GuildInformation>(getGuildDataPath);

var updateGuildFile = JsonConvert.SerializeObject(getGuildData, Formatting.Indented);
File.WriteAllText($"app1000/guilds/{getGuild.Id}/guilddata.json", updateGuildFile);
var getGuildDataPath = File.ReadAllText($"app1000/guilds/{getGuild.Id}/guilddata.json");
var getGuildData = JsonConvert.DeserializeObject<GuildInformation>(getGuildDataPath);

var updateGuildFile = JsonConvert.SerializeObject(getGuildData, Formatting.Indented);
File.WriteAllText($"app1000/guilds/{getGuild.Id}/guilddata.json", updateGuildFile);
I mean this looks kinda weird but it works?
jcotton42
jcotton422y ago
I mean how else would you expect it to work? you deserialize to an object update the object serialize back
kyeede
kyeedeOP2y ago
Well, tbh, this looks like sloppy work. I usually look at the code in a more clean way but this will do.
Want results from more Discord servers?
Add your server