Serialize anonymous types with System.Text.Json in C#

By FoxLearn 2/5/2025 7:34:53 AM   151
In C#, you can use the System.Text.Json library to serialize anonymous types by selecting properties from an existing object and serializing them into a JSON string.

Anonymous types are useful when you need to create a quick, one-off object for serialization without creating a full class.

For example, consider this simple serialization of an anonymous type:

var json = JsonSerializer.Serialize(new { book.Title, book.Author });

In this case, you're picking properties from an object (book) and formatting them as needed before serializing. You can also deserialize this JSON back into a dynamic object if necessary.

Formatting before serializing

If you need to change the format of a property during serialization, creating a custom converter is usually the default choice. However, an easier approach can be to select the property into an anonymous type and format it as needed.

For instance, imagine you want to serialize a DateTime but only include the date portion (excluding the time). You can convert the DateTime to a string with the desired format, and then serialize the anonymous type:

var eventDetails = new Event()
{
    EventName = "Tech Conference 2025",
    EventDate = DateTime.Now
};

var json = JsonSerializer.Serialize(new
{
    eventDetails.EventName,
    EventDate = eventDetails.EventDate.ToString("yyyy-MM-dd") // Only the date
}, new JsonSerializerOptions { WriteIndented = true });

Console.WriteLine(json);

This outputs:

{
  "EventName": "Tech Conference 2025",
  "EventDate": "2025-02-05"
}

Serializing a subset of properties

Sometimes, you may want to serialize only a subset of properties from an object. Instead of using [JsonIgnore] which would ignore properties globally, you can select the properties you need into an anonymous type.

For example, let's say you're logging details of a product being added to a shopping cart:

public class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
    public string SKU { get; set; }
}

public class CartLogger
{
    public void LogProduct(string action, object context) { }
}

To log just the product’s name and price, you could use an anonymous type to select only those properties:

var product = new Product
{
    Name = "Wireless Mouse",
    Price = 29.99m,
    SKU = "12345-XYZ"
};

var cartLogger = new CartLogger();
cartLogger.LogProduct("Added product to cart", new { product.Name, product.Price });

This will log the following JSON:

message=Added product to cart context={"Name":"Wireless Mouse","Price":29.99}

Changing property names to match client expectations

If your object properties are in English, but your client expects property names in another language, such as French, you can use anonymous types to map the properties:

var book = new Book()
{
    Title = "The Great Gatsby",
    Author = "F. Scott Fitzgerald",
    PublicationDate = new DateTime(1925, 4, 10)
};

var json = JsonSerializer.Serialize(new
{
    titre = book.Title,                   // 'Title' in French
    auteur = book.Author,                  // 'Author' in French
    dateDePublication = book.PublicationDate.ToShortDateString() // 'Publication Date' in French
}, new JsonSerializerOptions { WriteIndented = true });

Console.WriteLine(json);

This would output:

{
  "titre": "The Great Gatsby",
  "auteur": "F. Scott Fitzgerald",
  "dateDePublication": "4/10/1925"
}

In this example, we manually map the object’s properties to the expected French names using an anonymous type.

Serializing internal properties

By default, JsonSerializer only serializes public properties. But what if you need to serialize an internal or private property without creating a custom converter?

Imagine you have a class with an internal property:

public class SystemEvent
{
    public string Name { get; set; }
    internal DateTimeOffset HappenedAt { get; set; }
    
    public SystemEvent()
    {
        HappenedAt = DateTimeOffset.Now;
    }
}

To serialize the internal property HappenedAt, you can use reflection to get its value and then serialize it with an anonymous type:

var sysEvent = new SystemEvent()
{
    Name = "System Update",
};

var json = JsonSerializer.Serialize(new
{
    sysEvent.Name,
    HappenedAt = typeof(SystemEvent)
        .GetProperty("HappenedAt", BindingFlags.NonPublic | BindingFlags.Instance)
        .GetValue(sysEvent)
}, new JsonSerializerOptions { WriteIndented = true });

Console.WriteLine(json);

This will output the following JSON:

{
  "Name": "System Update",
  "HappenedAt": "2025-02-05T07:48:35.0491977-05:00"
}

This approach works even when your code doesn't have direct access to the internal property, allowing for more flexibility without the need for custom converters.

Using anonymous types with System.Text.Json allows you to easily customize the serialization of your objects. Whether you're changing property names, formatting values, or serializing only a subset of properties, anonymous types provide a quick and effective solution.