C# models from real payloads
ASP.NET Core, Azure Functions, MAUI and console tools all need model classes to deserialize JSON. Visual Studio’s “Paste JSON as Classes” exists, but it targets older conventions and is not available everywhere. This generator produces modern System.Text.Json code from a sample, with nullable reference types enabled, so the compiler warns you about values that may be missing.
Generated code
- Every JSON object becomes a
public partial classwith auto-properties ({ get; set; }) in PascalCase. - Each property carries
[JsonPropertyName("first-name")]with the original key, so casing and punctuation in the JSON never matter. - Whole numbers become
long, other numbersdouble, plusboolandstring; arrays becomeList<T>. - Objects in an array are merged into one class. Value-type properties that are missing or
nullin part of the sample become nullable (long?,double?), and strings becomestring?. Properties absent from some samples also get[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]so serialising does not add them back asnull. - A key that is only ever
nullis typedobject. - An array mixing value types gets a
partial structwith one nullable field per type, implicit conversion operators and aJsonConverter, registered in a sharedConverter.Settings.
Helpers make the classes easy to use: Root.FromJson(json) deserializes with the right settings, and a ToJson() extension method serializes back. A root array makes FromJson return List<Root>.
The file starts with #nullable enable and suppresses a few nullable warnings that would otherwise fire on uninitialised properties.
Options
Root type name (default Root) names the top-level class, converted to PascalCase. Namespace (default Example) wraps everything in a namespace such as Acme.Billing; an invalid value falls back to the default.
Notes
The code needs only System.Text.Json, which ships with .NET Core 3.0 and later. Date strings remain string because the sample alone cannot prove their format; change them to DateTimeOffset or DateOnly if appropriate. Large integers above 2^53 cause a warning — long handles up to 2^63, and decimal or string are options beyond that. Prefer records? Copy the property types and attributes into a positional record. The classes are generated without uploading anything, and the C# formatter can reformat the output.
In ASP.NET Core you rarely call FromJson yourself: use the class as a controller parameter or with HttpClient.GetFromJsonAsync<Root>(). In that case the property attributes still apply, but converters registered in Converter.Settings (used for mixed-type arrays) must be added to your app’s JsonSerializerOptions too. Feed the sample several array items so optional properties are detected correctly.
Examples
Invoice with line items
Creates Invoice, Customer and Line classes in Acme.Billing; discount becomes long? with a WhenWritingNull ignore attribute.
{
"invoiceNumber": "INV-2026-091",
"issued": "2026-09-14",
"customer": { "id": 1042, "name": "Aisha Tan", "taxId": null },
"lines": [
{ "description": "Mechanical keyboard", "quantity": 1, "unitPrice": 129.9 },
{ "description": "Wireless mouse", "quantity": 2, "unitPrice": 79.0, "discount": 5 }
],
"paid": false
}// <auto-generated />
//
// To parse this JSON data, add NuGet 'System.Text.Json' then do:
//
// using Acme.Billing;
//
// var invoice = Invoice.FromJson(jsonString);
#nullable enable
#pragma warning disable CS8618
#pragma warning disable CS8601
#pragma warning disable CS8602
#pragma warning disable CS8603
namespace Acme.Billing
{
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Globalization;
public partial class Invoice
{
[JsonPropertyName("invoiceNumber")]
public string InvoiceNumber { get; set; }
[JsonPropertyName("issued")]
public string Issued { get; set; }
[JsonPropertyName("customer")]
public Customer Customer { get; set; }
[JsonPropertyName("lines")]
public List<Line> Lines { get; set; }
[JsonPropertyName("paid")]
public bool Paid { get; set; }
}
public partial class Customer
{
[JsonPropertyName("id")]
public long Id { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("taxId")]
public object TaxId { get; set; }
}
public partial class Line
{
[JsonPropertyName("description")]
public string Description { get; set; }
[JsonPropertyName("quantity")]
public long Quantity { get; set; }
[JsonPropertyName("unitPrice")]
public double UnitPrice { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("discount")]
public long? Discount { get; set; }
}
public partial class Invoice
{
public static Invoice FromJson(string json) => JsonSerializer.Deserialize<Invoice>(json, Acme.Billing.Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this Invoice self) => JsonSerializer.Serialize(self, Acme.Billing.Converter.Settings);
}
internal static class Converter
{
public static readonly JsonSerializerOptions Settings = new(JsonSerializerDefaults.General)
{
Converters =
{
},
};
}
}
#pragma warning restore CS8618
#pragma warning restore CS8601
#pragma warning restore CS8602
#pragma warning restore CS8603
Array root
FromJson returns List<StockLevel>, qty is long? because one value is null, and price is double? because one item lacks it.
[
{ "id": 1, "qty": 2, "price": 19.99 },
{ "id": 2, "qty": null }
]// <auto-generated />
//
// To parse this JSON data, add NuGet 'System.Text.Json' then do:
//
// using Example;
//
// var stockLevel = StockLevel.FromJson(jsonString);
#nullable enable
#pragma warning disable CS8618
#pragma warning disable CS8601
#pragma warning disable CS8602
#pragma warning disable CS8603
namespace Example
{
using System;
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Globalization;
public partial class StockLevel
{
[JsonPropertyName("id")]
public long Id { get; set; }
[JsonPropertyName("qty")]
public long? Qty { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("price")]
public double? Price { get; set; }
}
public partial class StockLevel
{
public static List<StockLevel> FromJson(string json) => JsonSerializer.Deserialize<List<StockLevel>>(json, Example.Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this List<StockLevel> self) => JsonSerializer.Serialize(self, Example.Converter.Settings);
}
internal static class Converter
{
public static readonly JsonSerializerOptions Settings = new(JsonSerializerDefaults.General)
{
Converters =
{
},
};
}
}
#pragma warning restore CS8618
#pragma warning restore CS8601
#pragma warning restore CS8602
#pragma warning restore CS8603
Common errors and how to fix them
| Error | Cause | Fix |
|---|---|---|
Strings must use double quotes, not single quotesExplained | The sample uses single-quoted strings, which JSON does not allow. | Replace them with double quotes, or run the text through JSON5 to JSON. |
Trailing comma before ']'Explained | An array ends with a comma, common in hand-written samples. | Delete the trailing comma. |
Some integers are larger than 2^53; they are typed as floating-point numbers. Use a 64-bit or big-integer type if you need exact values.Explained | A warning: the sample includes very large integer IDs. | Change those properties to long, decimal or string after generating. |
Frequently asked questions
Does it support Newtonsoft.Json?
The attributes target System.Text.Json. For Newtonsoft, swap [JsonPropertyName] for [JsonProperty] and replace the converter with a Newtonsoft JsonConverter.
Why are the classes partial?
So you can add methods or computed properties in another file without editing the generated code.
What are the #pragma lines for?
They silence nullable warnings about properties that are not initialised in a constructor, which is normal for deserialization models.
Is my JSON uploaded?
No. The classes are generated in your browser and your payload stays local.