-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Breaking Change: XmlSerializer now includes [Obsolete] members by default
/cc @dotnet/compat, @mconnew, @mangod9
Summary
XmlSerializer
now includes members marked with [Obsolete]
during XML serialization and deserialization. Previously, such members were silently skipped, which could lead to silent data loss. This change corrects that behavior. The vast majority of affected scenarios will simply start seeing previously omitted data appear in serialized XML (and be populated during deserialization).
Old versions of XmlSerializer
(or the current version with the compat switch enabled) will continue silently drop any 'obsolete' data included in payloads for deserialization.
A secondary change: if a member is marked [Obsolete(..., error: true)]
, the serializer now throws an InvalidOperationException
at serializer creation time instead of silently ignoring the member. This enforces the intent of error-level obsolete usage.
Reason for Change
The old behavior was problematic because it silently omitted [Obsolete]
-decorated members, causing data loss or corruption without any warning or error. This was contrary to the intended purpose of the [Obsolete]
attribute, which is to provide a warning about API usage, not to affect runtime serialization behavior. The prior behavior treated [Obsolete]
like [XmlIgnore]
, suppressing those members without warning. This was:
- Undocumented and surprising
- Contrary to the purpose of
[Obsolete]
(a compile-time guidance mechanism, not a runtime serialization control) - Potentially dangerous due to silent data loss
Since[XmlIgnore]
already exists for intentionally excluding members, overloading[Obsolete]
for that purpose was incorrect.
This change aligns serialization behavior with developer expectations and .NET design principles. It prevents accidental data loss and makes the impact of [Obsolete]
explicit at runtime instead of silent.
Category (Breaking Change Classification)
Bucket 2: Reasonable Grey Area
A change of behavior that some consumers could have (even if unintentionally) depended on. Despite the old behavior being incorrect, it may have been relied upon in production.
Additionally, in some scenarios, the introduction of an exception when error: true
could create unexpected noise when upgrading. Properties that are obsolete with error: true
can be explicitly silenced with [XmlIgnore]
, since that attribute takes precedence over any obsolete checks.
Impact
- Old Behavior:
- Members with
[Obsolete]
were silently excluded from XML output and not populated on deserialization. No warning or exception.
- Members with
- New Behavior:
- Members with
[Obsolete]
(defaulterror: false
) are now serialized and deserialized like any other public serializable members. - Members with
[Obsolete(..., error: true)]
causeXmlSerializer
construction to throw anInvalidOperationException
, making the incompatibility explicit.
- Members with
- Mitigation / Opt-out:
- Set the AppContext switch to restore legacy omission behavior:
- Switch.System.Xml.IgnoreObsoleteMembers = true
- Set the AppContext switch to restore legacy omission behavior:
Risk-Benefit Analysis
- Benefits:
- Eliminates a source of silent data loss.
- Restores clear separation of concerns:
[Obsolete]
for deprecation signaling,[XmlIgnore]
for serialization control. - Surfaces issues early in development or deployment.
- Makes intentional blocking (
error: true
) explicit via an exception.
- Risks:
- Some applications may begin emitting additional XML elements (previously, obsolete members were missing).
- Code that (incorrectly) relied on omission may need adjustment.
- Rare cases with
error: true
now fail early instead of proceeding with partial data.
- Mitigation:
- Provided compat switch (AppContext) to re-enable old behavior temporarily while migrating.
Guidance for Affected Developers
- If you truly intended to exclude a member: replace
[Obsolete]
with[XmlIgnore]
(and optionally keep[Obsolete]
alongside if you still want deprecation warnings). - If you relied on the omission and need time to adjust: enable the AppContext switch temporarily.
- If you see an exception for
[Obsolete(..., error: true)]
: either removeerror: true
, remove the member from the contract, or explicitly ignore it via[XmlIgnore]
. - Review test baselines or golden XML files that may now include additional elements.
AppContext Switch
Name: Switch.System.Xml.IgnoreObsoleteMembers
Default: false (new correct behavior active)
Set to true to revert to legacy ignoring of [Obsolete]
members.