json csharp dotnet poco

JSON to C# Class Generator: From API Response to POCO in Seconds

How to use a JSON-to-C# converter to scaffold model classes from real API responses, database records, and config objects — and what to watch out for afterward.

· Updated · Mohammed Aquib Ansari

You’ve just consumed a new API. The documentation is thin, but you have a sample response. Before you can write a single line of real code, you need a model class — and writing it by hand from a large JSON blob is tedious, error-prone, and the kind of work that should be automated.

That’s what the JSON to C# converter is for.


The Core Use Case

Paste a JSON response in; get idiomatic C# classes out.

Input:

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "username": "alice_dev",
  "email": "alice@example.com",
  "registeredAt": "2025-03-12T14:30:00Z",
  "profile": {
    "bio": "Backend engineer",
    "avatarUrl": "https://example.com/avatars/alice.png",
    "followersCount": 1243
  },
  "roles": ["admin", "editor"],
  "settings": {
    "theme": "dark",
    "notifications": true
  }
}

Output:

public class Root
{
    public Guid Id { get; set; }
    public string Username { get; set; }
    public string Email { get; set; }
    public DateTime RegisteredAt { get; set; }
    public Profile Profile { get; set; }
    public List<string> Roles { get; set; }
    public Settings Settings { get; set; }
}

public class Profile
{
    public string Bio { get; set; }
    public string AvatarUrl { get; set; }
    public int FollowersCount { get; set; }
}

public class Settings
{
    public string Theme { get; set; }
    public bool Notifications { get; set; }
}

Three classes, correct property types, PascalCase naming — generated in one step.


Type Inference: What Gets Detected

The converter analyzes JSON values and infers the most specific C# type that fits:

JSON valueInferred C# type
"hello"string
"2026-01-15T09:00:00Z"DateTime
"a1b2c3d4-e5f6-7890-abcd-ef1234567890"Guid
42int
3.14double
true / falsebool
nullstring? (nullable)
{ }Nested class
[ ]List<T>
[ 1, 2, 3 ]List<int>
[ {...}, {...} ]List<ClassName>

The DateTime and Guid detection is particularly useful — without it, you’d get string for everything and have to manually identify and change those properties.


The Root Class Name Field

By default, the top-level object becomes a class named Root. If you know the semantic name of the type you’re modeling, enter it before generating:

  • Enter UserProfile → root class is public class UserProfile
  • Nested objects still get names derived from their JSON key

This saves you the rename step in your IDE afterward.


Handling Null Values

JSON APIs often return null for optional fields. The converter treats a null value as string? by default — a nullable string. In practice, you’ll want to review nullable properties and assign the correct type.

Example:

{
  "id": 1,
  "middleName": null,
  "deletedAt": null
}

Generated output:

public class Root
{
    public int Id { get; set; }
    public string? MiddleName { get; set; }
    public string? DeletedAt { get; set; }
}

DeletedAt is probably a DateTime?, not a string?. This is the kind of manual correction you’ll make after generation — but having string? is still better than string, and the property is at least correctly identified as nullable.


Arrays of Mixed Types

The JSON spec allows arrays to contain values of different types ([1, "two", true]), but C# generics don’t — and the converter doesn’t try to reconcile them. For any array, it looks at the first element only and uses that to infer T in List<T>. [1, "two", true] becomes List<int>, which will throw at deserialization time the moment it hits "two". An empty array ([]) is the one case that gets a safe fallback: List<object>. In practice, well-designed APIs don’t mix types within one array, so this rarely bites — but it’s worth knowing the tool isn’t scanning every element, just the first.


Using the Output in Real Code

The generated classes are a starting point. Several of the adjustments you’d otherwise make by hand afterward are actually options on the tool itself — set them before you generate:

1. Namespace — there’s a Namespace field right above the editor. Fill it in and the output is wrapped in a file-scoped namespace automatically:

namespace MyApp.Models;

2. Serialization attributes — the “JSON attributes” toggle adds [JsonPropertyName("...")] (from System.Text.Json.Serialization) automatically, but only for keys that can’t cleanly become PascalCase — hyphens, dots, spaces, or a leading digit:

using System.Text.Json.Serialization;

public class UserProfile
{
    [JsonPropertyName("user-id")]
    public int UserId { get; set; }
}

A plain camelCase key like username won’t get an attribute even with the toggle on — username → Username doesn’t need one to round-trip correctly with the default System.Text.Json naming policy. But if your API uses snake_case keys, the toggle won’t help either: underscores don’t trigger it, so first_name becomes FirstName with no attribute at all. For that case, configure the serializer globally instead:

var options = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower // or .CamelCase
};

3. Nullable reference types — the “Nullable types” toggle marks reference-typed properties (strings, nested classes, lists — not int/bool/DateTime/Guid) with ? proactively, even where this particular sample wasn’t null. A JSON null in the sample always produces string? regardless of this toggle, since the tool can’t infer the real type from a null value. Either way, review the result — it’s a conservative starting point, not a production-ready model.

4. Validation attributes — still manual. The tool doesn’t add [Required], [EmailAddress], or any ASP.NET validation attributes:

[Required]
[EmailAddress]
public string Email { get; set; }

5. Records for immutable models — pick “Record” instead of “Class” in the output type toggle and every property comes out as { get; init; } instead of { get; set; }. It won’t generate a positional record with a constructor like public record UserProfile(Guid Id, string Username, ...) — only the property-based form.


Practical Scenarios

Integrating a third-party REST API

You get sample responses from a vendor’s documentation or Postman collection. Generate the C# models, add a namespace, and you have a typed client model in minutes. Start calling JsonSerializer.Deserialize<VendorResponse>(json) immediately.

Building models from a database query result

If you’re using Dapper and you have a sample result set as JSON (from a monitoring tool or a test query), you can generate the class that matches the result shape. For the inverse — scaffolding the database table from the same C# model — the C# to SQL guide handles that translation. If you’re starting from JSON and need the schema too, the JSON to SQL guide generates CREATE TABLE statements directly from the sample response.

Prototyping fast

When building a proof of concept, you want to move quickly. Generate models from mock data, wire up your controller, and get the prototype running. Refine the models in a second pass.

Teaching yourself a new API

Paste a response you don’t understand. Read the generated class. The property names, types, and nesting make the API’s data model clear in C# terms — which is often more intuitive for a .NET developer than reading raw JSON.


What the Tool Doesn’t Do

  • No inheritance — all generated classes are standalone; it doesn’t detect is-a relationships between types.
  • No interfaces — it generates concrete classes, not interfaces like IUser.
  • No EF Core annotations — [Key], [ForeignKey], [Column] are not added. The output is plain POCO, not EF model.
  • No JsonIgnore or converter attributes — those require domain knowledge the tool doesn’t have.

These are intentional — the tool generates a starting scaffold, not complete production models. The 80% that is mechanical is done for you; the remaining 20% that requires judgment is left for you.


Tips

Paste real API responses, not hand-written JSON. Real responses show you the actual nullability and type patterns you’ll encounter in production.

Use a single representative sample. If you have 100 records and you want to generate from a list, paste one item from the array to get the item model, not the full array.

Combine with the JSON Formatter first. If the response is minified, run it through the JSON Formatter to verify it’s valid and see its structure clearly before generating classes.


The JSON to C# converter removes the most tedious part of integrating an API or building a new service: the initial model scaffolding. Get the classes generated, add your namespace, adjust the nullability, and start writing the code that actually matters.