.NET Academy

Files and JSON

Read and write files, and convert objects to and from JSON with System.Text.Json.

12 min read

You will learn

  • Read and write files with File and streams
  • Build paths portably with Path
  • Serialize and deserialize JSON with System.Text.Json
  • Control JSON naming and formatting with options and attributes

Files

System.IO covers everyday file work with simple static methods:

string path = Path.Combine(AppContext.BaseDirectory, "data", "notes.txt");
 
await File.WriteAllTextAsync(path, "Hello");                 // create or overwrite
await File.AppendAllTextAsync(path, "\nAnother line");
string text = await File.ReadAllTextAsync(path);
string[] lines = await File.ReadAllLinesAsync(path);
 
bool exists = File.Exists(path);
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
foreach (var file in Directory.EnumerateFiles("data", "*.json")) { ... }
  • Build paths with Path.Combine — it picks the right separator for Windows, Linux or macOS.
  • Prefer the async versions in servers.
  • For big files, don't load everything into memory: stream them.
await using var stream = File.OpenRead("huge-log.txt");
using var reader = new StreamReader(stream);
while (await reader.ReadLineAsync() is { } line)
{
    if (line.Contains("ERROR")) Console.WriteLine(line);
}
 
// Or simply — lazily, one line at a time:
foreach (var line in File.ReadLines("huge-log.txt")) { ... }

Files on servers

Remember the stateless rule: a web server's local disk may disappear with the instance. Store uploads and generated files in object storage (Azure Blob Storage, Amazon S3), and data in a database.

JSON with System.Text.Json

JSON is the lingua franca of web APIs and config files. .NET's built-in System.Text.Json converts objects to JSON (serialization) and back (deserialization):

using System.Text.Json;
 
record Product(int Id, string Name, decimal Price, string[] Tags);
 
var product = new Product(1, "Laptop", 999m, ["electronics", "sale"]);
 
string json = JsonSerializer.Serialize(product);
// {"Id":1,"Name":"Laptop","Price":999,"Tags":["electronics","sale"]}
 
Product? back = JsonSerializer.Deserialize<Product>(json);

Options

var options = new JsonSerializerOptions(JsonSerializerDefaults.Web)   // camelCase + case-insensitive
{
    WriteIndented = true,                                             // pretty-print
};
 
string pretty = JsonSerializer.Serialize(product, options);
// {
//   "id": 1,
//   "name": "Laptop",
//   ...

Reuse options instances — creating them is relatively expensive. ASP.NET Core uses web defaults automatically for request and response bodies.

Attributes

public class User
{
    [JsonPropertyName("user_name")]   // custom JSON name
    public string Name { get; set; } = "";
 
    [JsonIgnore]                      // never serialized
    public string PasswordHash { get; set; } = "";
 
    [JsonConverter(typeof(JsonStringEnumConverter))]
    public Role Role { get; set; }    // "Admin" instead of 1
}

When JSON doesn't match

  • Unknown JSON properties are ignored by default.
  • Missing properties keep their default values (or fail if marked required).
  • Malformed JSON throws JsonException — catch it when the input comes from outside.

Reading JSON without a class

For quick inspection of arbitrary JSON, use the DOM types:

using var doc = JsonDocument.Parse(json);
string name = doc.RootElement.GetProperty("name").GetString()!;

Try it

Program.cs
Loading editor…

C# runtime not loaded

Key takeaways

  • File and Path cover everyday file I/O; stream large files; use async in servers.
  • JsonSerializer.Serialize / Deserialize<T> convert between objects and JSON.
  • JsonSerializerDefaults.Web gives camelCase, case-insensitive JSON — reuse options instances.
  • Customize with [JsonPropertyName], [JsonIgnore], converters; catch JsonException for untrusted input.

Exercise

Using System.Text.Json: ToJson serializes an Order with web conventions (camelCase, compact). FromJson reads an Order back (property names in any case) and returns null for invalid JSON. TotalFromJson reads a JSON array of items and returns the sum of price × qty.

Program.cs
Loading editor…

C# runtime not loaded

Hint 1

new JsonSerializerOptions(JsonSerializerDefaults.Web) gives camelCase names and case-insensitive reading — keep one in a static field or local variable and pass it to Serialize/Deserialize.

Hint 2

Invalid JSON throws JsonException — catch it and return null.

Hint 3

Deserialize the array with JsonSerializer.Deserialize<List<Item>>(json, options), then Sum(i => i.Price * i.Qty).

Show solution
using System.Text.Json;

Console.WriteLine(ToJson(new Order(1, "Ada", 9.5m)));

JsonSerializerOptions Options() => new(JsonSerializerDefaults.Web);

string ToJson(Order order) => JsonSerializer.Serialize(order, Options());

Order? FromJson(string json)
{
    try
    {
        return JsonSerializer.Deserialize<Order>(json, Options());
    }
    catch (JsonException)
    {
        return null;
    }
}

decimal TotalFromJson(string json)
{
    var items = JsonSerializer.Deserialize<List<Item>>(json, Options()) ?? [];
    return items.Sum(i => i.Price * i.Qty);
}

record Order(int Id, string Customer, decimal Total);
record Item(string Name, decimal Price, int Qty);

Quiz

4 questions · 3 correct to pass
  1. 1.Why use Path.Combine("data", "orders.json") instead of "data/orders.json"?

  2. 2.What does JsonSerializerDefaults.Web change?

  3. 3.How do you give one property a different JSON name?

  4. 4.Why prefer File.ReadAllTextAsync over File.ReadAllText in a web server?

To complete this lesson

  • ○ Solve the exercise
  • ○ Pass the quiz (3/4 correct)