Working with JSON in C#

C# offers two main libraries for JSON: the built-in System.Text.Json (.NET Core 3.0+) and the popular Newtonsoft.Json (Json.NET). This guide covers both.

System.Text.Json (Built-in)

Deserializing JSON

using System.Text.Json;

// Define a class
public class User
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Email { get; set; }
    public bool IsActive { get; set; }
}

// Deserialize JSON string
string json = "{\"name\": \"John\", \"age\": 30, \"email\": \"john@example.com\", \"isActive\": true}";

var options = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true
};

User user = JsonSerializer.Deserialize(json, options);
Console.WriteLine(user.Name);  // John
Console.WriteLine(user.Age);   // 30

Serializing to JSON

using System.Text.Json;

var user = new User
{
    Name = "Jane",
    Age = 25,
    Email = "jane@example.com",
    IsActive = true
};

// Basic serialization
string json = JsonSerializer.Serialize(user);
Console.WriteLine(json);
// {"Name":"Jane","Age":25,"Email":"jane@example.com","IsActive":true}

// Pretty print with options
var options = new JsonSerializerOptions
{
    WriteIndented = true,
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};

string prettyJson = JsonSerializer.Serialize(user, options);
Console.WriteLine(prettyJson);

JsonDocument for Dynamic JSON

using System.Text.Json;

string json = "{\"name\": \"John\", \"address\": {\"city\": \"New York\"}, \"tags\": [\"developer\"]}";

using JsonDocument doc = JsonDocument.Parse(json);
JsonElement root = doc.RootElement;

// Access properties
string name = root.GetProperty("name").GetString();
string city = root.GetProperty("address").GetProperty("city").GetString();

// Access array
JsonElement tags = root.GetProperty("tags");
foreach (JsonElement tag in tags.EnumerateArray())
{
    Console.WriteLine(tag.GetString());
}

// Check if property exists
if (root.TryGetProperty("email", out JsonElement email))
{
    Console.WriteLine(email.GetString());
}

Attributes and Customization

using System.Text.Json.Serialization;

public class User
{
    // Rename property in JSON
    [JsonPropertyName("user_name")]
    public string Name { get; set; }

    // Ignore property
    [JsonIgnore]
    public string Password { get; set; }

    // Ignore if null
    [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
    public string? MiddleName { get; set; }

    // Number handling
    [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
    public int Age { get; set; }
}

Newtonsoft.Json (Json.NET)

Install via NuGet: Install-Package Newtonsoft.Json

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

public class User
{
    public string Name { get; set; }
    public int Age { get; set; }
}

// Deserialize
string json = "{\"name\": \"John\", \"age\": 30}";
User user = JsonConvert.DeserializeObject(json);

// Serialize
string output = JsonConvert.SerializeObject(user);

// Pretty print
string prettyJson = JsonConvert.SerializeObject(user, Formatting.Indented);

JObject for Dynamic JSON

using Newtonsoft.Json.Linq;

string json = "{\"name\": \"John\", \"address\": {\"city\": \"New York\"}}";

// Parse to JObject
JObject obj = JObject.Parse(json);

// Access values
string name = (string)obj["name"];
string city = (string)obj["address"]["city"];

// Modify
obj["age"] = 30;

// Create JObject
var newObj = new JObject
{
    ["name"] = "Jane",
    ["age"] = 25
};

Console.WriteLine(newObj.ToString());

JSON Validation

using System.Text.Json;

public class JsonValidator
{
    public static bool IsValidJson(string json)
    {
        try
        {
            JsonDocument.Parse(json);
            return true;
        }
        catch (JsonException)
        {
            return false;
        }
    }

    public static ValidationResult ValidateJson(string json)
    {
        try
        {
            using var doc = JsonDocument.Parse(json);
            var type = doc.RootElement.ValueKind switch
            {
                JsonValueKind.Object => "object",
                JsonValueKind.Array => "array",
                JsonValueKind.String => "string",
                _ => "unknown"
            };
            return new ValidationResult(true, null, type);
        }
        catch (JsonException ex)
        {
            return new ValidationResult(false, ex.Message, null);
        }
    }
}

public record ValidationResult(bool IsValid, string? Error, string? Type);

Working with Files

using System.Text.Json;
using System.IO;

// Read JSON file
string json = await File.ReadAllTextAsync("data.json");
var user = JsonSerializer.Deserialize(json);

// Write JSON file
var options = new JsonSerializerOptions { WriteIndented = true };
string output = JsonSerializer.Serialize(user, options);
await File.WriteAllTextAsync("output.json", output);

// Stream-based (memory efficient)
await using FileStream stream = File.OpenRead("data.json");
var data = await JsonSerializer.DeserializeAsync(stream);

HTTP API Example

using System.Net.Http.Json;

var httpClient = new HttpClient();

// GET JSON
var user = await httpClient.GetFromJsonAsync("https://api.example.com/user");

// POST JSON
var newUser = new User { Name = "John", Email = "john@example.com" };
var response = await httpClient.PostAsJsonAsync("https://api.example.com/users", newUser);
var createdUser = await response.Content.ReadFromJsonAsync();

// ASP.NET Core Controller
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
    [HttpGet("{id}")]
    public ActionResult Get(int id)
    {
        var user = new User { Name = "John", Age = 30 };
        return Ok(user);
    }

    [HttpPost]
    public ActionResult Create([FromBody] User user)
    {
        return CreatedAtAction(nameof(Get), new { id = 1 }, user);
    }
}

Best Practices