Skip to content

[Breaking change]: Fix ObsoleteAttribute incorrectly causing XML serialization to ignore properties with AppContext switch and SR resources #49054

@StephenMolloy

Description

@StephenMolloy

Description

Starting in .NET 10, the behavior of the System.Xml.Serialization.XmlSerializer has changed with respect to how it handles properties marked with the [Obsolete] attribute. Previously, properties marked with [Obsolete] were treated as if they were also marked with [XmlIgnore], causing them to be excluded from XML serialization. This behavior was unintended and has been corrected.

With this change, properties marked with [Obsolete] will now be serialized by default unless the IsError property of the [Obsolete] attribute is set to true. If IsError is true, the serializer will throw an InvalidOperationException during creation. Additionally, an AppContext switch, Switch.System.Xml.IgnoreObsoleteMembers, has been introduced to allow developers to revert to the previous behavior if necessary.

Version

.NET 10

Previous behavior

In previous versions of .NET, properties marked with the [Obsolete] attribute were excluded from XML serialization, similar to properties marked with [XmlIgnore]. This behavior was unexpected and not aligned with the intended purpose of the [Obsolete] attribute, which is to provide compile-time warnings about deprecated APIs.

Example

public class Example
{
    public string NormalProperty { get; set; } = "normal";
    
    [Obsolete("This property is deprecated")]
    public string ObsoleteProperty { get; set; } = "obsolete";
    
    [XmlIgnore]
    public string IgnoredProperty { get; set; } = "ignored";
}

var obj = new Example();
var serializer = new XmlSerializer(typeof(Example));
using var writer = new StringWriter();
serializer.Serialize(writer, obj);
Console.WriteLine(writer.ToString());

Output before the change:

<Example>
  <NormalProperty>normal</NormalProperty>
</Example>

New behavior

Starting in .NET 11, properties marked with [Obsolete] are no longer excluded from XML serialization by default. Instead:

  1. If the [Obsolete] attribute is applied with IsError = false (default), the property will be serialized normally.
  2. If the [Obsolete] attribute is applied with IsError = true, the XmlSerializer will throw an InvalidOperationException during serializer creation.

An AppContext switch, Switch.System.Xml.IgnoreObsoleteMembers, has been introduced to allow developers to restore the previous behavior where [Obsolete] properties are ignored during serialization. This switch is off by default.

Example

Using the same code as above, the output after the change will be:

Output after the change (default behavior):

<Example>
  <NormalProperty>normal</NormalProperty>
  <ObsoleteProperty>obsolete</ObsoleteProperty>
</Example>

If the AppContext switch Switch.System.Xml.IgnoreObsoleteMembers is enabled, the previous behavior is restored:

AppContext.SetSwitch("Switch.System.Xml.IgnoreObsoleteMembers", true);

var obj = new Example();
var serializer = new XmlSerializer(typeof(Example));
using var writer = new StringWriter();
serializer.Serialize(writer, obj);
Console.WriteLine(writer.ToString());

Output with AppContext switch enabled:

<Example>
  <NormalProperty>normal</NormalProperty>
</Example>

If [Obsolete(IsError = true)] is applied to a property, the following exception will be thrown during serializer creation:

System.InvalidOperationException: Cannot serialize member 'ObsoleteProperty' because it is marked with ObsoleteAttribute and IsError is set to true.

Type of breaking change

  • Behavioral change: Existing binaries might behave differently at runtime.

Reason for change

The previous behavior of treating [Obsolete] as equivalent to [XmlIgnore] was unintended and inconsistent with the purpose of the [Obsolete] attribute. This change ensures that [Obsolete] is used solely for its intended purpose of providing compile-time warnings and does not affect runtime serialization behavior. The introduction of the AppContext switch allows developers to opt into the legacy behavior if necessary.

Recommended action

Developers should review their codebases for any reliance on the previous behavior where [Obsolete] properties were excluded from XML serialization. If this behavior is still desired, enable the AppContext switch Switch.System.Xml.IgnoreObsoleteMembers as follows:

AppContext.SetSwitch("Switch.System.Xml.IgnoreObsoleteMembers", true);

If any properties are marked with [Obsolete(IsError = true)] and are being serialized, update the code to either remove the [Obsolete] attribute or set IsError = false to avoid runtime exceptions.

Note

Properties that are marked as Obsolete have always successfully deserialized when data is present in the Xml. While this change will allow [Obsolete] properties to "round trip" from object to Xml and back to object, the new behavior only affects the serialization half (object to Xml) of the "round trip."

Affected APIs

  • System.Xml.Serialization.XmlSerializer

Additional information


Associated WorkItem - 500367

Metadata

Metadata

Labels

📌 seQUESTeredIdentifies that an issue has been imported into Quest.breaking-changeIndicates a .NET Core breaking change

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions