Skip to content

Obsolete attribute impacts XML Serialization #100453

Open
@alundporchsoftware

Description

@alundporchsoftware

Description

This week my team was burned by an unexpected interaction between the Obsolete attribute and the behavior of XmlSerializer, which nearly caused production data loss had we not noticed. When the Obsolete attribute is applied to a property in a class subject to XML serialization, the property isn't serialized.

In reading around, this appears to be a very old decision originating in .NET Framework 3.5, that is not in alignment with the purpose of the Obsolete attribute (see https://weblogs.asp.net/psteele/xml-serialization-and-the-obsolete-attribute). The current documentation states that "Marking an element as obsolete informs users that the element may be removed in a future version of the product." Not serializing based on the presence of Obsolete seems like a secondary purpose, for what is practically a single purpose attribute. It seems especially egregious when considering the XmlIgnore attribute exists for the dedicated purpose of preventing serialization of a property. The interaction also wasn't documented (see dotnet/docs#40232)

I consider this issue a bug; it's an interaction between disparate parts of the dotnet platform which really shouldn't be interacting the way they do, and is a pretty significant gotcha when a developer encounters it. That said, it's almost certainly a breaking change to adjust this behavior, because someone is no doubt relying on this functionality, but I can't really think of an alternative that would be a practical fix otherwise. I don't trust the compiler or roslyn analyzers to be able to reliably detect when a class might be XML Serialized, so a compiler warning is impractical, and a pragma or other compiler flag to adjust the functionality seems heavy handed (although it might be best solution overall). About the only other thing I can think of is introducing an XMLSerializationOptions class similar to JSON serialization, which doesn't seem in line with the current state of the API.

If someone knows, I would be eager to hear the reasoning for this functionality.

Reproduction Steps

This code reproduces the issue:

using System.Xml.Serialization;

XmlSerializer serializer = new XmlSerializer(typeof(Thing));

var thing = new Thing();

using(var file = File.OpenWrite("bad.xml"))
{
	serializer.Serialize(file, thing);
}

public class Thing
{
	public string FineProp { get; set; } = nameof(FineProp); //Is properly serialized
	[XmlIgnore]
	public string IgnoreProp { get; set; } = nameof(IgnoreProp); //Is properly ignored
	[Obsolete]
	public string ObsoleteProp { get; set; } = nameof(ObsoleteProp); //Isn't serialiZed?
}

The resulting xml generated looks like this:

<?xml version="1.0" encoding="utf-8"?>
<Thing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <FineProp>FineProp</FineProp>
</Thing>

Expected behavior

When marked with the Obsolete attribute, a property of a class should be serialized by an instance of XMLSerializer

Actual behavior

When marked with the Obsolete attribute, public properties are not serialized by XMLSerializer

Regression?

No response

Known Workarounds

No response

Configuration

.NET SDK 6.0.416
Windows 11 x64
Not specific

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions