How to Convert JSON to C# Class (System.Text.Json Guide)
Need a quick JSON to C# class converter? You'll find it here. Your .NET service needs to consume an upstream JSON API. The shape is twenty fields deep, the docs were last touched in 2021, and the team lead just asked for the typed model on Slack. Hand-typing the C# class from the example payload is the slowest correct way to do this. There is a faster, equally correct one.
In this guide you'll learn how to convert JSON to a C# class using PDFFlare's JSON to C# tool — how System.Text.Json maps JSON onto your properties via [JsonPropertyName], why auto-properties beat fields, how to swap to Newtonsoft.Json when you have to, and the gotchas that bite during real ASP.NET Core integrations.
System.Text.Json or Newtonsoft.Json?
System.Text.Json ships with .NET 5+ and is the modern default — faster, lower allocation, and zero extra dependencies. Newtonsoft (Json.NET) has more battle-tested edge-case support: polymorphic deserialization, custom converters, and wider .NET Framework coverage. PDFFlare emits System.Text.Json-flavour attributes by default. To switch to Newtonsoft, swap [JsonPropertyName] for [JsonProperty]and change the using directive — the class shape doesn't move.
How to Convert JSON to a C# Class (Step by Step)
- Open PDFFlare's JSON to C# tool — no signup needed.
- Paste a JSON sample. The real production payload beats a docs example every time — production has the never-documented fields the docs forgot.
- Set the root class namevia the "Root class" field.
UserResponse,StripePaymentIntent,OrderEvent— pick the domain noun. - Click Convert to C#. Each unique object shape becomes its own public class. Properties carry
[JsonPropertyName("original_key")]so System.Text.Json maps snake_case JSON onto PascalCase C# automatically. - Drop into your project. Add
using System.Text.Json.Serialization;at the top of the file.JsonSerializer.Deserialize<Root>(json)now produces a typed object.
Real Use Cases for JSON to C#
ASP.NET Core [FromBody] DTOs
Generate the request DTO from a real client payload, drop it into your controller as [FromBody] UserRequest req, and model binding handles the rest. JsonElement indexers stop appearing in your controllers.
HttpClient.GetFromJsonAsync
The System.Net.Http.Json extensions deserialize straight into your generated class: await http.GetFromJsonAsync<Order>(url). No custom converter needed when keys map cleanly via [JsonPropertyName].
Webhook integrations
Stripe, GitHub, Octopus Deploy — each documents webhooks as JSON examples. Convert each example to a strongly-typed C# class so your handler is refactor-safe.
Migrating from Node to .NET
Don't hand-port the TypeScript types. Paste real production payloads, generate fresh C# classes, and drop them into the new project tree.
Common Mistakes (and How to Avoid Them)
- Forgetting
JsonSerializerOptions.PropertyNameCaseInsensitive. If your JSON has camelCase keys but you removed the[JsonPropertyName]attributes thinking they weren't needed, set the option globally or keep the attributes. - Using
doublefor currency. Refine todecimalmanually for money fields. The inference picksdoublefor any decimal value. - Mixing System.Text.Json and Newtonsoft attributes. They co-exist in source but only one library reads each — make sure your serializer matches the attributes you applied.
- Forgetting nullable reference types. If your project has
#nullable enable, mark optional fields asstring?orint?to match the API contract.
Privacy: Your JSON Stays Local
Conversion runs in your browser. The JSON you paste never leaves your device — safe for internal payloads, customer data, and contracts containing API keys.
Related Workflows in the JSON Suite
Adjacent tools you might find useful while working on the same JSON document: the JSON to TypeScript and JSON Schema generator both pair well with the conversion above. The first handles a different output format that consumers of your data may prefer; the second covers the validation side of the same workflow.
Related Tools
- JSON to Java POJO — same idea for the JVM with Jackson annotations.
- JSON to TypeScript — matching types for your front end.
- JSON Schema Generator — pair with FluentValidation or DataAnnotations to enforce the shape at the boundary.
- JSON Formatter — pretty-print before converting so you can read the shape.
Production Patterns for JSON to C# Classes
A generated C# class is a starting point — these refinements turn it into something you'd be happy to ship in production:
Nullable Reference Types
C# 8+ enables nullable reference types via <Nullable>enable</Nullable> in your .csproj. The generator can't know whether a field is optional from a single sample, so it emits non-nullable types. After generation, mark optional fields explicitly with ?: public string? Nickname { get; set; }. That signals intent to the compiler and turns runtime null surprises into compile-time warnings.
DateTime vs DateTimeOffset
JSON has no native date type. ISO-8601 strings ("2026-05-03T14:00:00Z") deserialize fine toDateTime, but the timezone information gets lost. For APIs that span timezones, swap to DateTimeOffset — it preserves the offset and round-trips correctly. For Unix timestamps as numbers, keep them as long and convert via DateTimeOffset.FromUnixTimeSeconds() in your domain code.
Switching to Newtonsoft.Json
The generator emits [JsonPropertyName] for System.Text.Json (the modern .NET default). If your project still uses Newtonsoft.Json, find-and-replace JsonPropertyName with JsonProperty and adjust the imports. The class structure works unchanged for both serializers — only the attribute names differ.
When to Reach for a Different Approach
JSON-to-C# generation is the right tool when you have one or two representative payloads and want typed C# classes fast. A few alternatives are worth knowing:
- NSwag / OpenAPI codegen — when the upstream service publishes an OpenAPI spec, generate from that instead. You get full coverage of every endpoint and operation, not just the shapes you happened to capture.
- JSON Schema — for validation rules (required, min/max, allowed values), generate a JSON Schema from your sample first, then refine constraints, and use NJsonSchema to emit C# from the schema.
- Working in F# instead?F# discriminated unions handle polymorphic JSON gracefully. The C# generator's flat class model isn't the right primitive — use FSharp.Data JsonProvider or hand-write the discriminated unions.
- Building a Java backend instead? JSON to Java POJO emits Jackson-annotated classes for Spring Boot. Same generator philosophy, different language idioms.
Common Mistakes to Avoid
The same handful of mistakes keep tripping up teams new to generated C# classes — most stem from treating the output as finished rather than as scaffolding:
- Generating from a single sparse sample.If your JSON only includes a few of the optional fields, the generator won't see the rest. Pull two or three diverse payloads (a minimal one, a full-detail one, an edge case) and merge the resulting classes by hand. Fields appearing in some samples but not others become your nullable candidates.
- Treating numeric strings as numbers. If your payload has
"amount": "1234.50"(currency stored as a string for precision), the generator types it asstring. That's correct, but you almost certainly want adecimalfor arithmetic. Swap the type and add a customJsonConverterif you need automatic parsing. - Ignoring naming-convention mismatches. .NET properties are PascalCase. JSON keys vary: snake_case from Python, camelCase from Node, kebab-case from some Ruby APIs. The generator preserves keys via
[JsonPropertyName], but you can also configure JsonSerializerOptions globally withPropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower(.NET 8+) — saves the per-field attributes when every API uses the same convention. - Skipping immutability. Generated classes are mutable by default for compatibility with model binding. For domain models that should be immutable, refactor to use init-only setters (
{ get; init; }) or convert to a record (public record User(string Name, int Age);). Records are particularly nice for value objects in DDD-style architectures. - Forgetting validation.
System.Text.Jsonhappily deserializes a payload with missing required fields into a class with default values. Add[Required],[Range], or[StringLength]attributes fromSystem.ComponentModel.DataAnnotations— ASP.NET Core MVC binds and validates them automatically with[ApiController].
Real-World Workflow Examples
A few concrete scenarios from working .NET teams where the generator earns its keep:
- Reverse-engineering a partner's webhook payload. The partner's integration documentation shows three example payloads but no formal schema. Drop each example into the generator, merge the resulting classes by hand, and ship the integration in an afternoon instead of spending two days spelunking through their dashboard. The resulting classes serve as living documentation of the actual contract — far more reliable than a Confluence page that goes stale within a quarter.
- Building a strongly-typed API client library. When you wrap a third-party REST API as a NuGet package for internal use, you want every endpoint's request and response shape captured as a class. Generate from real captured payloads, organize the resulting classes into a clean namespace structure, and ship a discoverable client that downstream teams can use without reading the upstream docs.
- Migrating from Newtonsoft to System.Text.Json. ASP.NET Core projects that were created before .NET Core 3 use Newtonsoft.Json. When you migrate to the modern
System.Text.Json, the attribute names change. The generator emits the new attributes by default — paste the generated classes alongside your existing models, copy the relevant property attributes, and you're halfway through the migration without having to change every model file. - Decoupling a service migration.An existing Node service emits JSON; a new .NET service has to consume the same shape during the cutover. Generate matching classes from a production capture, evolve them independently going forward, and you've made the contract between the two services explicit and version-controlled in your repository.
- Replacing fragile
JObject-style code. Existing handlers that readobj["user"]?["email"]?.ToString()are brittle — every field rename in the upstream API breaks production silently. Generate a typed class instead and the compiler catches every refactor. Code review gets faster because reviewers can rely on the type names instead of mentally tracing string keys.
Wrapping Up
Hand-writing a C# class from a JSON sample is fifteen minutes of boilerplate that ages badly. Generate from a real payload with PDFFlare's JSON to C# tool and refine the parts the inference can't guess — decimal for money, nullable for optional, custom converters for polymorphism.