System.Text.Json — the modern default
using System.Text.Json;
// straight onto a type
var user = JsonSerializer.Deserialize<User>(json);
// with the options you almost always want
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
};
var user2 = JsonSerializer.Deserialize<User>(json, options);
// back to a string
string output = JsonSerializer.Serialize(user, options);Shipped with .NET Core 3.0 and later, so there is no package to add. It is strict by design: it will not accept trailing commas or comments unless you opt in withAllowTrailingCommas and ReadCommentHandling.
Parsing without a class
using var doc = JsonDocument.Parse(json);
JsonElement root = doc.RootElement;
int id = root.GetProperty("id").GetInt32();
string name = root.GetProperty("user").GetProperty("name").GetString();
foreach (JsonElement item in root.GetProperty("items").EnumerateArray())
Console.WriteLine(item.GetProperty("sku").GetString());JsonDocument is read-only and pooled, so dispose it — hence the using. When you need to modify the tree before writing it back, JsonNode.Parse gives you a mutable equivalent with indexer syntax.
Newtonsoft.Json
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
var user = JsonConvert.DeserializeObject<User>(json);
string output = JsonConvert.SerializeObject(user, Formatting.Indented);
// LINQ to JSON, no class required
JObject obj = JObject.Parse(json);
string name = (string)obj["user"]["name"];
var skus = obj.SelectTokens("$.items[*].sku"); // JsonPathSelectTokens and JsonPath support are the main reason Newtonsoft still earns its place — System.Text.Json has no equivalent query syntax.
The mistakes that cost the most time
- Silent nulls from casing. Deserialization does not throw when a name does not match; the property simply stays at its default. Turn on case insensitivity early.
- Missing setters. System.Text.Json needs a public setter (or a constructor parameter) to populate a property. Read-only auto-properties stay empty.
- Double-encoded strings. If
Deserialize<string>succeeds where you expected an object, the payload was serialized twice — deserialize the result again. The converter above unwraps these for you. - Records and required members. Positional records work well with both libraries, and
requiredmembers give you a compile-time nudge that[JsonRequired]only checks at runtime.
Nullable reference types and JSON
Enabling nullable reference types makes a promise the deserializer does not keep. A property declared as string Name looks non-nullable to the compiler, but if the JSON omits that field you get null at runtime and aNullReferenceException somewhere downstream. Nothing inSystem.Text.Json checks this by default.
Two things help. Mark genuinely optional fields as nullable (string?) so the compiler forces you to handle the absent case, and mark genuinely required ones with therequired modifier — on .NET 7 and later, System.Text.Json honours it and throws during deserialization rather than silently handing you an incomplete object. For anything crossing a trust boundary, validate after deserializing regardless; the type system describes your intent, not the payload's actual contents.
Source generation
System.Text.Json uses reflection by default, which costs startup time and does not survive trimming or ahead-of-time compilation. Declaring a partialJsonSerializerContext with [JsonSerializable(typeof(User))] moves the work to compile time: the serializer is generated as ordinary source, startup gets faster, and Native AOT and Blazor WebAssembly builds stop failing with trimming warnings. If you are writing a minimal API or anything that runs in a container where cold start matters, it is worth setting up early — retrofitting it later means touching every serialization call site.
Naming, briefly
C# convert string to JSON, c# string to json,convert string to JSON c#, string to JSON c#, convert JSON string to object, and parse JSON C# example queries all land on the same two methods:Deserialize in, Serialize out. If you need to convert JSON to string C# online rather than in code — to check a payload, or to format JSON to a C# string before pasting it into a test — use the free string to JSON converter online above without a project open.