Saltar al contenido principal

Convertir JSON a C#

JSON to C# generates classes or records from a sample document in your browser. Property names are PascalCase and every one carries an explicit attribute with the original JSON key, because System.Text.Json is case-sensitive by default and a PascalCase property will not bind to a snake_case key without being told to.

Solo local

La interfaz de esta herramienta está en inglés.

Shape
Sample JSON
0 B1 lineLn 1, Col 1
Syntax error at line 1, column 1

Empty JSON input (truncated document)


^
Generated coderead-only
0 B1 line
Paste more than one record if you have them. A field present in some records and absent from others is only detectable across samples, and it is the difference between a type that matches your data and one that matches your first row.

La guía de abajo solo está disponible en inglés.

How does JSON to C# Classes work?

C# is the target where the nullable reference type setting changes what correct output looks like, so the generator treats it as a first-class option rather than a formatting preference.

Nullable reference types decide the shape of every member

Under <Nullable>enable</Nullable>, which is the default on every template since .NET 6, a string property that JSON can leave absent is a warning waiting to happen and a NullReferenceException if the warning is ignored. Optional and nullable fields therefore get ? — which on a value type is Nullable<T> and on a reference type is the annotation. Both are spelled T?, which is one of the tidier things about the language.

Non-nullable members need an initialiser or CS8618 fires on every one

A required string Name { get; set; } warns that it is uninitialised, because the compiler cannot see that a deserializer will fill it. The conventional generated-code answer is = null!; — an explicit promise to the compiler that something else assigns it. Without it the generated file produces one warning per property, which people fix by turning nullable off, which throws away the reason to use it.

Attributes are explicit, not conventions

System.Text.Json matches property names case-sensitively unless configured otherwise, so UserId does not bind to user_id and quietly stays null. Every property gets a [JsonPropertyName] (or [JsonProperty] for Newtonsoft) carrying the exact original key, so the class works regardless of what the serializer options happen to be.

class or record

A record is the better default for a deserialized payload — value equality and a readable ToString come free, and a DTO should not be mutated after it arrives. Plenty of code still expects a mutable class with settable properties, so both are available.

long where int would truncate

int is 32-bit. Any sample value beyond 2,147,483,647 — a snowflake ID, a millisecond timestamp — is emitted as long, because a truncated ID is a bug that only appears once real data arrives.

Sample

[
  { "user_id": 900719925474099, "name": "Ada" },
  { "user_id": 12, "name": "Grace", "team": "ops" }
]

Generated

public class User
{
    [JsonPropertyName("user_id")]
    public long UserId { get; set; }

    [JsonPropertyName("name")]
    public string Name { get; set; } = null!;

    [JsonPropertyName("team")]
    public string? Team { get; set; }
}

What options and edge cases does JSON to C# Classes support?

Options and mapping rules
ParameterTypeDefaultBehaviour & edge cases
Shapeclass / recordclassrecord gives value equality and a useful ToString, which suits a DTO. class stays mutable and is what older code expects.
NamespaceidentifierGeneratedWraps the output in a namespace block. Leave it empty to emit bare types for a file that already has one.
System.Text.JsonbooleanonEmits [JsonPropertyName] and the matching using. Turn it off for [JsonProperty] and Newtonsoft.Json, which is still the right choice for anything on .NET Framework.
nullablebooleanonEmits #nullable enable, marks optional members T?, and initialises required reference members with = null! so CS8618 does not fire on every property.
stringC# typestringDetected formats are not mapped to DateTime or Guid. System.Text.Json parses ISO 8601 into DateTime if you change the type by hand, but it throws on any record that formats a date differently.
integerC# typeint / longlong when any sample exceeds 2,147,483,647. JSON numbers have no declared width, so this is read from the values.
arrayC# typeList<T>List<T> rather than T[], because both serializers handle it and it is what calling code usually wants. An array of mixed types becomes List<object>.
Nested objectclassown typePromoted to its own class, declared before the type that uses it. Identical shapes share one class rather than generating Address, Address2, Address3.

Frequently asked questions

Why does every property have an attribute when my keys are already PascalCase?

Because the binding is only guaranteed with one. System.Text.Json matches case-sensitively unless PropertyNameCaseInsensitive is set, and even then it will not bridge user_id to UserId — that needs a naming policy the generated class cannot assume is configured. An explicit attribute makes the class correct under any serializer options, which is worth the line.

What is = null! and can I delete it?

It tells the compiler that a non-nullable reference property will be assigned by something it cannot see — the deserializer — and suppresses CS8618. You can delete it if you make the property required (C# 11) or initialise it in a constructor. What you should not do is turn nullable reference types off to make the warnings go away, which is the usual reaction and throws away the feature that would have caught the real null.

Should I use record or class?

record for a payload you deserialize and read: value equality makes tests much cleaner and immutability is correct for data that arrived from elsewhere. class if the object is going to be mutated, if you are on a framework older than C# 9, or if an existing codebase expects settable properties everywhere.

Why is my date a string?

Because generating DateTime from a sample would produce a class that throws on the first record whose date is formatted differently. System.Text.Json only accepts ISO 8601, and real APIs emit Unix timestamps, US-format dates and offsets-without-colons. The detected format is noted so you can change the type deliberately, with a converter if the format needs one.

Newtonsoft or System.Text.Json?

System.Text.Json for anything on modern .NET — it is in the box, it is significantly faster, and it is where the investment is going. Newtonsoft if you are on .NET Framework, or if you depend on something System.Text.Json still does not do: TypeNameHandling, custom contract resolvers, or the more forgiving parsing of malformed input. The generator emits the right attributes either way.

Is my JSON uploaded?

No. The document is parsed, the types are inferred and the code is rendered in the tab you already have open. You can confirm it in the Network panel. This matters for the usual reason: the samples people paste into a class generator are real responses, frequently with customer data still in them.