Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Sep 18, 2025

This PR fixes an issue where properties marked with [Obsolete] were incorrectly being ignored during XML serialization, similar to how [XmlIgnore] works.

Problem

The XML serialization infrastructure was treating ObsoleteAttribute the same as XmlIgnoreAttribute, causing properties marked as obsolete to be excluded from serialization. This behavior is unexpected since ObsoleteAttribute is intended only to provide compile-time warnings about deprecated APIs, not to affect runtime serialization behavior.

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));
// Before fix: Only NormalProperty appears in XML
// After fix: Both NormalProperty and ObsoleteProperty appear in XML

Solution

Updated the ObsoleteAttribute handling logic in both XmlAttributes.cs and SoapAttributes.cs to:

  1. If ObsoleteAttribute.IsError = false (default): Serialize normally (don't ignore)
  2. If ObsoleteAttribute.IsError = true: Throw an InvalidOperationException using SR string resources during serializer creation
  3. AppContext Switch: Added Switch.System.Xml.IgnoreObsoleteMembers (off by default) to restore legacy behavior when needed

Key Features

  • Default behavior (switch off): Obsolete properties serialize normally, IsError=true throws localized exception
  • Legacy behavior (switch on): Obsolete properties are ignored like before for backward compatibility
  • Proper error handling: Uses SR string resources for exception messages with proper localization
  • Backward compatibility: Switch allows restoring old behavior when needed

Changes Made

  • XmlAttributes.cs & SoapAttributes.cs: Updated constructors to use AppContext switch and SR for error messages
  • LocalAppContextSwitches.cs: Added IgnoreObsoleteMembers switch property
  • Strings.resx: Added XmlObsoleteIsError string resource for localized error messages
  • Comprehensive tests: Added tests for normal behavior, error cases, and switch functionality

This ensures that:

  • Properties with [Obsolete] are serialized normally by default
  • Properties with [Obsolete("message", true)] throw a localized exception to prevent runtime usage
  • Properties with [XmlIgnore] continue to be ignored as expected
  • ObsoleteAttribute maintains its intended purpose of providing compile-time warnings by default
  • Legacy behavior can be restored via the AppContext switch when needed

Tests

Added comprehensive tests including new test classes and test methods to verify:

  • Obsolete properties with IsError=false are properly serialized
  • Obsolete properties with IsError=true throw exceptions during serializer creation with proper SR messages
  • AppContext switch correctly toggles between new and legacy behavior
  • Ignored properties remain excluded

Fixes #100453.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@StephenMolloy
Copy link
Member

@copilot - Our xml serializers shouldn't be silently ignoring [Obsolete] members. The way this should work is if a member is marked [Obsolete(IsError=true)], then the serializer should throw an exception. If 'IsError' is not set or not true, then the member should still serialize normally.

Copilot AI and others added 2 commits September 18, 2025 22:24
Co-authored-by: StephenMolloy <19562826+StephenMolloy@users.noreply.github.com>
Co-authored-by: StephenMolloy <19562826+StephenMolloy@users.noreply.github.com>
Copilot AI changed the title [WIP] Obsolete attribute impacts XML Serialization Fix ObsoleteAttribute incorrectly causing XML serialization to ignore properties Sep 18, 2025
Copilot finished work on behalf of StephenMolloy September 18, 2025 22:35
Copilot AI requested a review from StephenMolloy September 18, 2025 22:35
Co-authored-by: StephenMolloy <19562826+StephenMolloy@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Sep 18, 2025

@copilot - Our xml serializers shouldn't be silently ignoring [Obsolete] members. The way this should work is if a member is marked [Obsolete(IsError=true)], then the serializer should throw an except...

I've updated the implementation based on your feedback. The XML serializers now handle ObsoleteAttribute as follows:

  • If IsError is false or not set (default): The property serializes normally (not ignored)
  • If IsError is true: The serializer throws an InvalidOperationException during creation

This preserves the intended behavior where ObsoleteAttribute provides compile-time warnings by default, while [Obsolete(IsError=true)] prevents runtime usage. I've also added comprehensive tests to cover both scenarios.

Changes implemented in commit cf89504.

Copilot AI changed the title Fix ObsoleteAttribute incorrectly causing XML serialization to ignore properties Fix ObsoleteAttribute incorrectly causing XML serialization to ignore properties and add error handling for IsError=true Sep 18, 2025
Copilot finished work on behalf of StephenMolloy September 18, 2025 23:04
@StephenMolloy
Copy link
Member

@copilot - the new exceptions being thrown should use SR to get string resources rather than directly including exception message text. Also, please put this new behavior behind an appContext switch - similar to how the XmlSerialzier currently draws on LocalAppContextSwitches.cs. Call the switch "Switch.System.Xml.IgnoreObsoleteMembers". The switch should be off by default, which indicates this new behavior should be enabled.

…ttribute behavior

Co-authored-by: StephenMolloy <19562826+StephenMolloy@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Sep 18, 2025

@copilot - the new exceptions being thrown should use SR to get string resources rather than directly including exception message text. Also, please put this new behavior behind an appContext switch...

I've updated the implementation based on your feedback:

  1. Using SR for string resources: Changed exception messages to use SR.Format(SR.XmlObsoleteIsError, obsoleteAttr.Message) instead of direct string interpolation. Added the XmlObsoleteIsError resource to Strings.resx.

  2. Added AppContext switch: Implemented Switch.System.Xml.IgnoreObsoleteMembers in LocalAppContextSwitches.cs (off by default). When the switch is:

    • Off (default): New behavior - obsolete properties serialize normally, IsError=true throws exception
    • On: Legacy behavior - obsolete properties are ignored like before
  3. Added comprehensive tests: Including a test that verifies the switch behavior works correctly.

The switch being off by default means the new, correct behavior is enabled by default, but users can opt back into the old behavior if needed for compatibility.

Changes implemented in commit 90d0b03.

Copilot AI changed the title Fix ObsoleteAttribute incorrectly causing XML serialization to ignore properties and add error handling for IsError=true Fix ObsoleteAttribute incorrectly causing XML serialization to ignore properties with AppContext switch and SR resources Sep 18, 2025
Copilot finished work on behalf of StephenMolloy September 18, 2025 23:43
@StephenMolloy StephenMolloy marked this pull request as ready for review September 19, 2025 06:01
Copilot AI review requested due to automatic review settings September 19, 2025 06:01
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes an issue where properties marked with [Obsolete] were incorrectly being ignored during XML serialization, similar to how [XmlIgnore] works. The fix ensures that obsolete properties are serialized normally by default, with an option to throw exceptions for IsError=true cases and an AppContext switch for backward compatibility.

Key Changes

  • Modified XML serialization attribute handling to differentiate between ObsoleteAttribute and XmlIgnoreAttribute
  • Added AppContext switch Switch.System.Xml.IgnoreObsoleteMembers to control legacy behavior
  • Added proper error handling with localized messages for ObsoleteAttribute.IsError=true cases

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
SerializationTypes.RuntimeOnly.cs Added test types with obsolete properties for different scenarios
XmlSerializerTests.cs Added comprehensive tests including fixture for AppContext switch management
XmlAttributes.cs Updated constructor to handle ObsoleteAttribute separately from XmlIgnoreAttribute
SoapAttributes.cs Updated constructor to handle ObsoleteAttribute separately from SoapIgnoreAttribute
LocalAppContextSwitches.cs Added IgnoreObsoleteMembers switch property
Strings.resx Added localized error message for obsolete properties with IsError=true

Copy link
Member

@mconnew mconnew left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@mconnew
Copy link
Member

mconnew commented Sep 19, 2025

Don't forget to run this by those owning the breaking changes document to see if this would class as a breaking change as it is a behavior change and this could cause data to be output which wasn't previously. I don't think it meets the bar, but worth checking.

@StephenMolloy
Copy link
Member

/backport to release/10.0

@github-actions
Copy link
Contributor

Started backporting to release/10.0: https://github.com/dotnet/runtime/actions/runs/17871036556

@rhuijben
Copy link
Contributor

I remember this behavior going back to .Net Framework 1.0/2.0 in the early days.
This would be a breaking change for the xml serialization tool I wrote 23 years ago. Not sure if this is still in use though.

@StephenMolloy StephenMolloy added area-Serialization breaking-change Issue or PR that represents a breaking API or functional change over a prerelease. labels Sep 26, 2025
@dotnet-policy-service dotnet-policy-service bot added the needs-breaking-change-doc-created Breaking changes need an issue opened with https://github.com/dotnet/docs/issues/new?template=dotnet label Sep 26, 2025
@dotnet-policy-service
Copy link
Contributor

Added needs-breaking-change-doc-created label because this PR has the breaking-change label.

When you commit this breaking change:

  1. Create and link to this PR and the issue a matching issue in the dotnet/docs repo using the breaking change documentation template, then remove this needs-breaking-change-doc-created label.
  2. Ask a committer to mail the .NET Breaking Change Notification DL.

Tagging @dotnet/compat for awareness of the breaking change.

@StephenMolloy StephenMolloy added this to the 10.0.0 milestone Sep 26, 2025
@mconnew
Copy link
Member

mconnew commented Sep 26, 2025

@rhuijben, the scenario where this was reported was when referencing a .NET type which used the Obsolete attribute (SslProtocols I think) which caused the data to disappear in the output. What used to work subsequently broke when a newer version of the runtime added the Obsolete attribute. I hope you can see that this was the wrong behavior previously. I suspect this behavior originates from the fact that XmlSerializer used to generate a source code implementation and compile it and someone decided they didn't want the compiler warnings.

@jkotas jkotas deleted the copilot/fix-100453 branch September 27, 2025 05:28
@jeffhandley
Copy link
Member

@StephenMolloy Even though there might not be many affected, I do still recommend creating the breaking change doc issue and sending the announcement linking to the doc issue as described in the comment: #119865 (comment).

This should be done ahead of the RC2 release.

@ericstj
Copy link
Member

ericstj commented Oct 3, 2025

📋 Breaking Change Documentation Required

Create a breaking change issue with AI-generated content

Generated by Breaking Change Documentation Tool - 2025-10-03 14:13:00

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-Serialization breaking-change Issue or PR that represents a breaking API or functional change over a prerelease.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Obsolete attribute impacts XML Serialization

6 participants