Description
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