What this tool does
Generate C# classes with serializer attributes from a JSON sample. Use the namespace option to scope the generated types to your project. Default output targets Newtonsoft.Json (JsonProperty); the generated shape is also valid for System.Text.Json once you swap the attribute name. Powered by quicktype, runs entirely in your browser.
How to use it
Paste JSON (or load the example) and read the C# classes on the right. Set the namespace in the options pane to drop the file straight into your project; default output targets Newtonsoft.Json attributes.
Input: {"id":42,"name":"devsmiths","createdAt":"2024-03-11T08:24:00Z","stars":1280,"public":true,"contributors":[{"login":"ada","commits":51,"admin":true},{"login":"linus","commits":33,"admin":false}],"homepage":null}
Output (C#):
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace Devsmiths
{
public partial class Root
{
[JsonProperty("id")] public long Id { get; set; }
[JsonProperty("name")] public string Name { get; set; }
[JsonProperty("createdAt")] public string CreatedAt { get; set; }
[JsonProperty("stars")] public long Stars { get; set; }
[JsonProperty("public")] public bool Public { get; set; }
[JsonProperty("contributors")] public Contributor[] Contributors { get; set; }
[JsonProperty("homepage")] public object Homepage { get; set; }
}
public partial class Contributor
{
[JsonProperty("login")] public string Login { get; set; }
[JsonProperty("commits")] public long Commits { get; set; }
[JsonProperty("admin")] public bool Admin { get; set; }
}
}Limits and edge cases
- Default output targets Newtonsoft.Json (
JsonProperty). For .NET 6+ System.Text.Json, find/replaceJsonProperty→JsonPropertyNameandusing Newtonsoft.Json→using System.Text.Json.Serialization— the property shapes are otherwise identical. - Properties are
publicauto-properties (get; set;), not records. For C# 9+ records, the shape doesn’t round-trip throughSystem.Text.Jsonas-is because records’ primary constructor needs[JsonConstructor]+ ordered parameters — out of scope for a syntactic generator. - Nullable reference types aren’t marked. If your project has
<Nullable>enable</Nullable>in the csproj, add?to reference-type properties by hand (or accept the warnings). Value types (long,bool) use?automatically where the sample showsnull. - Date strings stay as
string, notDateTime/DateTimeOffset. ISO 8601 strings are unambiguous, but mixing serializer attributes for date conversion is brittle — handle conversion in a customJsonConverterif you need typed dates. - Arrays are emitted as
T[], notList<T>. Both deserialise correctly with Newtonsoft.Json and System.Text.Json; switch toList<T>by hand if you need.Add()at runtime. - Single-sample inference: missing keys in the sample don’t become nullable. Toggle all optional if every field should be optional.
Frequently asked questions
- Newtonsoft.Json or System.Text.Json — which is the output?
- Default is Newtonsoft.Json (the `[JsonProperty]` attribute, `using Newtonsoft.Json`). Newtonsoft is more permissive and more widely used in legacy projects. For System.Text.Json (the stdlib option in .NET 6+), do a find/replace: `[JsonProperty("foo")]` → `[JsonPropertyName("foo")]` and `using Newtonsoft.Json` → `using System.Text.Json.Serialization`. The property shapes are otherwise identical.
- Why aren't records generated for C# 9+?
- Records would be a nice fit (immutable, value-based equality, fewer lines) but their primary-constructor parameters don't round-trip through System.Text.Json without `[JsonConstructor]` annotations and careful ordering — easy to break, easy to silently misalign. The generator stays with `public class { get; set; }` properties because they round-trip with zero ceremony in both serializers.
- How do I get nullable reference types to play nicely with #nullable enable?
- Value types (long, bool) automatically get `?` where the sample contains null. Reference types (string, object) don't — the generator emits them unmarked. With `<Nullable>enable</Nullable>`, add `?` by hand to fields that can be null. The generator is conservative here because mass-marking everything `string?` propagates null-checks through your call site that you may not want.
- Can I get DateTime / DateTimeOffset for ISO 8601 date strings?
- Not automatically — date strings stay as `string`. Workarounds: change the field type to `DateTime` and rely on the serializer's default ISO 8601 parsing (works in System.Text.Json since .NET 7); or write a `JsonConverter<DateTimeOffset>` for fields where the JSON has timezone info. DateTimeOffset is usually the right choice for wire-format dates.
- Why are arrays emitted as T[] and not List<T>?
- T[] is fixed-size but allocation-cheaper and Span-compatible; List<T> is mutable but has more allocator overhead. The generator picks T[] because deserialization treats them identically and the slimmer type is the better default. Switch to List<T> by hand for collections you'll mutate in your domain code.
- What's the JsonProperty("…") attribute doing exactly?
- It tells Newtonsoft.Json (or System.Text.Json after rename) what the JSON key is for that property. C# convention is PascalCase property names, JSON convention is camelCase or snake_case — the attribute bridges the two. Without it, Newtonsoft falls back to case-insensitive matching, which usually works but is implicit and slower; the explicit attribute is clearer and faster.
Content reviewed by ShiangYu Huang