Skip to content
Back to Blog
By JSONConvert Team··6 min read

JSON to C# Classes: Generate .NET Types Fast

You have a JSON payload from an API and you need to deserialize it in C#. Writing the class by hand means converting camelCase JSON keys to PascalCase properties, adding [JsonPropertyName] attributes for every field that doesn't match, figuring out which fields can be null, and defining sub-classes for nested objects. For a response with 15 fields and two nested objects, that's 30+ lines of boilerplate before you write a single line of logic.

Generate the scaffold from your JSON instead, then refine it.

JSON Types to C# Types

The mapping from JSON primitives to C# types is mostly direct, with a few decisions to make.

JSON typeC# typeNotes
stringstringNullable in C# 8+ unless initialized
number (integer)int or longUse long if values exceed 2,147,483,647
number (float)double or decimaldecimal for financial data
booleanboolDirect mapping
nullT?Make the type nullable
objectnested classDefine a separate class
arrayListT is the element type
The tricky case is JSON number. JSON doesn't distinguish between integers and floats - 42 and 42.0 are both valid. When you see 42 in a payload, use int. When you see 42.5 or you know the field can be fractional, use double. For currency, always use decimal.

A Real Example: Stripe Charge Object

Take a simplified Stripe charge response:

The generated C# class with System.Text.Json attributes:

Paste your own API response into the JSON to C# class generator to produce this in one click.

System.Text.Json vs Newtonsoft.Json

.NET 5+ ships System.Text.Json in the standard library. Newtonsoft.Json (Json.NET) is the older library that dominated for years and is still common in legacy codebases and NuGet packages.

The attribute names differ:

PurposeSystem.Text.JsonNewtonsoft.Json
Map JSON key to property[JsonPropertyName("key")][JsonProperty("key")]
Ignore a property[JsonIgnore][JsonIgnore]
Enum as string[JsonConverter(typeof(JsonStringEnumConverter))][JsonConverter(typeof(StringEnumConverter))]
If you're starting a new project, use System.Text.Json. It's faster, allocates less, and has no extra dependency. The only reason to reach for Newtonsoft is if you need features like polymorphic deserialization with $type discriminators in .NET 6 or earlier (STJ added limited support in .NET 7).

Handling Nullable Fields

C# 8 introduced nullable reference types. If your project has enable in the .csproj (the default for new .NET 6+ projects), non-nullable string properties will produce compiler warnings if they might be null.

For fields the API guarantees will always be present, initialize with a default:

For fields that can legitimately be null (like failure_message above), use the nullable form:

Don't use string? everywhere just to silence warnings. That hides real nullability information and leads to null reference exceptions downstream. If you know the API always returns a value, make the property non-nullable.

Arrays and Lists

When a JSON field is an array of objects, the C# property should be List where T is a class matching the element shape.

Initialize list properties with = new() to avoid null reference issues when the JSON field is absent or the array is empty.

Deserializing the Result

Once you have the class, deserialization is one line:

For Newtonsoft.Json:

If you're using HttpClient in an ASP.NET Core project, skip the intermediate string and deserialize directly from the response:

ReadFromJsonAsync handles encoding, buffering, and disposal automatically.

One thing to know: if the JSON contains fields not in your class, System.Text.Json silently ignores them by default. Usually that's fine. If you want strict validation (fail on unknown fields), configure the serializer:

UnmappedMemberHandling requires .NET 8+. In earlier versions, use a custom converter or switch to Newtonsoft, which has MissingMemberHandling.Error.

Use the JSON to C# generator to get the initial classes, then run your payload through the JSON validator to confirm it's well-formed before you start wiring up deserialization. If you're also generating TypeScript interfaces for a frontend that talks to the same API, you can paste the same JSON into both tools and get consistent types across your stack.

Related Tools