NonSerialized
property attribute
.NET
serialization
C#

NonSerialized on property

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

NonSerialized is frequently misunderstood in .NET because developers expect it to hide properties from all serializers. In reality, it was designed for field-based serialization scenarios and does not automatically control property serialization in modern JSON pipelines. Reliable behavior comes from choosing serializer-specific attributes and testing contracts explicitly.

What NonSerialized Actually Targets

The attribute applies to fields that participate in compatible serializers, historically including binary formatter style flows. A property is not the same metadata target, even when an auto-property compiles to a backing field.

Correct field usage:

csharp
1[Serializable]
2public class CacheEntry
3{
4    public string Key = string.Empty;
5
6    [NonSerialized]
7    private string _runtimeOnlyToken = string.Empty;
8
9    public string RuntimeOnlyToken
10    {
11        get => _runtimeOnlyToken;
12        set => _runtimeOnlyToken = value;
13    }
14}

Placing NonSerialized directly on RuntimeOnlyToken does not produce the intended effect for most serializers.

Use the Right Ignore Attribute for the Active Serializer

Modern applications often use one of these serializers:

  • System.Text.Json
  • Newtonsoft.Json
  • XML serialization APIs

Each has its own ignore mechanism.

System.Text.Json:

csharp
1using System.Text.Json;
2using System.Text.Json.Serialization;
3
4public class UserDto
5{
6    public string Id { get; set; } = string.Empty;
7
8    [JsonIgnore]
9    public string PasswordHash { get; set; } = string.Empty;
10}
11
12var dto = new UserDto { Id = "u1", PasswordHash = "hidden" };
13Console.WriteLine(JsonSerializer.Serialize(dto));

Newtonsoft.Json:

csharp
1using Newtonsoft.Json;
2
3public class UserDtoLegacy
4{
5    public string Id { get; set; } = string.Empty;
6
7    [JsonIgnore]
8    public string PasswordHash { get; set; } = string.Empty;
9}

XML serializer example:

csharp
1using System.Xml.Serialization;
2
3public class ReportDto
4{
5    public string Title { get; set; } = string.Empty;
6
7    [XmlIgnore]
8    public string InternalNote { get; set; } = string.Empty;
9}

Auto-Properties and Backing Field Control

If you truly need field-level control with NonSerialized, use an explicit field and property wrapper. This makes serialization intent visible to maintainers and avoids compiler-generated field ambiguity.

csharp
1[Serializable]
2public class JobState
3{
4    [NonSerialized]
5    private int _retryBudget;
6
7    public int RetryBudget
8    {
9        get => _retryBudget;
10        set => _retryBudget = value;
11    }
12}

Even then, the behavior depends on serializer selection.

Keep Domain and Transport Models Separate

Trying to hide internal data through many ignore attributes is usually a design smell. A cleaner pattern is separate classes:

  • domain entity with full internal state
  • transport DTO exposing only contract-safe fields
csharp
1public class AccountEntity
2{
3    public string Id { get; set; } = string.Empty;
4    public string SecretKey { get; set; } = string.Empty;
5}
6
7public class AccountResponse
8{
9    public string Id { get; set; } = string.Empty;
10}

Mapping cost is small compared with the risk of sensitive field leakage.

Contract Tests Prevent Regressions

Serialization behavior can change during refactors, package upgrades, or source generator changes. Add tests that assert serialized payload contents.

csharp
1using System.Text.Json;
2
3var dto = new UserDto { Id = "u42", PasswordHash = "hash" };
4var json = JsonSerializer.Serialize(dto);
5
6if (json.Contains("PasswordHash"))
7{
8    throw new Exception("Secret field should not be serialized");
9}

Treat these tests as security and compatibility checks.

Migration Advice for Legacy Code

When modernizing older code:

  1. inventory every serialization boundary
  2. identify serializer type per boundary
  3. replace ambiguous attributes with explicit serializer attributes
  4. add snapshot tests before and after migration

This approach avoids silent payload changes in production APIs. It also makes future framework upgrades safer because serialization intent is documented in code and in tests.

Common Pitfalls

  • Applying NonSerialized to properties and assuming it works everywhere.
  • Mixing serializers in one solution without explicit per-serializer annotations.
  • Relying on auto-property backing field behavior that is not guaranteed by contract intent.
  • Exposing sensitive fields in logs even when serializer output is filtered.
  • Skipping regression tests for serialized payload shape.

Summary

  • NonSerialized is field-focused, not a universal property exclusion tool.
  • Property serialization should be controlled with serializer-specific attributes.
  • Explicit DTO contracts are safer than heavy use of ignore annotations.
  • Back serialization decisions with automated payload tests.
  • Treat serialization configuration as part of application security design.

Course illustration
Course illustration

All Rights Reserved.