Selective Serialization in C#: How to Exclude Unwanted Properties

Serialization is a crucial part of modern C# applications, especially in ASP.NET Core and .NET applications that interact with APIs, databases, or other external services. However, there are scenarios where you need to exclude certain properties during serialization to optimize performance, enhance security, or control the shape of your JSON or XML output.

In this comprehensive guide, we will explore various techniques to selectively exclude properties from serialization in C# using Newtonsoft.Json, System.Text.Json, DataContract attributes, and custom converters. We’ll also discuss best practices and performance considerations to ensure efficient and secure serialization.

1. Using [JsonIgnore] Attribute (Newtonsoft.Json & System.Text.Json)

The most straightforward way to exclude properties from JSON serialization is by using the [JsonIgnore] attribute.

Newtonsoft.Json Example:

using Newtonsoft.Json;

public class User
{
    public string Name { get; set; }
    
    [JsonIgnore]
    public string Password { get; set; }
}

When serialized using Newtonsoft.Json, the Password property will be ignored:

var user = new User { Name = "John", Password = "123456" };
string json = JsonConvert.SerializeObject(user);
Console.WriteLine(json); // Output: { "Name": "John" }

System.Text.Json Example:

With System.Text.Json, the approach is identical but requires System.Text.Json.Serialization.

using System.Text.Json;
using System.Text.Json.Serialization;

public class User
{
    public string Name { get; set; }
    
    [JsonIgnore]
    public string Password { get; set; }
}

Key Considerations:

  • [JsonIgnore] is the simplest approach.

  • It works statically, meaning all instances of the class will ignore the marked property.

  • If you need dynamic control, consider custom converters or serialization settings.

2. Excluding Properties Dynamically

Sometimes, you need to exclude properties at runtime based on conditions.

Using JsonSerializerSettings (Newtonsoft.Json)

var settings = new JsonSerializerSettings { ContractResolver = new CustomContractResolver() };
string json = JsonConvert.SerializeObject(user, settings);

Creating a Custom Contract Resolver:

using Newtonsoft.Json.Serialization;

public class CustomContractResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        var properties = base.CreateProperties(type, memberSerialization);
        return properties.Where(p => p.PropertyName != "Password").ToList();
    }
}

This allows filtering properties dynamically without modifying the class.

3. Using [DataContract] and [DataMember] Attributes (WCF & XML Serialization)

For WCF and XML serialization, you can use [DataContract] and [DataMember] attributes to control which properties are serialized.

using System.Runtime.Serialization;

[DataContract]
public class User
{
    [DataMember]
    public string Name { get; set; }
    
    // Not marked with [DataMember], so it will be excluded
    public string Password { get; set; }
}

4. Custom Converters for Advanced Scenarios

System.Text.Json Custom Converter

For more control, you can create a custom converter.

public class UserConverter : JsonConverter<User>
{
    public override User Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }

    public override void Write(Utf8JsonWriter writer, User value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();
        writer.WriteString("Name", value.Name);
        // Exclude Password
        writer.WriteEndObject();
    }
}

Registering the converter:

var options = new JsonSerializerOptions { Converters = { new UserConverter() } };
string json = JsonSerializer.Serialize(user, options);

5. Performance Considerations

  • **Prefer **System.Text.Json for better performance in ASP.NET Core applications.

  • Avoid reflection-based resolvers (e.g., DefaultContractResolver) in high-performance scenarios.

  • Use custom converters for selective exclusion at runtime without affecting serialization globally.

Conclusion

Selective serialization in C# is a powerful technique that helps in optimizing performance, ensuring security, and maintaining clean API responses. Depending on your needs, you can use attributes (JsonIgnore, DataContract) for static exclusion, contract resolvers for dynamic control, or custom converters for fine-grained customization.

By implementing these strategies effectively, you can have complete control over how your C# objects are serialized, improving efficiency and security in your .NET applications.