diff --git a/docs/workflow/trimming/feature-switches.md b/docs/workflow/trimming/feature-switches.md index 92d04e897a2da1..76714d95f2c2ba 100644 --- a/docs/workflow/trimming/feature-switches.md +++ b/docs/workflow/trimming/feature-switches.md @@ -14,6 +14,7 @@ configurations but their defaults might vary as any SDK can set the defaults dif | VerifyDependencyInjectionOpenGenericServiceTrimmability | Microsoft.Extensions.DependencyInjection.VerifyOpenGenericServiceTrimmability | When set to true, DependencyInjection will verify trimming annotations applied to open generic services are correct. | | _AggressiveAttributeTrimming | System.AggressiveAttributeTrimming | When set to true, aggressively trims attributes to allow for the most size savings possible, even if it could result in runtime behavior changes | | _ComObjectDescriptorSupport | System.ComponentModel.TypeDescriptor.IsComObjectDescriptorSupported | When set to true, supports creating a TypeDescriptor based view of COM objects. | +| _DataSetXmlSerializationSupport | System.Data.DataSet.XmlSerializationIsSupported | When set to false, DataSet implementation of IXmlSerializable will throw instead of using trim-incompatible XML serialization. | | _DefaultValueAttributeSupport | System.ComponentModel.DefaultValueAttribute.IsSupported | When set to true, supports creating a DefaultValueAttribute at runtime. | | _DesignerHostSupport | System.ComponentModel.Design.IDesignerHost.IsSupported | When set to true, supports creating design components at runtime. | | _EnableConsumingManagedCodeFromNativeHosting | System.Runtime.InteropServices.EnableConsumingManagedCodeFromNativeHosting | Getting a managed function from native hosting is disabled when set to false and related functionality can be trimmed. | diff --git a/src/libraries/System.Data.Common/src/Resources/Strings.resx b/src/libraries/System.Data.Common/src/Resources/Strings.resx index 8c3c530ceb37c4..4b5d9b14a661ea 100644 --- a/src/libraries/System.Data.Common/src/Resources/Strings.resx +++ b/src/libraries/System.Data.Common/src/Resources/Strings.resx @@ -527,4 +527,5 @@ The DataRowComparer does not work with DataRows that have been deleted since it only compares current values. The source contains a deleted DataRow that cannot be copied to the DataTable. Cannot cast DBNull. Value to type '{0}'. Please use a nullable type. + DataSet implementation of IXmlSerializable is not trim compatible and has been disabled in the app configuration. diff --git a/src/libraries/System.Data.Common/src/System/Data/DataSet.cs b/src/libraries/System.Data.Common/src/System/Data/DataSet.cs index 37c1fb283d7e19..56fa3c9118f546 100644 --- a/src/libraries/System.Data.Common/src/System/Data/DataSet.cs +++ b/src/libraries/System.Data.Common/src/System/Data/DataSet.cs @@ -77,6 +77,12 @@ public class DataSet : MarshalByValueComponent, IListSource, IXmlSerializable, I internal bool _useDataSetSchemaOnly; // UseDataSetSchemaOnly , for YUKON internal bool _udtIsWrapped; // if UDT is wrapped , for YUKON + [FeatureSwitchDefinition("System.Data.DataSet.XmlSerializationIsSupported")] + [FeatureGuard(typeof(RequiresUnreferencedCodeAttribute))] +#pragma warning disable IL4000 + internal static bool XmlSerializationIsSupported => AppContext.TryGetSwitch("System.Data.DataSet.XmlSerializationIsSupported", out bool isSupported) ? isSupported : true; +#pragma warning restore IL4000 + /// /// Initializes a new instance of the class. /// @@ -3459,6 +3465,11 @@ public static XmlSchemaComplexType GetDataSetSchema(XmlSchemaSet? schemaSet) XmlSchema? IXmlSerializable.GetSchema() { + if (!XmlSerializationIsSupported) + { + throw new NotSupportedException(SR.DataSet_XmlSerializationUnsupported); + } + if (GetType() == typeof(DataSet)) { return null; @@ -3469,9 +3480,7 @@ public static XmlSchemaComplexType GetDataSetSchema(XmlSchemaSet? schemaSet) XmlWriter writer = new XmlTextWriter(stream, null); if (writer != null) { -#pragma warning disable IL2026 // suppressed in ILLink.Suppressions.LibraryBuild.xml WriteXmlSchema(this, writer); -#pragma warning restore IL2026 } stream.Position = 0; return XmlSchema.Read(new XmlTextReader(stream), null); @@ -3485,6 +3494,11 @@ private static void WriteXmlSchema(DataSet ds, XmlWriter writer) void IXmlSerializable.ReadXml(XmlReader reader) { + if (!XmlSerializationIsSupported) + { + throw new NotSupportedException(SR.DataSet_XmlSerializationUnsupported); + } + bool fNormalization = true; XmlTextReader? xmlTextReader = null; IXmlTextParser? xmlTextParser = reader as IXmlTextParser; @@ -3503,9 +3517,7 @@ void IXmlSerializable.ReadXml(XmlReader reader) } } -#pragma warning disable IL2026 // suppressed in ILLink.Suppressions.LibraryBuild.xml ReadXmlSerializableInternal(reader); -#pragma warning restore IL2026 if (xmlTextParser != null) { @@ -3525,9 +3537,12 @@ private void ReadXmlSerializableInternal(XmlReader reader) void IXmlSerializable.WriteXml(XmlWriter writer) { -#pragma warning disable IL2026 // suppressed in ILLink.Suppressions.LibraryBuild.xml + if (!XmlSerializationIsSupported) + { + throw new NotSupportedException(SR.DataSet_XmlSerializationUnsupported); + } + WriteXmlInternal(writer); -#pragma warning restore IL2026 } [RequiresUnreferencedCode("DataSet.WriteXml uses XmlSerialization underneath which is not trimming safe. Members from serialized types may be trimmed if not referenced directly.")] diff --git a/src/libraries/System.Data.Common/src/System/Data/DataTable.cs b/src/libraries/System.Data.Common/src/System/Data/DataTable.cs index dedde6f7efbd62..ab92707b1c2089 100644 --- a/src/libraries/System.Data.Common/src/System/Data/DataTable.cs +++ b/src/libraries/System.Data.Common/src/System/Data/DataTable.cs @@ -6664,9 +6664,15 @@ public static XmlSchemaComplexType GetDataTableSchema(XmlSchemaSet? schemaSet) return type; } -#pragma warning disable IL2026 // suppressed in ILLink.Suppressions.LibraryBuild.xml - XmlSchema? IXmlSerializable.GetSchema() => GetXmlSchema(); -#pragma warning restore IL2026 + XmlSchema? IXmlSerializable.GetSchema() + { + if (!DataSet.XmlSerializationIsSupported) + { + throw new NotSupportedException(SR.DataSet_XmlSerializationUnsupported); + } + + return GetXmlSchema(); + } [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)] [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2046:UnrecognizedReflectionPattern", @@ -6693,6 +6699,11 @@ public static XmlSchemaComplexType GetDataTableSchema(XmlSchemaSet? schemaSet) void IXmlSerializable.ReadXml(XmlReader reader) { + if (!DataSet.XmlSerializationIsSupported) + { + throw new NotSupportedException(SR.DataSet_XmlSerializationUnsupported); + } + IXmlTextParser? textReader = reader as IXmlTextParser; bool fNormalization = true; if (textReader != null) @@ -6700,9 +6711,7 @@ void IXmlSerializable.ReadXml(XmlReader reader) fNormalization = textReader.Normalized; textReader.Normalized = false; } -#pragma warning disable IL2026 // suppressed in ILLink.Suppressions.LibraryBuild.xml ReadXmlSerializableInternal(reader); -#pragma warning restore IL2026 if (textReader != null) { @@ -6718,9 +6727,12 @@ private void ReadXmlSerializableInternal(XmlReader reader) void IXmlSerializable.WriteXml(XmlWriter writer) { -#pragma warning disable IL2026 // suppressed in ILLink.Suppressions.LibraryBuild.xml + if (!DataSet.XmlSerializationIsSupported) + { + throw new NotSupportedException(SR.DataSet_XmlSerializationUnsupported); + } + WriteXmlInternal(writer); -#pragma warning restore IL2026 } [RequiresUnreferencedCode("DataTable.WriteXml uses XmlSerialization underneath which is not trimming safe. Members from serialized types may be trimmed if not referenced directly.")] diff --git a/src/libraries/System.Data.Common/tests/TrimmingTests/DataSetXmlSerialization.cs b/src/libraries/System.Data.Common/tests/TrimmingTests/DataSetXmlSerialization.cs new file mode 100644 index 00000000000000..502133d912ddf6 --- /dev/null +++ b/src/libraries/System.Data.Common/tests/TrimmingTests/DataSetXmlSerialization.cs @@ -0,0 +1,82 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Data; +using System.Xml.Schema; +using System.Xml.Serialization; + +namespace DataSetXmlSerializationTrimmingTests +{ + class Program + { + static int Main(string[] args) + { + IXmlSerializable xmlSerializable = new DataSet(); + + // Calling GetSchema should throw NotSupportedException + try + { + xmlSerializable.GetSchema(); + return -1; + } + catch (NotSupportedException) + { + } + + // Calling ReadXml should throw NotSupportedException + try + { + xmlSerializable.ReadXml(null); + return -2; + } + catch (NotSupportedException) + { + } + + // Calling WriteXml should throw NotSupportedException + try + { + xmlSerializable.WriteXml(null); + return -3; + } + catch (NotSupportedException) + { + } + + xmlSerializable = new DataTable(); + + // Calling GetSchema should throw NotSupportedException + try + { + xmlSerializable.GetSchema(); + return -4; + } + catch (NotSupportedException) + { + } + + // Calling ReadXml should throw NotSupportedException + try + { + xmlSerializable.ReadXml(null); + return -5; + } + catch (NotSupportedException) + { + } + + // Calling WriteXml should throw NotSupportedException + try + { + xmlSerializable.WriteXml(null); + return -6; + } + catch (NotSupportedException) + { + } + + return 100; + } + } +} diff --git a/src/libraries/System.Data.Common/tests/TrimmingTests/System.Data.Common.TrimmingTests.proj b/src/libraries/System.Data.Common/tests/TrimmingTests/System.Data.Common.TrimmingTests.proj index 7254c33fc9c7ba..9d59bb0f97e146 100644 --- a/src/libraries/System.Data.Common/tests/TrimmingTests/System.Data.Common.TrimmingTests.proj +++ b/src/libraries/System.Data.Common/tests/TrimmingTests/System.Data.Common.TrimmingTests.proj @@ -4,6 +4,9 @@ + + System.Data.DataSet.XmlSerializationIsSupported + diff --git a/src/tools/illink/src/ILLink.Tasks/build/Microsoft.NET.ILLink.targets b/src/tools/illink/src/ILLink.Tasks/build/Microsoft.NET.ILLink.targets index ab36c6795a4b0c..3fdf083a3beda8 100644 --- a/src/tools/illink/src/ILLink.Tasks/build/Microsoft.NET.ILLink.targets +++ b/src/tools/illink/src/ILLink.Tasks/build/Microsoft.NET.ILLink.targets @@ -57,6 +57,7 @@ Copyright (c) .NET Foundation. All rights reserved. <_DefaultValueAttributeSupport Condition="'$(_DefaultValueAttributeSupport)' == ''">false true false + <_DataSetXmlSerializationSupport Condition="'$(_DataSetXmlSerializationSupport)' == ''">false