To change a JSON value in C#, deserialize the string into a dynamic object or a strongly-typed class using System.Text.Json, modify the property, and serialize it back. For API keys, store them in environment variables or user secrets rather than plain JSON files to ensure security.
Understanding JSON Serialization in C#
Modern .NET applications rely heavily on System.Text.Json for handling data interchange. This library provides high-performance serialization and deserialization capabilities. When you need to update a specific value within a JSON structure, you typically load the existing data, parse it into a manipulable format, adjust the target field, and then write the updated content back to storage or an API payload.
This process is straightforward but requires attention to type safety. Using dynamic types offers flexibility when the schema is unknown, while strongly-typed classes provide compile-time checking. Both approaches are valid depending on your application's architecture and security requirements.
Method 1: Modifying Dynamic JSON Objects
The most flexible approach involves parsing the JSON string into a JsonDocument or JsonNode. This allows you to navigate the hierarchy without defining explicit classes. Here is how you can update a value dynamically:
using System;
using System.Text.Json;
using System.Text.Json.Nodes;
public void UpdateJsonValue()
{
string json = "{ \"apiKey\": \"old-key\", \"version\": 1 }";
// Parse into a mutable JsonNode
JsonNode node = JsonNode.Parse(json);
// Modify the value
node["apiKey"] = "new-secure-key";
// Serialize back to string
string updatedJson = node.ToJsonString();
Console.WriteLine(updatedJson);
}
This method is ideal for configuration files where the structure might vary. It avoids the overhead of creating POCO (Plain Old CLR Object) classes for simple updates. However, be aware that JsonNode is available in .NET 6 and later. For older versions, consider using third-party libraries like Newtonsoft.Json.
Method 2: Using Strongly-Typed Classes
For robust applications, defining a class that matches your JSON structure ensures type safety. This approach prevents runtime errors caused by typos in property names. Define a class with properties corresponding to your JSON keys:
using System.Text.Json;
public class AppConfig
{
public string ApiKey { get; set; }
public int Version { get; set; }
}
public void UpdateTypedJson()
{
string json = "{ \"apiKey\": \"old-key\", \"version\": 1 }";
// Deserialize into the typed class
var config = JsonSerializer.Deserialize(json);
// Modify the property directly
config.ApiKey = "new-secure-key";
// Serialize back
string updatedJson = JsonSerializer.Serialize(config);
Console.WriteLine(updatedJson);
}
This pattern is recommended when the JSON schema is stable. It integrates well with dependency injection and unit testing. If your JSON contains nested objects, create corresponding nested classes to maintain clarity and maintainability.
Security Best Practices for API Keys
Storing API keys directly in JSON files poses significant security risks. If these files are committed to version control or accessed by unauthorized users, credentials can be compromised. Instead, use environment variables or the User Secrets manager in development environments.
In production, integrate with Azure Key Vault, AWS Secrets Manager, or HashiCorp Vault. These services provide encryption at rest and access controls. When reading configuration in C#, inject these secrets via IConfiguration rather than parsing raw JSON strings manually.
For local development, you can use the UserSecrets tool in .NET. This stores sensitive data outside the project directory. Access these values through the standard configuration builder, which abstracts away the underlying storage mechanism. This practice aligns with the Twelve-Factor App methodology and reduces the attack surface.
Related Resources
If you are working with other C# features, you might find our guide on C# Convert DateTimePicker String: A Comprehensive Guide helpful for handling date inputs in similar configuration scenarios.
Frequently Asked Questions
Does System.Text.Json throw if a property is missing?
No, it does not throw by default. Missing properties simply remain as their default values (null for reference types, zero for numbers). You can enable strict mode using JsonSerializerOptions.IgnoreUnknownPropertyNames = false if needed, but this controls unknown properties, not missing ones.
How do I handle case sensitivity in JSON keys?
By default, System.Text.Json is case-sensitive. To ignore case during deserialization, set PropertyNameCaseInsensitive = true in your JsonSerializerOptions. This allows your C# properties to match JSON keys regardless of capitalization.
Can I update only one part of a large JSON file?
Yes, using JsonDocument or JsonNode allows you to navigate to specific nodes and modify them without reloading the entire file. However, for very large files, consider using streaming APIs to avoid high memory consumption.
What is the performance difference between dynamic and typed approaches?
Strongly-typed deserialization is generally faster because it uses compiled reflection. Dynamic parsing incurs slight overhead due to runtime type resolution. For high-throughput applications, prefer typed classes.
Is it safe to store JSON configs in source control?
No, never commit files containing secrets or API keys. Use .gitignore to exclude sensitive JSON files. Always replace hardcoded values with environment variable references in your deployment pipelines.