Skip to main content
๐Ÿ“œ WAYPOINT LESSON

Serializing, Deserializing, and Options

โญโญ intermediateโณ 17 min read๐Ÿ“ Lesson 129 of 265

JsonSerializer with naming policies, case sensitivity, and round-trip fidelity.

The two workhorses

string json = JsonSerializer.Serialize(order);
var back = JsonSerializer.Deserialize<Order>(json);

Serialize turns objects into JSON text; Deserialize parses text into a typed object. Deserialization REQUIRES the target type โ€” that's how JSON becomes checked C# instead of string soup.

Naming policies

C# is PascalCase, JSON APIs usually camelCase:

var options = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
};
string json = JsonSerializer.Serialize(order, options);

Without the policy, OrderTotal serializes as "OrderTotal" โ€” surprising every JavaScript caller. Pick one convention per API and keep it.

Case sensitivity is a feature

By default, deserialization is CASE-SENSITIVE: "total" does NOT bind to a Total property, and silently stays default. ASP.NET's web defaults differ (PropertyNameCaseInsensitive = true) โ€” know which world you're in. When parsing external payloads, decide deliberately; mismatches become nulls/zeros, not errors.

Round-trip fidelity

Serialize(Deserialize(json)) should preserve data. Frequent breakers:

  • properties without setters (silently skipped on deserialize),
  • object-typed members (typed as JsonElement on the way back),
  • dictionaries with non-string keys,
  • timezone-less DateTimes (kind is preserved, but check your contract).

Check your understanding

  • What happens to "orderTotal" with no naming policy? (Doesn't bind to OrderTotal โ€” silently default.)
  • Why prefer typed deserialization over JsonDocument for API payloads? (Type checks shape; defaults surface missing data; refactoring is compiler-checked.)