Skip to content

JSON Formatter — C# source

Beautify, minify and validate JSON instantly. Paste, format, copy - all in your browser. Share a link to your exact input.

This is the C# implementation — the same logic the interactive tool runs, in a shareable, citable form.

// json-formatter — parse, pretty-print (2-space indent), and minify.
//
// Language: C# (C# 12 / .NET 8, standard library: System.Text.Json)
// Source:   CosmoDev polyglot showcase port of the `json-formatter` tool,
//           ported from src/tools/JsonFormatter.tsx (the canonical
//           TypeScript island).
// License:  display source — part of CosmoDev's polyglot tool pages.
//
// Unlike the Rust/C/C++/Java ports (hand-written parsers, because those
// languages ship no JSON engine), .NET's base class library includes
// System.Text.Json — so this port delegates to JsonNode, which preserves
// object-member insertion order just like a JavaScript engine, renders
// empty containers as [] / {} even when indented (matching
// JSON.stringify), and reports JsonException with line/position info.
//
// Parity caveats: integers up to long (2^63) round-trip exactly — wider
// than JS Number's 2^53 — and doubles print via .NET's shortest
// round-trip form, which can differ from ECMAScript's Number::toString
// near the exponential-notation thresholds.

using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Nodes;

namespace CosmoDev.Polyglot;

/// <summary>Selects the output shape.</summary>
public enum Mode
{
    Beautify,
    Minify,
}

/// <summary>Mirrors the TypeScript { output, error } shape. Error is null
/// on success or empty input.</summary>
public record FormatResult(string Output, string? Error = null);

public static class JsonFormatter
{
    /// <summary>
    /// Parse and re-emit a JSON document the way the live island does.
    /// <para>
    /// - empty / whitespace-only input -> empty output, no error<br/>
    /// - valid JSON + Minify   -> compact JSON (no whitespace)<br/>
    /// - valid JSON + Beautify -> indent-space-indented JSON<br/>
    /// - invalid JSON          -> empty output, error message
    /// </para>
    /// </summary>
    /// <param name="input">Raw JSON text.</param>
    /// <param name="mode">Beautify (indented) or Minify (compact).</param>
    /// <param name="indent">Spaces per nesting level for Beautify (the UI passes 2).</param>
    public static FormatResult FormatJson(string input, Mode mode = Mode.Beautify, int indent = 2)
    {
        string raw = input.Trim();
        if (raw.Length == 0)
            return new FormatResult("");

        JsonNode? parsed;
        try
        {
            // JsonNode.Parse rejects comments and trailing commas by
            // default, matching JSON.parse strictness.
            parsed = JsonNode.Parse(raw);
        }
        catch (JsonException e)
        {
            // e.Message includes line/position, matching the engine-message
            // feel of the island's e.message.
            return new FormatResult("", e.Message);
        }

        var options = new JsonSerializerOptions
        {
            // Leave non-ASCII characters unescaped, like JSON.stringify —
            // unlike the HTML-safe default encoder.
            Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
            WriteIndented = mode == Mode.Beautify,
            IndentSize = indent, // .NET 8+; the default of 2 matches the UI
        };
        // JsonNode.Parse returns null for the literal "null"; emit it back.
        return new FormatResult(parsed?.ToJsonString(options) ?? "null");
    }
}

public static class Program
{
    public static void Main()
    {
        const string sample =
            """{"name":"CosmoDev","tools":["json","base64"],"free":true,"nested":{"ok":1}}""";
        FormatResult result = JsonFormatter.FormatJson(sample);
        Console.WriteLine(result.Error ?? result.Output);
    }
}

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →