From 1322449c996928d9a117496e1233299036827349 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Tue, 28 Jun 2022 15:09:17 -0700 Subject: [PATCH 01/33] Fix Private.Xml solution broken by https://github.com/dotnet/runtime/pull/70706. --- src/libraries/System.Private.Xml/System.Private.Xml.sln | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/libraries/System.Private.Xml/System.Private.Xml.sln b/src/libraries/System.Private.Xml/System.Private.Xml.sln index 5abe88fab2f2a..b9f572e763739 100644 --- a/src/libraries/System.Private.Xml/System.Private.Xml.sln +++ b/src/libraries/System.Private.Xml/System.Private.Xml.sln @@ -65,8 +65,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Xml.XPath.Tests", "t EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Xml.Xsl.XslCompiledTransformApi.Tests", "tests\Xslt\XslCompiledTransformApi\System.Xml.Xsl.XslCompiledTransformApi.Tests.csproj", "{A2B94467-3E3E-4632-B76A-4820CF43EDA0}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XsltCompiler.Tests", "tests\Xslt\XsltCompiler\XsltCompiler.Tests.csproj", "{4A49FD39-51EF-42F4-AEF9-C60880FC41B3}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Xml.Xsl.XslTransformApi.Tests", "tests\Xslt\XslTransformApi\System.Xml.Xsl.XslTransformApi.Tests.csproj", "{BBB6623D-BDF2-41B6-9165-A22A6C4D4159}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibraryImportGenerator", "..\System.Runtime.InteropServices\gen\LibraryImportGenerator\LibraryImportGenerator.csproj", "{6BC66CAC-5D61-48C2-8343-FF32DC7BC626}" @@ -219,10 +217,6 @@ Global {A2B94467-3E3E-4632-B76A-4820CF43EDA0}.Debug|Any CPU.Build.0 = Debug|Any CPU {A2B94467-3E3E-4632-B76A-4820CF43EDA0}.Release|Any CPU.ActiveCfg = Release|Any CPU {A2B94467-3E3E-4632-B76A-4820CF43EDA0}.Release|Any CPU.Build.0 = Release|Any CPU - {4A49FD39-51EF-42F4-AEF9-C60880FC41B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4A49FD39-51EF-42F4-AEF9-C60880FC41B3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4A49FD39-51EF-42F4-AEF9-C60880FC41B3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4A49FD39-51EF-42F4-AEF9-C60880FC41B3}.Release|Any CPU.Build.0 = Release|Any CPU {BBB6623D-BDF2-41B6-9165-A22A6C4D4159}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BBB6623D-BDF2-41B6-9165-A22A6C4D4159}.Debug|Any CPU.Build.0 = Debug|Any CPU {BBB6623D-BDF2-41B6-9165-A22A6C4D4159}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -276,7 +270,6 @@ Global {8C4495D3-EC0D-49FB-B49F-31F326BE3B7C} = {E96EBB95-6AC7-4ECD-AD77-30F089F2C1F9} {2ACA294D-34E5-476C-B978-DE6FA028318E} = {E96EBB95-6AC7-4ECD-AD77-30F089F2C1F9} {A2B94467-3E3E-4632-B76A-4820CF43EDA0} = {E96EBB95-6AC7-4ECD-AD77-30F089F2C1F9} - {4A49FD39-51EF-42F4-AEF9-C60880FC41B3} = {E96EBB95-6AC7-4ECD-AD77-30F089F2C1F9} {BBB6623D-BDF2-41B6-9165-A22A6C4D4159} = {E96EBB95-6AC7-4ECD-AD77-30F089F2C1F9} {B49AD269-3938-4F33-AEF8-029D3A94138F} = {41E18B29-2DB1-495A-8460-E7A257F8EA07} {6BC66CAC-5D61-48C2-8343-FF32DC7BC626} = {75FE1E48-B986-46E6-874F-336D74FF6C94} From fe3c017aea2f4f59da91985bb52a86d8580c2f3c Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Wed, 29 Jun 2022 09:16:45 -0700 Subject: [PATCH 02/33] Align DCS with 4.8 implementation - minus schema import/export. --- .../src/Resources/Strings.resx | 17 +- ...m.Private.DataContractSerialization.csproj | 99 ++- .../Serialization/ClassDataContract.cs | 469 ++++++--------- .../Runtime/Serialization/CodeGenerator.cs | 224 ++----- .../Serialization/CollectionDataContract.cs | 226 +++---- .../Runtime/Serialization/DataContract.cs | 563 ++++++++++++------ .../Serialization/DataContractSerializer.cs | 22 +- .../Runtime/Serialization/DataContractSet.cs | 93 +-- .../Runtime/Serialization/DataMember.cs | 30 +- .../Runtime/Serialization/EnumDataContract.cs | 46 +- .../Runtime/Serialization/ExportOptions.cs | 14 - .../Serialization/ExtensionDataObject.cs | 2 +- .../Serialization/ExtensionDataReader.cs | 322 +++++++++- .../GenericParameterDataContract.cs | 7 +- .../System/Runtime/Serialization/Globals.cs | 25 +- .../Json/DataContractJsonSerializer.cs | 13 +- .../DataContractJsonSerializerExtensions.cs | 18 + .../Json/JsonFormatReaderGenerator.cs | 10 +- .../Json/JsonFormatWriterGenerator.cs | 17 +- .../Json/ReflectionJsonFormatWriter.cs | 2 +- .../Serialization/PrimitiveDataContract.cs | 18 +- .../Serialization/ReflectionClassWriter.cs | 5 - .../Runtime/Serialization/ReflectionReader.cs | 7 +- .../ReflectionXmlFormatWriter.cs | 2 +- .../Runtime/Serialization/SchemaExporter.cs | 2 - .../Runtime/Serialization/SchemaHelper.cs | 1 - .../Serialization/SerializationMode.cs | 10 - .../Serialization/SpecialTypeDataContract.cs | 2 +- .../System/Runtime/Serialization/TypeCode.cs | 80 --- .../Runtime/Serialization/XmlDataContract.cs | 60 +- .../XmlFormatGeneratorStatics.cs | 58 +- .../Serialization/XmlFormatReaderGenerator.cs | 43 +- .../Serialization/XmlFormatWriterGenerator.cs | 57 +- .../Serialization/XmlObjectSerializer.cs | 2 +- .../XmlObjectSerializerContext.cs | 37 +- .../XmlObjectSerializerReadContext.cs | 51 +- .../XmlObjectSerializerReadContextComplex.cs | 129 +--- .../XmlObjectSerializerWriteContext.cs | 13 +- .../XmlObjectSerializerWriteContextComplex.cs | 7 - .../Serialization/XmlReaderDelegator.cs | 12 +- .../Serialization/XmlSerializableReader.cs | 41 +- .../Serialization/XmlWriterDelegator.cs | 12 +- .../Serialization/XsdDataContractExporter.cs | 5 - .../src/System/Xml/ArrayHelper.cs | 5 + .../src/System/Xml/EncodingStreamWrapper.cs | 8 +- .../src/System/Xml/StringHandle.cs | 21 +- .../src/System/Xml/ValueHandle.cs | 2 + .../src/System/Xml/XmlBaseReader.cs | 128 +++- .../src/System/Xml/XmlBaseWriter.cs | 212 ++++++- .../src/System/Xml/XmlBinaryReader.cs | 25 +- .../src/System/Xml/XmlBinaryWriter.cs | 132 +++- .../src/System/Xml/XmlBufferReader.cs | 53 +- .../src/System/Xml/XmlCanonicalWriter.cs | 3 +- .../src/System/Xml/XmlConverter.cs | 13 +- .../src/System/Xml/XmlDictionaryReader.cs | 26 + .../src/System/Xml/XmlDictionaryWriter.cs | 2 +- .../src/System/Xml/XmlExceptionHelper.cs | 12 + .../src/System/Xml/XmlSigningNodeWriter.cs | 2 +- .../src/System/Xml/XmlStreamNodeWriter.cs | 36 +- .../src/System/Xml/XmlUTF8TextWriter.cs | 21 +- .../tests/DataContractSerializer.cs | 129 ++++ 61 files changed, 2176 insertions(+), 1527 deletions(-) create mode 100644 src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializerExtensions.cs delete mode 100644 src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SerializationMode.cs delete mode 100644 src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/TypeCode.cs diff --git a/src/libraries/System.Private.DataContractSerialization/src/Resources/Strings.resx b/src/libraries/System.Private.DataContractSerialization/src/Resources/Strings.resx index f772c16d39646..985893b4ac42b 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/Resources/Strings.resx +++ b/src/libraries/System.Private.DataContractSerialization/src/Resources/Strings.resx @@ -312,6 +312,12 @@ Member '{0}' in type '{1}' cannot have DataMemberAttribute attribute Name set to null or empty string. + + '{0}' is an invalid data node when deserializing extension data. + + + Type '{0}' in namespace '{1}' is not a valid base type for enum '{2}' in namespace '{3}'. + '{0}' in type '{1}' cannot have EnumMemberAttribute attribute Value set to null or empty string. @@ -624,6 +630,9 @@ Unrecognized Byte Order Mark. + + The maximum nametable character count quota ({0}) has been exceeded while reading XML data. The nametable is a data structure used to store strings encountered during XML processing - long XML documents with non-repeating element names, attribute names and attribute values may trigger this quota. This quota may be increased by changing the MaxNameTableCharCount property on the XmlDictionaryReaderQuotas object used when creating the XML reader. + Base64 encoded data expected. Found {0}. @@ -786,6 +795,9 @@ The maximum array length quota ({0}) has been exceeded while reading XML data. This quota may be increased by changing the MaxArrayLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader. + + The maximum array length quota ({0}) or the maximum items in object graph quota has been exceeded while reading XML data. These quotas may be increased by changing the MaxArrayLength property on XmlDictionaryReaderQuotas or the MaxItemsInObjectGraph setting. + The 'maximum bytes per Read operation' quota ({0}) has been exceeded while reading XML data. Long element start tags (consisting of the element name, attribute names and attribute values) may trigger this quota. This quota may be increased by changing the MaxBytesPerRead property on the XmlDictionaryReaderQuotas object used when creating the XML reader. @@ -1155,10 +1167,13 @@ '{0}' must be greater than 0. + + {0} The class cannot be deserialized. + Collection type '{0}' cannot be deserialized since it Unknown Type for null value - \ No newline at end of file + diff --git a/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj b/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj index f8df7d3599de5..60e229ca44380 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj +++ b/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent) $(NoWarn);1634;1691;649 @@ -15,11 +15,11 @@ - - + + + + @@ -29,44 +29,56 @@ + + + + - + + + + + + + + + + + + + - + + + + - - - - - - - - - - + + + @@ -81,6 +93,7 @@ + @@ -89,6 +102,7 @@ + @@ -96,59 +110,42 @@ + + + + + + + + - + + + + + - - - - - - + + - - - - - - - - + + - - - - - - - - - - - - - - - - - - - diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs index 1200e4ee07097..47c525eed133f 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs @@ -30,8 +30,6 @@ internal sealed class ClassDataContract : DataContract private ClassDataContractCriticalHelper _helper; - private bool _isScriptObject; - internal const DynamicallyAccessedMemberTypes DataContractPreserveMemberTypes = DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | @@ -59,7 +57,6 @@ private void InitClassDataContract() this.ContractNamespaces = _helper.ContractNamespaces; this.MemberNames = _helper.MemberNames; this.MemberNamespaces = _helper.MemberNamespaces; - _isScriptObject = _helper.IsScriptObject; } internal ClassDataContract? BaseContract @@ -95,34 +92,26 @@ public XmlDictionaryString?[]? ChildElementNamespaces } return _childElementNamespaces; } - set - { - _childElementNamespaces = value; - } } internal MethodInfo? OnSerializing { - get - { return _helper.OnSerializing; } + get { return _helper.OnSerializing; } } internal MethodInfo? OnSerialized { - get - { return _helper.OnSerialized; } + get { return _helper.OnSerialized; } } internal MethodInfo? OnDeserializing { - get - { return _helper.OnDeserializing; } + get { return _helper.OnDeserializing; } } internal MethodInfo? OnDeserialized { - get - { return _helper.OnDeserialized; } + get { return _helper.OnDeserialized; } } internal MethodInfo? ExtensionDataSetMethod @@ -130,14 +119,13 @@ internal MethodInfo? ExtensionDataSetMethod get { return _helper.ExtensionDataSetMethod; } } - public override DataContractDictionary? KnownDataContracts + internal override DataContractDictionary? KnownDataContracts { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - get - { return _helper.KnownDataContracts; } + get { return _helper.KnownDataContracts; } } - public override bool IsISerializable + internal override bool IsISerializable { get { return _helper.IsISerializable; } set { _helper.IsISerializable = value; } @@ -145,44 +133,20 @@ public override bool IsISerializable internal bool IsNonAttributedType { - get - { return _helper.IsNonAttributedType; } + get { return _helper.IsNonAttributedType; } } - public bool HasExtensionData + internal bool HasExtensionData { - get - { return _helper.HasExtensionData; } - set { _helper.HasExtensionData = value; } + get { return _helper.HasExtensionData; } } - [MemberNotNullWhen(true, nameof(KeyValuePairGenericArguments))] - [MemberNotNullWhen(true, nameof(KeyValuePairAdapterConstructorInfo))] - [MemberNotNullWhen(true, nameof(GetKeyValuePairMethodInfo))] - internal bool IsKeyValuePairAdapter - { - get -#pragma warning disable CS8775 // Member must have a non-null value when exiting in some condition. - { return _helper.IsKeyValuePairAdapter; } -#pragma warning restore CS8775 // Member must have a non-null value when exiting in some condition. - } - - internal Type[]? KeyValuePairGenericArguments - { - get - { return _helper.KeyValuePairGenericArguments; } - } + internal string? SerialiazationExceptionMessage { get { return _helper.SerializationExceptionMessage; } } + internal string? DeserializationExceptionMessage { get { return _helper.DeserializationExceptionMessage; } } - internal ConstructorInfo? KeyValuePairAdapterConstructorInfo + internal bool IsReadOnlyContract { - get - { return _helper.KeyValuePairAdapterConstructorInfo; } - } - - internal MethodInfo? GetKeyValuePairMethodInfo - { - get - { return _helper.GetKeyValuePairMethodInfo; } + get { return DeserializationExceptionMessage != null; } } internal ConstructorInfo? GetISerializableConstructor() @@ -253,9 +217,6 @@ internal XmlFormatClassWriterDelegate XmlFormatWriterDelegate } return _helper.XmlFormatWriterDelegate; } - set - { - } } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -275,6 +236,10 @@ internal XmlFormatClassReaderDelegate XmlFormatReaderDelegate { if (_helper.XmlFormatReaderDelegate == null) { + if (this.IsReadOnlyContract) + { + ThrowInvalidDataContractException(DeserializationExceptionMessage, null /*type*/); + } XmlFormatClassReaderDelegate tempDelegate = CreateXmlFormatReaderDelegate(); Interlocked.MemoryBarrier(); _helper.XmlFormatReaderDelegate = tempDelegate; @@ -283,25 +248,12 @@ internal XmlFormatClassReaderDelegate XmlFormatReaderDelegate } return _helper.XmlFormatReaderDelegate; } - set - { - } } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal static ClassDataContract CreateClassDataContractForKeyValue(Type type, XmlDictionaryString ns, string[] memberNames) { - ClassDataContract? cdc = (ClassDataContract?)DataContract.GetDataContractFromGeneratedAssembly(type); - if (cdc == null) - { - return new ClassDataContract(type, ns, memberNames); - } - else - { - ClassDataContract cloned = cdc.Clone(); - cloned.UpdateNamespaceAndMembers(type, ns, memberNames); - return cloned; - } + return new ClassDataContract(type, ns, memberNames); } internal static void CheckAndAddMember(List members, DataMember memberContract, Dictionary memberNamesTable) @@ -370,10 +322,9 @@ internal static bool IsNonAttributedTypeValidForSerialization( if (type.IsDefined(Globals.TypeOfCollectionDataContractAttribute, false)) return false; - Type[] interfaceTypes = type.GetInterfaces(); - if (!IsArraySegment(type)) { + Type[] interfaceTypes = type.GetInterfaces(); foreach (Type interfaceType in interfaceTypes) { if (CollectionDataContract.IsCollectionInterface(interfaceType)) @@ -389,60 +340,15 @@ internal static bool IsNonAttributedTypeValidForSerialization( if (type.IsDefined(Globals.TypeOfDataContractAttribute, false)) return false; - if (type.IsValueType) - { - return type.IsVisible; - } - else - { - return (type.IsVisible && - type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, Type.EmptyTypes) != null); - } - } - - private static readonly Dictionary s_knownSerializableTypeInfos = new Dictionary { - { "System.Collections.Generic.KeyValuePair`2", Array.Empty() }, - { "System.Collections.Generic.Queue`1", new[] { "_syncRoot" } }, - { "System.Collections.Generic.Stack`1", new[] {"_syncRoot" } }, - { "System.Collections.ObjectModel.ReadOnlyCollection`1", new[] {"_syncRoot" } }, - { "System.Collections.ObjectModel.ReadOnlyDictionary`2", new[] {"_syncRoot", "_keys", "_values" } }, - { "System.Tuple`1", Array.Empty() }, - { "System.Tuple`2", Array.Empty() }, - { "System.Tuple`3", Array.Empty() }, - { "System.Tuple`4", Array.Empty() }, - { "System.Tuple`5", Array.Empty() }, - { "System.Tuple`6", Array.Empty() }, - { "System.Tuple`7", Array.Empty() }, - { "System.Tuple`8", Array.Empty() }, - { "System.Collections.Queue", new[] {"_syncRoot" } }, - { "System.Collections.Stack", new[] {"_syncRoot" } }, - { "System.Globalization.CultureInfo", Array.Empty() }, - { "System.Version", Array.Empty() }, - }; - - private static string GetGeneralTypeName(Type type) - { - return type.IsGenericType && !type.IsGenericParameter - ? type.GetGenericTypeDefinition().FullName! - : type.FullName!; - } - - internal static bool IsKnownSerializableType(Type type) - { - // Applies to known types that DCS understands how to serialize/deserialize - // - string typeFullName = GetGeneralTypeName(type); - return s_knownSerializableTypeInfos.ContainsKey(typeFullName); - } + if (type == Globals.TypeOfExtensionDataObject) + return false; - internal static bool IsNonSerializedMember(Type type, string memberName) - { - string typeFullName = GetGeneralTypeName(type); + if (type.IsValueType) + return type.IsVisible; - string[]? members; - return s_knownSerializableTypeInfos.TryGetValue(typeFullName, out members) - && members.Contains(memberName); + return (type.IsVisible && + type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, Type.EmptyTypes) != null); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -477,21 +383,12 @@ private void EnsureMethodsImported() public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext? context) { Debug.Assert(context != null); - - if (_isScriptObject) - { - throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.UnexpectedContractType, DataContract.GetClrTypeFullName(this.GetType()), DataContract.GetClrTypeFullName(UnderlyingType)))); - } XmlFormatWriterDelegate(xmlWriter, obj, context, this); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] public override object? ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext? context) { - if (_isScriptObject) - { - throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.UnexpectedContractType, DataContract.GetClrTypeFullName(this.GetType()), DataContract.GetClrTypeFullName(UnderlyingType)))); - } xmlReader.Read(); object? o = XmlFormatReaderDelegate(xmlReader, context, MemberNames, MemberNamespaces); xmlReader.ReadEndElement(); @@ -521,12 +418,21 @@ internal bool RequiresMemberAccessForRead(SecurityException? securityException) if (this.BaseContract != null && this.BaseContract.RequiresMemberAccessForRead(securityException)) return true; - if (ConstructorRequiresMemberAccess(GetNonAttributedTypeConstructor())) + if (ConstructorRequiresMemberAccess(GetISerializableConstructor())) { - if (Globals.TypeOfScriptObject_IsAssignableFrom(UnderlyingType)) + if (securityException != null) { - return true; + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new SecurityException(SR.Format( + SR.PartialTrustIXmlSerialzableNoPublicConstructor, + DataContract.GetClrTypeFullName(UnderlyingType)), + securityException)); } + return true; + } + + if (ConstructorRequiresMemberAccess(GetNonAttributedTypeConstructor())) + { if (securityException != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( @@ -692,8 +598,6 @@ internal bool RequiresMemberAccessForWrite(SecurityException? securityException) private sealed class ClassDataContractCriticalHelper : DataContract.DataContractCriticalHelper { private static Type[]? s_serInfoCtorArgs; - private static readonly MethodInfo s_getKeyValuePairMethod = typeof(KeyValuePairAdapter<,>).GetMethod("GetKeyValuePair", Globals.ScanAllMembers)!; - private static readonly ConstructorInfo s_ctorGenericMethod = typeof(KeyValuePairAdapter<,>).GetConstructor(Globals.ScanAllMembers, new Type[] { typeof(KeyValuePair<,>).MakeGenericType(typeof(KeyValuePairAdapter<,>).GetGenericArguments()) })!; private ClassDataContract? _baseContract; private List? _members; @@ -701,20 +605,21 @@ private sealed class ClassDataContractCriticalHelper : DataContract.DataContract private MethodInfo? _onDeserializing, _onDeserialized; private MethodInfo? _extensionDataSetMethod; private DataContractDictionary? _knownDataContracts; + private string? _serializationExceptionMessage; private bool _isISerializable; private bool _isKnownTypeAttributeChecked; private bool _isMethodChecked; + /// - /// in serialization/deserialization we base the decision whether to Demand SerializationFormatter permission on this value and hasDataContract + /// in serialization/deserialization we base the decision whether to Demand SerializationFormatter permission on this value and isNonAttributedType /// private bool _isNonAttributedType; /// - /// in serialization/deserialization we base the decision whether to Demand SerializationFormatter permission on this value and isNonAttributedType + /// in serialization/deserialization we base the decision whether to Demand SerializationFormatter permission on this value and hasDataContract /// private bool _hasDataContract; private bool _hasExtensionData; - private readonly bool _isScriptObject; private XmlDictionaryString?[]? _childElementNamespaces; private XmlFormatClassReaderDelegate? _xmlFormatReaderDelegate; @@ -750,22 +655,9 @@ internal ClassDataContractCriticalHelper([DynamicallyAccessedMembers(DataContrac if (baseType != null && !(baseType.IsSerializable && Globals.TypeOfISerializable.IsAssignableFrom(baseType))) baseType = null; } - SetKeyValuePairAdapterFlags(type); this.IsValueType = type.IsValueType; if (baseType != null && baseType != Globals.TypeOfObject && baseType != Globals.TypeOfValueType && baseType != Globals.TypeOfUri) { - // https://github.com/dotnet/corefx/pull/19629: - // A DataContract created at runtime does not work with the base DataContract pre-generated by SG. - // It's because the runtime DataContract requires full information of a base DataContract while a - // pre-generated DataContract is incomplete. - // - // At this point in code, we're in the midlle of creating a new DataContract at runtime, so we need to make - // sure that we create our own base type DataContract when the base type could potentially have SG generated - // DataContract. - // - // We wanted to enable the fix for the issue described above only when SG generated DataContracts are available. - // Currently we don't have a good way of detecting usage of SG (either globally or per data contract). - DataContract baseContract = DataContract.GetDataContract(baseType); if (baseContract is CollectionDataContract) { @@ -816,6 +708,10 @@ internal ClassDataContractCriticalHelper([DynamicallyAccessedMembers(DataContrac } else { + if (BaseContract.IsReadOnlyContract) + { + _serializationExceptionMessage = BaseContract.SerialiazationExceptionMessage; + } baseMemberCount = BaseContract.MemberNames!.Length; MemberNames = new XmlDictionaryString[Members.Count + baseMemberCount]; Array.Copy(BaseContract.MemberNames, MemberNames, baseMemberCount); @@ -834,8 +730,6 @@ internal ClassDataContractCriticalHelper([DynamicallyAccessedMembers(DataContrac } EnsureMethodsImported(); - _isScriptObject = this.IsNonAttributedType && - Globals.TypeOfScriptObject_IsAssignableFrom(this.UnderlyingType); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -924,9 +818,7 @@ private void ImportDataMembers() MemberInfo[] memberInfos; - bool isPodSerializable = !_isNonAttributedType || IsKnownSerializableType(type); - - if (!isPodSerializable) + if (_isNonAttributedType) { memberInfos = type.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public); } @@ -960,9 +852,9 @@ private void ImportDataMembers() ThrowInvalidDataContractException(SR.Format(SR.NoGetMethodForProperty, property.DeclaringType, property.Name)); if (setMethod == null) { - if (!SetIfGetOnlyCollection(memberContract)) + if (!SetIfGetOnlyCollection(memberContract, skipIfReadOnlyContract: false)) { - ThrowInvalidDataContractException(SR.Format(SR.NoSetMethodForProperty, property.DeclaringType, property.Name)); + _serializationExceptionMessage = SR.Format(SR.NoSetMethodForProperty, property.DeclaringType, property.Name); } } if (getMethod.GetParameters().Length > 0) @@ -996,7 +888,7 @@ private void ImportDataMembers() CheckAndAddMember(tempMembers, memberContract, memberNamesTable); } } - else if (!isPodSerializable) + else if (_isNonAttributedType) { FieldInfo? field = member as FieldInfo; PropertyInfo? property = member as PropertyInfo; @@ -1021,7 +913,7 @@ private void ImportDataMembers() MethodInfo? setMethod = property.SetMethod; if (setMethod == null) { - if (!SetIfGetOnlyCollection(memberContract)) + if (!SetIfGetOnlyCollection(memberContract, skipIfReadOnlyContract: true)) continue; } else @@ -1029,6 +921,11 @@ private void ImportDataMembers() if (!setMethod.IsPublic || IsMethodOverriding(setMethod)) continue; } + + //skip ExtensionData member of type ExtensionDataObject if IExtensibleDataObject is implemented in non-attributed type + if (_hasExtensionData && memberContract.MemberType == Globals.TypeOfExtensionDataObject + && member.Name == Globals.ExtensionDataObjectPropertyName) + continue; } memberContract.Name = DataContract.EncodeLocalName(member.Name); @@ -1039,23 +936,7 @@ private void ImportDataMembers() { FieldInfo? field = member as FieldInfo; - bool canSerializeMember; - - // Previously System.SerializableAttribute was not available in NetCore, so we had - // a list of known [Serializable] types for type in the framework. Although now SerializableAttribute - // is available in NetCore, some framework types still do not have [Serializable] - // yet, e.g. ReadOnlyDictionary. So, we still need to maintain the known serializable - // type list. - if (IsKnownSerializableType(type)) - { - canSerializeMember = CanSerializeMember(field); - } - else - { - canSerializeMember = field != null && !field.IsNotSerialized; - } - - if (canSerializeMember) + if (field != null && !field.IsNotSerialized) { DataMember memberContract = new DataMember(member); @@ -1087,16 +968,11 @@ private void ImportDataMembers() Debug.Assert(Members != null); } - private static bool CanSerializeMember(FieldInfo? field) - { - return field != null && !ClassDataContract.IsNonSerializedMember(field.DeclaringType!, field.Name); - } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private static bool SetIfGetOnlyCollection(DataMember memberContract) + private static bool SetIfGetOnlyCollection(DataMember memberContract, bool skipIfReadOnlyContract) { //OK to call IsCollection here since the use of surrogated collection types is not supported in get-only scenarios - if (CollectionDataContract.IsCollection(memberContract.MemberType, false /*isConstructorRequired*/) && !memberContract.MemberType.IsValueType) + if (CollectionDataContract.IsCollection(memberContract.MemberType, false /*isConstructorRequired*/, skipIfReadOnlyContract) && !memberContract.MemberType.IsValueType) { memberContract.IsGetOnlyCollection = true; return true; @@ -1339,6 +1215,9 @@ internal override DataContractDictionary? KnownDataContracts [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get { + // NOTE TODO smolloy - Oddly, this shortcut was not here in NetFx. I'm not sure this was added strictly as a perf-optimization though. + // See https://github.com/dotnet/runtime/commit/5d2dba7ffcc4ad6a11a570f5bd8d1964000099ea + // This shouldn't change between invocations though, right? So seems like a good thing to leave in. if (_knownDataContracts != null) { return _knownDataContracts; @@ -1359,8 +1238,17 @@ internal override DataContractDictionary? KnownDataContracts return _knownDataContracts; } - set - { _knownDataContracts = value; } + set { _knownDataContracts = value; } + } + + internal string? SerializationExceptionMessage + { + get { return _serializationExceptionMessage; } + } + + internal string? DeserializationExceptionMessage + { + get { return (_serializationExceptionMessage == null) ? null : SR.Format(SR.ReadOnlyClassDeserialization, _serializationExceptionMessage); } } internal override bool IsISerializable @@ -1377,7 +1265,6 @@ internal bool HasDataContract internal bool HasExtensionData { get { return _hasExtensionData; } - set { _hasExtensionData = value; } } internal bool IsNonAttributedType @@ -1385,50 +1272,6 @@ internal bool IsNonAttributedType get { return _isNonAttributedType; } } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private void SetKeyValuePairAdapterFlags( - [DynamicallyAccessedMembers(DataContractPreserveMemberTypes)] - Type type) - { - if (type.IsGenericType && type.GetGenericTypeDefinition() == Globals.TypeOfKeyValuePairAdapter) - { - _isKeyValuePairAdapter = true; - _keyValuePairGenericArguments = type.GetGenericArguments(); - _keyValuePairCtorInfo = (ConstructorInfo)type.GetMemberWithSameMetadataDefinitionAs(s_ctorGenericMethod); - _getKeyValuePairMethodInfo = (MethodInfo)type.GetMemberWithSameMetadataDefinitionAs(s_getKeyValuePairMethod); - } - } - - private bool _isKeyValuePairAdapter; - private Type[]? _keyValuePairGenericArguments; - private ConstructorInfo? _keyValuePairCtorInfo; - private MethodInfo? _getKeyValuePairMethodInfo; - - internal bool IsKeyValuePairAdapter - { - get { return _isKeyValuePairAdapter; } - } - - internal bool IsScriptObject - { - get { return _isScriptObject; } - } - - internal Type[]? KeyValuePairGenericArguments - { - get { return _keyValuePairGenericArguments; } - } - - internal ConstructorInfo? KeyValuePairAdapterConstructorInfo - { - get { return _keyValuePairCtorInfo; } - } - - internal MethodInfo? GetKeyValuePairMethodInfo - { - get { return _getKeyValuePairMethodInfo; } - } - internal ConstructorInfo? GetISerializableConstructor() { if (!IsISerializable) @@ -1508,44 +1351,118 @@ public int Compare(Member x, Member y) internal static DataMemberConflictComparer Singleton = new DataMemberConflictComparer(); } + } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal ClassDataContractCriticalHelper Clone() + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal override bool Equals(object? other, HashSet checkedContracts) + { + if (IsEqualOrChecked(other, checkedContracts)) + return true; + + if (base.Equals(other, checkedContracts)) + { + if (other is ClassDataContract dataContract) + { + if (IsISerializable) + { + if (!dataContract.IsISerializable) + return false; + } + else + { + if (dataContract.IsISerializable) + return false; + + if (Members == null) + { + if (dataContract.Members != null) + { + // check that all the datamembers in dataContract.Members are optional + if (!IsEveryDataMemberOptional(dataContract.Members)) + return false; + } + } + else if (dataContract.Members == null) + { + // check that all the datamembers in Members are optional + if (!IsEveryDataMemberOptional(Members)) + return false; + } + else + { + Dictionary membersDictionary = new Dictionary(Members.Count); + List dataContractMembersList = new List(); + for (int i = 0; i < Members.Count; i++) + { + membersDictionary.Add(Members[i].Name, Members[i]); + } + + for (int i = 0; i < dataContract.Members.Count; i++) + { + // check that all datamembers common to both datacontracts match + DataMember? dataMember; + if (membersDictionary.TryGetValue(dataContract.Members[i].Name, out dataMember)) + { + if (dataMember.Equals(dataContract.Members[i], checkedContracts)) + { + membersDictionary.Remove(dataMember.Name); + } + else + { + return false; + } + } + // otherwise save the non-matching datamembers for later verification + else + { + dataContractMembersList.Add(dataContract.Members[i]); + } + } + + // check that datamembers left over from either datacontract are optional + if (!IsEveryDataMemberOptional(membersDictionary.Values)) + return false; + if (!IsEveryDataMemberOptional(dataContractMembersList)) + return false; + } + } + + if (BaseContract == null) + return (dataContract.BaseContract == null); + else if (dataContract.BaseContract == null) + return false; + else + return BaseContract.Equals(dataContract.BaseContract, checkedContracts); + } + } + return false; + } + + private static bool IsEveryDataMemberOptional(IEnumerable dataMembers) + { + foreach (DataMember dataMember in dataMembers) { - ClassDataContractCriticalHelper clonedHelper = new ClassDataContractCriticalHelper(this.UnderlyingType); - - clonedHelper._baseContract = this._baseContract; - clonedHelper._childElementNamespaces = this._childElementNamespaces; - clonedHelper.ContractNamespaces = this.ContractNamespaces; - clonedHelper._hasDataContract = this._hasDataContract; - clonedHelper._isMethodChecked = this._isMethodChecked; - clonedHelper._isNonAttributedType = this._isNonAttributedType; - clonedHelper.IsReference = this.IsReference; - clonedHelper.IsValueType = this.IsValueType; - clonedHelper.MemberNames = this.MemberNames; - clonedHelper.MemberNamespaces = this.MemberNamespaces; - clonedHelper._members = this._members; - clonedHelper.Name = this.Name; - clonedHelper.Namespace = this.Namespace; - clonedHelper._onDeserialized = this._onDeserialized; - clonedHelper._onDeserializing = this._onDeserializing; - clonedHelper._onSerialized = this._onSerialized; - clonedHelper._onSerializing = this._onSerializing; - clonedHelper.StableName = this.StableName; - clonedHelper.TopLevelElementName = this.TopLevelElementName; - clonedHelper.TopLevelElementNamespace = this.TopLevelElementNamespace; - clonedHelper._xmlFormatReaderDelegate = this._xmlFormatReaderDelegate; - clonedHelper._xmlFormatWriterDelegate = this._xmlFormatWriterDelegate; - - return clonedHelper; + if (dataMember.IsRequired) + return false; } + return true; + } + + public override int GetHashCode() + { + return base.GetHashCode(); } internal sealed class DataMemberComparer : IComparer { public int Compare(DataMember? x, DataMember? y) { - int orderCompare = x!.Order - y!.Order; + if (x == null && y == null) + return 0; + if (x == null || y == null) + return -1; + + int orderCompare = x.Order - y.Order; if (orderCompare != 0) return orderCompare; @@ -1556,7 +1473,7 @@ public int Compare(DataMember? x, DataMember? y) } /// - /// Get object type for Xml/JsonFormmatReaderGenerator + /// Get object type for Xml/JsonFormatReaderGenerator /// internal Type ObjectType { @@ -1570,37 +1487,5 @@ internal Type ObjectType return type; } } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal ClassDataContract Clone() - { - ClassDataContract clonedDc = new ClassDataContract(this.UnderlyingType); - clonedDc._helper = _helper.Clone(); - clonedDc.ContractNamespaces = this.ContractNamespaces; - clonedDc.ChildElementNamespaces = this.ChildElementNamespaces; - clonedDc.MemberNames = this.MemberNames; - clonedDc.MemberNamespaces = this.MemberNamespaces; - clonedDc.XmlFormatWriterDelegate = this.XmlFormatWriterDelegate; - clonedDc.XmlFormatReaderDelegate = this.XmlFormatReaderDelegate; - return clonedDc; - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal void UpdateNamespaceAndMembers(Type type, XmlDictionaryString ns, string[] memberNames) - { - this.StableName = new XmlQualifiedName(GetStableName(type).Name, ns.Value); - this.Namespace = ns; - XmlDictionary dictionary = new XmlDictionary(1 + memberNames.Length); - this.Name = dictionary.Add(StableName.Name); - this.Namespace = ns; - this.ContractNamespaces = new XmlDictionaryString[] { ns }; - this.MemberNames = new XmlDictionaryString[memberNames.Length]; - this.MemberNamespaces = new XmlDictionaryString[memberNames.Length]; - for (int i = 0; i < memberNames.Length; i++) - { - this.MemberNames[i] = dictionary.Add(memberNames[i]); - this.MemberNamespaces[i] = ns; - } - } } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs index b39d1af3d439f..466acca4b3bf0 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs @@ -88,6 +88,14 @@ private static MethodInfo StringFormat } } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", + Justification = "The trimmer will never remove the Invoke method from delegates.")] + internal static MethodInfo GetInvokeMethod(Type delegateType) + { + Debug.Assert(typeof(Delegate).IsAssignableFrom(delegateType)); + return delegateType.GetMethod("Invoke")!; + } + private Type _delegateType = null!; // initialized in BeginMethod private static Module? s_serializationModule; @@ -100,17 +108,9 @@ private static MethodInfo StringFormat private Stack _blockStack = null!; // initialized in BeginMethod private Label _methodEndLabel; - private readonly Dictionary _localNames = new Dictionary(); - - private enum CodeGenTrace { None, Save, Tron }; - private readonly CodeGenTrace _codeGenTrace; private LocalBuilder? _stringFormatArray; - internal CodeGenerator() - { - //Defaulting to None as thats the default value in WCF - _codeGenTrace = CodeGenTrace.None; - } + internal CodeGenerator() { } internal void BeginMethod(DynamicMethod dynamicMethod, Type delegateType, string methodName, Type[] argTypes, bool allowPrivateMemberAccess) { @@ -123,7 +123,7 @@ internal void BeginMethod(DynamicMethod dynamicMethod, Type delegateType, string internal void BeginMethod(string methodName, Type delegateType, bool allowPrivateMemberAccess) { - MethodInfo signature = JsonFormatWriterGenerator.GetInvokeMethod(delegateType); + MethodInfo signature = GetInvokeMethod(delegateType); ParameterInfo[] parameters = signature.GetParameters(); Type[] paramTypes = new Type[parameters.Length]; for (int i = 0; i < parameters.Length; i++) @@ -148,15 +148,11 @@ private void InitILGeneration(string methodName, Type[] argTypes) _argList = new List(); for (int i = 0; i < argTypes.Length; i++) _argList.Add(new ArgBuilder(i, argTypes[i])); - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceLabel("Begin method " + methodName + " {"); } internal Delegate EndMethod() { MarkLabel(_methodEndLabel); - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceLabel("} End method"); Ret(); Delegate? retVal; @@ -208,13 +204,7 @@ internal LocalBuilder DeclareLocal(Type type, string name) internal LocalBuilder DeclareLocal(Type type, string name, bool isPinned) { - LocalBuilder local = _ilGen.DeclareLocal(type, isPinned); - if (_codeGenTrace != CodeGenTrace.None) - { - _localNames[local] = name; - EmitSourceComment("Declare local '" + name + "' of type " + type); - } - return local; + return _ilGen.DeclareLocal(type, isPinned); } internal void Set(LocalBuilder local, object value) @@ -285,8 +275,7 @@ internal void InternalBreakFor(object userForState, OpCode branchInstruction) forState.EndLabel = DefineLabel(); forState.RequiresEndLabel = true; } - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction(branchInstruction + " " + forState.EndLabel.GetHashCode()); + _ilGen.Emit(branchInstruction, forState.EndLabel); break; } @@ -329,7 +318,7 @@ internal void EndForEach(MethodInfo moveNextMethod) internal void IfNotDefaultValue(object value) { Type type = GetVariableType(value); - TypeCode typeCode = type.GetTypeCode(); + TypeCode typeCode = Type.GetTypeCode(type); if ((typeCode == TypeCode.Object && type.IsValueType) || typeCode == TypeCode.DateTime || typeCode == TypeCode.Decimal) { @@ -507,51 +496,36 @@ internal void Call(MethodInfo methodInfo) { if (methodInfo.IsVirtual && !methodInfo.DeclaringType!.IsValueType) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Callvirt " + methodInfo.ToString() + " on type " + methodInfo.DeclaringType.ToString()); _ilGen.Emit(OpCodes.Callvirt, methodInfo); } else if (methodInfo.IsStatic) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Static Call " + methodInfo.ToString() + " on type " + methodInfo.DeclaringType!.ToString()); _ilGen.Emit(OpCodes.Call, methodInfo); } else { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Call " + methodInfo.ToString() + " on type " + methodInfo.DeclaringType!.ToString()); _ilGen.Emit(OpCodes.Call, methodInfo); } } internal void Call(ConstructorInfo ctor) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Call " + ctor.ToString() + " on type " + ctor.DeclaringType!.ToString()); _ilGen.Emit(OpCodes.Call, ctor); } internal void New(ConstructorInfo constructorInfo) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Newobj " + constructorInfo.ToString() + " on type " + constructorInfo.DeclaringType!.ToString()); _ilGen.Emit(OpCodes.Newobj, constructorInfo); } - internal void InitObj(Type valueType) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Initobj " + valueType); _ilGen.Emit(OpCodes.Initobj, valueType); } internal void NewArray(Type elementType, object len) { Load(len); - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Newarr " + elementType); _ilGen.Emit(OpCodes.Newarr, elementType); } @@ -605,27 +579,20 @@ internal Type LoadMember(MemberInfo memberInfo) memberType = fieldInfo.FieldType; if (fieldInfo.IsStatic) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Ldsfld " + fieldInfo + " on type " + fieldInfo.DeclaringType); _ilGen.Emit(OpCodes.Ldsfld, fieldInfo); } else { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Ldfld " + fieldInfo + " on type " + fieldInfo.DeclaringType); _ilGen.Emit(OpCodes.Ldfld, fieldInfo); } } else if (memberInfo is PropertyInfo property) { memberType = property.PropertyType; - if (property != null) - { - MethodInfo? getMethod = property.GetMethod; - if (getMethod == null) - throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.NoGetMethodForProperty, property.DeclaringType, property))); - Call(getMethod); - } + MethodInfo? getMethod = property.GetMethod; + if (getMethod == null) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.NoGetMethodForProperty, property.DeclaringType, property))); + Call(getMethod); } else if (memberInfo is MethodInfo method) { @@ -645,30 +612,22 @@ internal void StoreMember(MemberInfo memberInfo) { if (fieldInfo.IsStatic) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Stsfld " + fieldInfo + " on type " + fieldInfo.DeclaringType); _ilGen.Emit(OpCodes.Stsfld, fieldInfo); } else { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Stfld " + fieldInfo + " on type " + fieldInfo.DeclaringType); _ilGen.Emit(OpCodes.Stfld, fieldInfo); } } - else if (memberInfo is PropertyInfo) + else if (memberInfo is PropertyInfo property) { - PropertyInfo? property = memberInfo as PropertyInfo; - if (property != null) - { - MethodInfo? setMethod = property.SetMethod; - if (setMethod == null) - throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.NoSetMethodForProperty, property.DeclaringType, property))); - Call(setMethod); - } + MethodInfo? setMethod = property.SetMethod; + if (setMethod == null) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.NoSetMethodForProperty, property.DeclaringType, property))); + Call(setMethod); } - else if (memberInfo is MethodInfo) - Call((MethodInfo)memberInfo); + else if (memberInfo is MethodInfo method) + Call(method); else throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.CannotLoadMemberType, "Unknown"))); } @@ -677,7 +636,7 @@ internal void LoadDefaultValue(Type type) { if (type.IsValueType) { - switch (type.GetTypeCode()) + switch (Type.GetTypeCode(type)) { case TypeCode.Boolean: Ldc(false); @@ -719,8 +678,6 @@ internal void Load(object? obj) { if (obj == null) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Ldnull"); _ilGen.Emit(OpCodes.Ldnull); } else if (obj is ArgBuilder) @@ -776,22 +733,16 @@ internal void ConvertValue(Type source, Type target) internal void Castclass(Type target) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Castclass " + target); _ilGen.Emit(OpCodes.Castclass, target); } internal void Box(Type type) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Box " + type); _ilGen.Emit(OpCodes.Box, type); } internal void Unbox(Type type) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Unbox " + type); _ilGen.Emit(OpCodes.Unbox, type); } @@ -816,47 +767,35 @@ private static OpCode GetLdindOpCode(TypeCode typeCode) => internal void Ldobj(Type type) { - OpCode opCode = GetLdindOpCode(type.GetTypeCode()); + OpCode opCode = GetLdindOpCode(Type.GetTypeCode(type)); if (!opCode.Equals(OpCodes.Nop)) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction(opCode.ToString()!); _ilGen.Emit(opCode); } else { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Ldobj " + type); _ilGen.Emit(OpCodes.Ldobj, type); } } internal void Stobj(Type type) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Stobj " + type); _ilGen.Emit(OpCodes.Stobj, type); } internal void Ceq() { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Ceq"); _ilGen.Emit(OpCodes.Ceq); } internal void Throw() { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Throw"); _ilGen.Emit(OpCodes.Throw); } internal void Ldtoken(Type t) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Ldtoken " + t); _ilGen.Emit(OpCodes.Ldtoken, t); } @@ -870,13 +809,11 @@ internal void Ldc(object o) } else if (valueType.IsEnum) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceComment("Ldc " + o.GetType() + "." + o); Ldc(Convert.ChangeType(o, Enum.GetUnderlyingType(valueType), null)); } else { - switch (valueType.GetTypeCode()) + switch (Type.GetTypeCode(valueType)) { case TypeCode.Boolean: Ldc((bool)o); @@ -915,6 +852,7 @@ internal void Ldc(object o) case TypeCode.Decimal: case TypeCode.DateTime: case TypeCode.Empty: + case TypeCode.DBNull: default: throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.UnknownConstantType, DataContract.GetClrTypeFullName(valueType)))); } @@ -925,50 +863,36 @@ internal void Ldc(bool boolVar) { if (boolVar) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Ldc.i4 1"); _ilGen.Emit(OpCodes.Ldc_I4_1); } else { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Ldc.i4 0"); _ilGen.Emit(OpCodes.Ldc_I4_0); } } internal void Ldc(int intVar) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Ldc.i4 " + intVar); _ilGen.Emit(OpCodes.Ldc_I4, intVar); } internal void Ldc(long l) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Ldc.i8 " + l); _ilGen.Emit(OpCodes.Ldc_I8, l); } internal void Ldc(float f) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Ldc.r4 " + f); _ilGen.Emit(OpCodes.Ldc_R4, f); } internal void Ldc(double d) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Ldc.r8 " + d); _ilGen.Emit(OpCodes.Ldc_R8, d); } internal void Ldstr(string strVar) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Ldstr " + strVar); _ilGen.Emit(OpCodes.Ldstr, strVar); } @@ -982,25 +906,18 @@ internal void LdlocAddress(LocalBuilder localBuilder) internal void Ldloc(LocalBuilder localBuilder) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Ldloc " + _localNames[localBuilder]); _ilGen.Emit(OpCodes.Ldloc, localBuilder); EmitStackTop(localBuilder.LocalType); } internal void Stloc(LocalBuilder local) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Stloc " + _localNames[local]); EmitStackTop(local.LocalType); _ilGen.Emit(OpCodes.Stloc, local); } - internal void Ldloca(LocalBuilder localBuilder) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Ldloca " + _localNames[localBuilder]); _ilGen.Emit(OpCodes.Ldloca, localBuilder); EmitStackTop(localBuilder.LocalType); } @@ -1025,17 +942,11 @@ internal void Starg(ArgBuilder arg) internal void Ldarg(int slot) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Ldarg " + slot); - _ilGen.Emit(OpCodes.Ldarg, slot); } internal void Starg(int slot) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Starg " + slot); - _ilGen.Emit(OpCodes.Starg, slot); } @@ -1046,26 +957,19 @@ internal void Ldarga(ArgBuilder argBuilder) internal void Ldarga(int slot) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Ldarga " + slot); - _ilGen.Emit(OpCodes.Ldarga, slot); } internal void Ldlen() { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Ldlen"); _ilGen.Emit(OpCodes.Ldlen); - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Conv.i4"); _ilGen.Emit(OpCodes.Conv_I4); } private static OpCode GetLdelemOpCode(TypeCode typeCode) => typeCode switch { - TypeCode.Object => OpCodes.Ldelem_Ref, // TypeCode.Object: + TypeCode.Object or TypeCode.DBNull => OpCodes.Ldelem_Ref, // TypeCode.Object: TypeCode.Boolean => OpCodes.Ldelem_I1, // TypeCode.Boolean: TypeCode.Char => OpCodes.Ldelem_I2, // TypeCode.Char: TypeCode.SByte => OpCodes.Ldelem_I1, // TypeCode.SByte: @@ -1090,11 +994,9 @@ internal void Ldelem(Type arrayElementType) } else { - OpCode opCode = GetLdelemOpCode(arrayElementType.GetTypeCode()); + OpCode opCode = GetLdelemOpCode(Type.GetTypeCode(arrayElementType)); if (opCode.Equals(OpCodes.Nop)) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ArrayTypeIsNotSupported_GeneratingCode, DataContract.GetClrTypeFullName(arrayElementType)))); - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction(opCode.ToString()!); _ilGen.Emit(opCode); EmitStackTop(arrayElementType); } @@ -1102,8 +1004,6 @@ internal void Ldelem(Type arrayElementType) internal void Ldelema(Type arrayElementType) { OpCode opCode = OpCodes.Ldelema; - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction(opCode.ToString()!); _ilGen.Emit(opCode, arrayElementType); EmitStackTop(arrayElementType); @@ -1112,7 +1012,7 @@ internal void Ldelema(Type arrayElementType) private static OpCode GetStelemOpCode(TypeCode typeCode) => typeCode switch { - TypeCode.Object => OpCodes.Stelem_Ref, // TypeCode.Object: + TypeCode.Object or TypeCode.DBNull => OpCodes.Stelem_Ref, // TypeCode.Object: TypeCode.Boolean => OpCodes.Stelem_I1, // TypeCode.Boolean: TypeCode.Char => OpCodes.Stelem_I2, // TypeCode.Char: TypeCode.SByte => OpCodes.Stelem_I1, // TypeCode.SByte: @@ -1135,11 +1035,10 @@ internal void Stelem(Type arrayElementType) Stelem(Enum.GetUnderlyingType(arrayElementType)); else { - OpCode opCode = GetStelemOpCode(arrayElementType.GetTypeCode()); + OpCode opCode = GetStelemOpCode(Type.GetTypeCode(arrayElementType)); if (opCode.Equals(OpCodes.Nop)) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ArrayTypeIsNotSupported_GeneratingCode, DataContract.GetClrTypeFullName(arrayElementType)))); - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction(opCode.ToString()!); + EmitStackTop(arrayElementType); _ilGen.Emit(opCode); } @@ -1153,92 +1052,64 @@ internal Label DefineLabel() internal void MarkLabel(Label label) { _ilGen.MarkLabel(label); - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceLabel(label.GetHashCode() + ":"); } internal void Add() { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Add"); _ilGen.Emit(OpCodes.Add); } internal void Subtract() { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Sub"); _ilGen.Emit(OpCodes.Sub); } internal void And() { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("And"); _ilGen.Emit(OpCodes.And); } internal void Or() { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Or"); _ilGen.Emit(OpCodes.Or); } internal void Not() { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Not"); _ilGen.Emit(OpCodes.Not); } internal void Ret() { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Ret"); _ilGen.Emit(OpCodes.Ret); } internal void Br(Label label) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Br " + label.GetHashCode()); _ilGen.Emit(OpCodes.Br, label); } internal void Blt(Label label) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Blt " + label.GetHashCode()); _ilGen.Emit(OpCodes.Blt, label); } internal void Brfalse(Label label) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Brfalse " + label.GetHashCode()); _ilGen.Emit(OpCodes.Brfalse, label); } internal void Brtrue(Label label) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Brtrue " + label.GetHashCode()); _ilGen.Emit(OpCodes.Brtrue, label); } - - internal void Pop() { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Pop"); _ilGen.Emit(OpCodes.Pop); } internal void Dup() { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("Dup"); _ilGen.Emit(OpCodes.Dup); } @@ -1296,13 +1167,11 @@ private void InternalConvert(Type source, Type target, bool isAddress) { if (source.IsValueType) { - OpCode opCode = GetConvOpCode(target.GetTypeCode()); + OpCode opCode = GetConvOpCode(Type.GetTypeCode(target)); if (opCode.Equals(OpCodes.Nop)) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.NoConversionPossibleTo, DataContract.GetClrTypeFullName(target)))); else { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction(opCode.ToString()!); _ilGen.Emit(opCode); } } @@ -1351,24 +1220,9 @@ private static void ThrowMismatchException(object expected) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ExpectingEnd, expected.ToString()))); } - - internal static void EmitSourceInstruction(string line) - { - } - - internal static void EmitSourceLabel(string line) + internal static void EmitStackTop(Type stackTopType) { - } - - internal static void EmitSourceComment(string comment) - { - } - - - internal void EmitStackTop(Type stackTopType) - { - if (_codeGenTrace != CodeGenTrace.Tron) - return; + return; } internal Label[] Switch(int labelCount) @@ -1385,8 +1239,6 @@ internal Label[] Switch(int labelCount) } internal void Case(Label caseLabel1, string caseLabelName) { - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("case " + caseLabelName + "{"); MarkLabel(caseLabel1); } @@ -1397,8 +1249,6 @@ internal void EndCase() if (switchState == null) ThrowMismatchException(stackTop); Br(switchState.EndOfSwitchLabel); - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("} //end case "); } internal void EndSwitch() @@ -1407,8 +1257,6 @@ internal void EndSwitch() SwitchState? switchState = stackTop as SwitchState; if (switchState == null) ThrowMismatchException(stackTop); - if (_codeGenTrace != CodeGenTrace.None) - EmitSourceInstruction("} //end switch"); if (!switchState.DefaultDefined) MarkLabel(switchState.DefaultLabel); MarkLabel(switchState.EndOfSwitchLabel); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs index f56630822de1c..791d592fdb20c 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs @@ -16,54 +16,6 @@ namespace System.Runtime.Serialization { - // The interface is a perf optimization. - // Only KeyValuePairAdapter should implement the interface. - internal interface IKeyValuePairAdapter { } - - //Special Adapter class to serialize KeyValuePair as Dictionary needs it when polymorphism is involved - [DataContract(Namespace = "http://schemas.datacontract.org/2004/07/System.Collections.Generic")] - internal sealed class KeyValuePairAdapter : IKeyValuePairAdapter - { - private K _kvpKey; - private T _kvpValue; - - public KeyValuePairAdapter(KeyValuePair kvPair) - { - _kvpKey = kvPair.Key; - _kvpValue = kvPair.Value; - } - - [DataMember(Name = "key")] - public K Key - { - get { return _kvpKey; } - set { _kvpKey = value; } - } - - [DataMember(Name = "value")] - public T Value - { - get - { - return _kvpValue; - } - set - { - _kvpValue = value; - } - } - - internal KeyValuePair GetKeyValuePair() - { - return new KeyValuePair(_kvpKey, _kvpValue); - } - - internal static KeyValuePairAdapter GetKeyValuePairAdapter(KeyValuePair kvPair) - { - return new KeyValuePairAdapter(kvPair); - } - } - internal interface IKeyValue { object? Key { get; set; } @@ -140,8 +92,14 @@ internal CollectionDataContract(Type type) : base(new CollectionDataContractCrit } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private CollectionDataContract(Type type, CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, string? deserializationExceptionMessage) - : base(new CollectionDataContractCriticalHelper(type, kind, itemType, getEnumeratorMethod, deserializationExceptionMessage)) + internal CollectionDataContract(Type type, DataContract itemContract) : base(new CollectionDataContractCriticalHelper(type, itemContract)) + { + InitCollectionDataContract(this); + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private CollectionDataContract(Type type, CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, string? serializationExceptionMessage, string? deserializationExceptionMessage) + : base(new CollectionDataContractCriticalHelper(type, kind, itemType, getEnumeratorMethod, serializationExceptionMessage, deserializationExceptionMessage)) { InitCollectionDataContract(GetSharedTypeContract(type)); } @@ -192,11 +150,10 @@ internal CollectionKind Kind { return _helper.Kind; } } - public Type ItemType + internal Type ItemType { get { return _helper.ItemType; } - set { _helper.ItemType = value; } } public DataContract ItemContract @@ -220,7 +177,7 @@ internal DataContract? SharedTypeContract { return _helper.SharedTypeContract; } } - public string ItemName + internal string ItemName { get { return _helper.ItemName; } @@ -232,10 +189,9 @@ public string ItemName public XmlDictionaryString CollectionItemName { get { return _collectionItemName; } - set { _collectionItemName = value; } } - public string? KeyName + internal string? KeyName { get { return _helper.KeyName; } @@ -244,7 +200,7 @@ public string? KeyName { _helper.KeyName = value; } } - public string? ValueName + internal string? ValueName { get { return _helper.ValueName; } @@ -316,7 +272,7 @@ internal ConstructorInfo? Constructor { return _helper.Constructor; } } - public override DataContractDictionary? KnownDataContracts + internal override DataContractDictionary? KnownDataContracts { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get @@ -332,6 +288,11 @@ internal string? InvalidCollectionInSharedContractMessage { return _helper.InvalidCollectionInSharedContractMessage; } } + internal string? SerializationExceptionMessage + { + get { return _helper.SerializationExceptionMessage; } + } + internal string? DeserializationExceptionMessage { get { return _helper.DeserializationExceptionMessage; } @@ -342,6 +303,11 @@ internal bool IsReadOnlyContract get { return DeserializationExceptionMessage != null; } } + private bool ItemNameSetExplicit + { + get { return _helper.ItemNameSetExplicit; } + } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private XmlFormatCollectionWriterDelegate CreateXmlFormatWriterDelegate() { @@ -367,9 +333,6 @@ internal XmlFormatCollectionWriterDelegate XmlFormatWriterDelegate } return _helper.XmlFormatWriterDelegate; } - set - { - } } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -402,9 +365,6 @@ internal XmlFormatCollectionReaderDelegate XmlFormatReaderDelegate } return _helper.XmlFormatReaderDelegate; } - set - { - } } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -479,6 +439,7 @@ private sealed class CollectionDataContractCriticalHelper : DataContract.DataCon private readonly MethodInfo? _getEnumeratorMethod; private readonly MethodInfo? _addMethod; private readonly ConstructorInfo? _constructor; + private readonly string? _serializationExceptionMessage; private readonly string? _deserializationExceptionMessage; private DataContract? _itemContract; private DataContract? _sharedTypeContract; @@ -574,7 +535,6 @@ private void Init(CollectionKind kind, Type? itemType, CollectionDataContractAtt } } - // array [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal CollectionDataContractCriticalHelper( [DynamicallyAccessedMembers(ClassDataContract.DataContractPreserveMemberTypes)] @@ -588,12 +548,26 @@ internal CollectionDataContractCriticalHelper( Init(CollectionKind.Array, type.GetElementType(), null); } + // array + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal CollectionDataContractCriticalHelper( + [DynamicallyAccessedMembers(ClassDataContract.DataContractPreserveMemberTypes)] + Type type, + DataContract itemContract) : base(type) + { + if (type.GetArrayRank() > 1) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.SupportForMultidimensionalArraysNotPresent)); + this.StableName = CreateQualifiedName(Globals.ArrayPrefix + itemContract.StableName.Name, itemContract.StableName.Namespace); + _itemContract = itemContract; + Init(CollectionKind.Array, type.GetElementType(), null); + } + // read-only collection [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal CollectionDataContractCriticalHelper( [DynamicallyAccessedMembers(ClassDataContract.DataContractPreserveMemberTypes)] Type type, - CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, string? deserializationExceptionMessage) + CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, string? serializationExceptionMessage, string? deserializationExceptionMessage) : base(type) { if (getEnumeratorMethod == null) @@ -606,6 +580,7 @@ internal CollectionDataContractCriticalHelper( Init(kind, itemType, collectionContractAttribute); _getEnumeratorMethod = getEnumeratorMethod; + _serializationExceptionMessage = serializationExceptionMessage; _deserializationExceptionMessage = deserializationExceptionMessage; } @@ -614,20 +589,12 @@ internal CollectionDataContractCriticalHelper( internal CollectionDataContractCriticalHelper( [DynamicallyAccessedMembers(ClassDataContract.DataContractPreserveMemberTypes)] Type type, - CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, MethodInfo? addMethod, ConstructorInfo? constructor) : base(type) + CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, MethodInfo? addMethod, ConstructorInfo? constructor) + : this(type, kind, itemType, getEnumeratorMethod, (string?)null, (string?)null) { - if (getEnumeratorMethod == null) - throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.CollectionMustHaveGetEnumeratorMethod, DataContract.GetClrTypeFullName(type)))); if (addMethod == null && !type.IsInterface) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.CollectionMustHaveAddMethod, DataContract.GetClrTypeFullName(type)))); - if (itemType == null) - throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.CollectionMustHaveItemType, DataContract.GetClrTypeFullName(type)))); - - CollectionDataContractAttribute? collectionContractAttribute; - this.StableName = DataContract.GetCollectionStableName(type, itemType, out collectionContractAttribute); - Init(kind, itemType, collectionContractAttribute); - _getEnumeratorMethod = getEnumeratorMethod; _addMethod = addMethod; _constructor = constructor; } @@ -658,7 +625,6 @@ internal CollectionKind Kind internal Type ItemType { get { return _itemType; } - set { _itemType = value; } } internal DataContract ItemContract @@ -684,9 +650,7 @@ internal DataContract ItemContract } else { - _itemContract = - DataContract.GetDataContractFromGeneratedAssembly(ItemType) ?? - DataContract.GetDataContract(ItemType); + _itemContract = DataContract.GetDataContract(ItemType); } } return _itemContract; @@ -734,6 +698,8 @@ internal string? ValueName internal bool IsDictionary => KeyName != null; + public string? SerializationExceptionMessage => _serializationExceptionMessage; + public string? DeserializationExceptionMessage => _deserializationExceptionMessage; public XmlDictionaryString? ChildElementNamespace @@ -971,7 +937,7 @@ private static CreateGenericDictionaryEnumeratorDelegate BuildCreateGenericDicti { return this; } - if (type.IsDefined(Globals.TypeOfDataContractAttribute, false)) + if (type.IsSerializable || type.IsDefined(Globals.TypeOfDataContractAttribute, false)) { return new ClassDataContract(type); } @@ -998,20 +964,20 @@ internal static bool IsCollection(Type type, [NotNullWhen(true)] out Type? itemT } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static bool IsCollection(Type type, bool constructorRequired) + internal static bool IsCollection(Type type, bool constructorRequired, bool skipIfReadOnlyContract) { - return IsCollectionHelper(type, out _, constructorRequired); + return IsCollectionHelper(type, out _, constructorRequired, skipIfReadOnlyContract); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private static bool IsCollectionHelper(Type type, [NotNullWhen(true)] out Type? itemType, bool constructorRequired) + private static bool IsCollectionHelper(Type type, [NotNullWhen(true)] out Type? itemType, bool constructorRequired, bool skipIfReadOnlyContract = false) { if (type.IsArray && DataContract.GetBuiltInDataContract(type) == null) { itemType = type.GetElementType()!; return true; } - return IsCollectionOrTryCreate(type, tryCreate: false, out _, out itemType, constructorRequired); + return IsCollectionOrTryCreate(type, tryCreate: false, out _, out itemType, constructorRequired, skipIfReadOnlyContract); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -1021,7 +987,7 @@ internal static bool TryCreate(Type type, [NotNullWhen(true)] out DataContract? } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static bool CreateGetOnlyCollectionDataContract(Type type, [NotNullWhen(true)] out DataContract? dataContract) + internal static bool TryCreateGetOnlyCollectionDataContract(Type type, [NotNullWhen(true)] out DataContract? dataContract) { if (type.IsArray) { @@ -1034,36 +1000,6 @@ internal static bool CreateGetOnlyCollectionDataContract(Type type, [NotNullWhen } } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static bool TryCreateGetOnlyCollectionDataContract(Type type, [NotNullWhen(true)] out DataContract? dataContract) - { - dataContract = DataContract.GetDataContractFromGeneratedAssembly(type); - if (dataContract == null) - { - if (type.IsArray) - { - dataContract = new CollectionDataContract(type); - return true; - } - else - { - return IsCollectionOrTryCreate(type, tryCreate: true, out dataContract!, out _, constructorRequired: false); - } - } - else - { - if (dataContract is CollectionDataContract) - { - return true; - } - else - { - dataContract = null; - return false; - } - } - } - // Once https://github.com/mono/linker/issues/1731 is fixed we can remove the suppression from here as it won't be needed any longer. [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:GetMethod", Justification = "The DynamicallyAccessedMembers declarations will ensure the interface methods will be preserved.")] @@ -1083,7 +1019,7 @@ private static bool IsArraySegment(Type t) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private static bool IsCollectionOrTryCreate(Type type, bool tryCreate, out DataContract? dataContract, out Type itemType, bool constructorRequired) + private static bool IsCollectionOrTryCreate(Type type, bool tryCreate, out DataContract? dataContract, out Type itemType, bool constructorRequired, bool skipIfReadOnlyContract = false) { dataContract = null; itemType = Globals.TypeOfObject; @@ -1097,6 +1033,7 @@ private static bool IsCollectionOrTryCreate(Type type, bool tryCreate, out DataC MethodInfo? addMethod, getEnumeratorMethod; bool hasCollectionDataContract = IsCollectionDataContract(type); bool isReadOnlyContract = false; + string? serializationExceptionMessage = null; string? deserializationExceptionMessage = null; Type? baseType = type.BaseType; bool isBaseTypeCollection = (baseType != null && baseType != Globals.TypeOfObject @@ -1193,7 +1130,7 @@ private static bool IsCollectionOrTryCreate(Type type, bool tryCreate, out DataC else { isReadOnlyContract = true; - GetReadOnlyCollectionExceptionMessages(type, SR.CollectionTypeDoesNotHaveDefaultCtor, null, out deserializationExceptionMessage); + GetReadOnlyCollectionExceptionMessages(type, hasCollectionDataContract, SR.CollectionTypeDoesNotHaveDefaultCtor, null, out serializationExceptionMessage, out deserializationExceptionMessage); } } } @@ -1247,22 +1184,22 @@ private static bool IsCollectionOrTryCreate(Type type, bool tryCreate, out DataC // All collection types could be considered read-only collections except collection types that are marked [Serializable]. // Collection types marked [Serializable] cannot be read-only collections for backward compatibility reasons. // DataContract types and POCO types cannot be collection types, so they don't need to be factored in. - if (type.IsSerializable) + if (type.IsSerializable || skipIfReadOnlyContract) { - return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, createContractWithException, + return HandleIfInvalidCollection(type, tryCreate, hasCollectionDataContract, createContractWithException && !skipIfReadOnlyContract, SR.CollectionTypeDoesNotHaveAddMethod, DataContract.GetClrTypeFullName(itemType), ref dataContract); } else { isReadOnlyContract = true; - GetReadOnlyCollectionExceptionMessages(type, SR.CollectionTypeDoesNotHaveAddMethod, DataContract.GetClrTypeFullName(itemType), out deserializationExceptionMessage); + GetReadOnlyCollectionExceptionMessages(type, hasCollectionDataContract, SR.CollectionTypeDoesNotHaveAddMethod, DataContract.GetClrTypeFullName(itemType), out serializationExceptionMessage, out deserializationExceptionMessage); } } if (tryCreate) { dataContract = isReadOnlyContract ? - new CollectionDataContract(type, kind, itemType, getEnumeratorMethod, deserializationExceptionMessage) : + new CollectionDataContract(type, kind, itemType, getEnumeratorMethod, serializationExceptionMessage, deserializationExceptionMessage) : new CollectionDataContract(type, kind, itemType, getEnumeratorMethod, addMethod, defaultCtor, !constructorRequired); } } @@ -1307,12 +1244,12 @@ private static bool IsCollectionOrTryCreate(Type type, bool tryCreate, out DataC Debug.Assert(getEnumeratorMethod != null); dataContract = isReadOnlyContract ? - new CollectionDataContract(type, kind, itemType, getEnumeratorMethod, deserializationExceptionMessage) : + new CollectionDataContract(type, kind, itemType, getEnumeratorMethod, serializationExceptionMessage, deserializationExceptionMessage) : new CollectionDataContract(type, kind, itemType, getEnumeratorMethod, addMethod, defaultCtor, !constructorRequired); } } - return true; + return !(isReadOnlyContract && skipIfReadOnlyContract); } internal static bool IsCollectionDataContract(Type type) @@ -1340,8 +1277,9 @@ private static bool HandleIfInvalidCollection(Type type, bool tryCreate, bool ha return false; } - private static void GetReadOnlyCollectionExceptionMessages(Type type, string message, string? param, out string deserializationExceptionMessage) + private static void GetReadOnlyCollectionExceptionMessages(Type type, bool hasCollectionDataContract, string message, string? param, out string serializationExceptionMessage, out string deserializationExceptionMessage) { + serializationExceptionMessage = GetInvalidCollectionMessage(message, SR.Format(hasCollectionDataContract ? SR.InvalidCollectionDataContract : SR.InvalidCollectionType, GetClrTypeFullName(type)), param); deserializationExceptionMessage = GetInvalidCollectionMessage(message, SR.Format(SR.ReadOnlyCollectionDeserialization, GetClrTypeFullName(type)), param); } @@ -1444,20 +1382,16 @@ private static bool IsKnownInterface(Type type) return false; } - internal override DataContract GetValidContract(SerializationMode mode) - { - if (InvalidCollectionInSharedContractMessage != null) - throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(InvalidCollectionInSharedContractMessage)); - - return this; - } - - internal override DataContract GetValidContract() + internal override DataContract GetValidContract(bool verifyConstructor = false) { - if (this.IsConstructorCheckRequired) + if (verifyConstructor && this.IsConstructorCheckRequired) { CheckConstructor(); + return this; } + + if (InvalidCollectionInSharedContractMessage != null) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(InvalidCollectionInSharedContractMessage)); return this; } @@ -1473,7 +1407,7 @@ private void CheckConstructor() } } - internal override bool IsValidContract(SerializationMode mode) + internal override bool IsValidContract() { return (InvalidCollectionInSharedContractMessage == null); } @@ -1573,6 +1507,28 @@ internal bool RequiresMemberAccessForWrite(SecurityException? securityException) return false; } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal override bool Equals(object? other, HashSet checkedContracts) + { + if (IsEqualOrChecked(other, checkedContracts)) + return true; + + if (base.Equals(other, checkedContracts)) + { + if (other is CollectionDataContract dataContract) + { + bool thisItemTypeIsNullable = (ItemContract == null) ? false : !ItemContract.IsValueType; + bool otherItemTypeIsNullable = (dataContract.ItemContract == null) ? false : !dataContract.ItemContract.IsValueType; + return ItemName == dataContract.ItemName && + (IsItemTypeNullable || thisItemTypeIsNullable) == (dataContract.IsItemTypeNullable || otherItemTypeIsNullable) && + ItemContract != null && ItemContract.Equals(dataContract.ItemContract, checkedContracts); + } + } + return false; + } + + public override int GetHashCode() => base.GetHashCode(); + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext? context) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs index 402b99053bd42..8d8b231b6bb77 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs @@ -3,6 +3,7 @@ using System; using System.Buffers.Binary; +using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; @@ -21,21 +22,11 @@ namespace System.Runtime.Serialization { internal abstract class DataContract { - private XmlDictionaryString _name; - - private XmlDictionaryString _ns; - - // this the global dictionary for data contracts introduced for multi-file. - private static readonly Dictionary s_dataContracts = new Dictionary(); - internal const string SerializerTrimmerWarning = "Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the " + "required types are preserved."; - public static Dictionary GetDataContracts() - { - return s_dataContracts; - } - + private XmlDictionaryString _name; + private XmlDictionaryString _ns; private readonly DataContractCriticalHelper _helper; internal DataContract(DataContractCriticalHelper helper) @@ -45,25 +36,6 @@ internal DataContract(DataContractCriticalHelper helper) _ns = helper.Namespace; } - private static DataContract? GetGeneratedDataContract(Type type) - { - // this method used to be rewritten by an IL transform - // with the restructuring for multi-file, it has become a regular method - DataContract? result; - return s_dataContracts.TryGetValue(type, out result) ? result : null; - } - - internal static bool TryGetDataContractFromGeneratedAssembly(Type type, out DataContract? dataContract) - { - dataContract = GetGeneratedDataContract(type); - return dataContract != null; - } - - internal static DataContract? GetDataContractFromGeneratedAssembly(Type? type) - { - return null; - } - internal MethodInfo? ParseMethod { get { return _helper.ParseMethod; } @@ -76,24 +48,18 @@ internal static DataContract GetDataContract(Type type) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static DataContract GetDataContract(RuntimeTypeHandle typeHandle, Type type) - { - return GetDataContract(typeHandle, type, SerializationMode.SharedContract); - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static DataContract GetDataContract(RuntimeTypeHandle typeHandle, Type? type, SerializationMode mode) + internal static DataContract GetDataContract(RuntimeTypeHandle typeHandle, Type? type) { int id = GetId(typeHandle); DataContract dataContract = GetDataContractSkipValidation(id, typeHandle, null); - return dataContract.GetValidContract(mode); + return dataContract.GetValidContract(); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static DataContract GetDataContract(int id, RuntimeTypeHandle typeHandle, SerializationMode mode) + internal static DataContract GetDataContract(int id, RuntimeTypeHandle typeHandle) { DataContract dataContract = GetDataContractSkipValidation(id, typeHandle, null); - return dataContract.GetValidContract(mode); + return dataContract.GetValidContract(); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -103,10 +69,10 @@ internal static DataContract GetDataContractSkipValidation(int id, RuntimeTypeHa } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static DataContract GetGetOnlyCollectionDataContract(int id, RuntimeTypeHandle typeHandle, Type? type, SerializationMode mode) + internal static DataContract GetGetOnlyCollectionDataContract(int id, RuntimeTypeHandle typeHandle, Type? type) { DataContract dataContract = GetGetOnlyCollectionDataContractSkipValidation(id, typeHandle, type); - dataContract = dataContract.GetValidContract(mode); + dataContract = dataContract.GetValidContract(); if (dataContract is ClassDataContract) { throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR.Format(SR.ErrorDeserializing, SR.Format(SR.ErrorTypeInfo, DataContract.GetClrTypeFullName(dataContract.UnderlyingType)), SR.Format(SR.NoSetMethodForProperty, string.Empty, string.Empty)))); @@ -171,29 +137,23 @@ internal static void ThrowInvalidDataContractException(string? message, Type? ty protected DataContractCriticalHelper Helper { - get - { return _helper; } + get { return _helper; } } [DynamicallyAccessedMembers(ClassDataContract.DataContractPreserveMemberTypes)] - public Type UnderlyingType + internal Type UnderlyingType { - get - { return _helper.UnderlyingType; } - set { _helper.UnderlyingType = value; } + get { return _helper.UnderlyingType; } } - public Type OriginalUnderlyingType + internal Type OriginalUnderlyingType { get { return _helper.OriginalUnderlyingType; } - set { _helper.OriginalUnderlyingType = value; } } - public virtual bool IsBuiltInDataContract + internal virtual bool IsBuiltInDataContract { - get - { return _helper.IsBuiltInDataContract; } - set { } + get { return _helper.IsBuiltInDataContract; } } internal Type TypeForInitialization @@ -225,7 +185,7 @@ public virtual object ReadXmlElement(XmlReaderDelegator xmlReader, XmlObjectSeri throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.UnexpectedContractType, DataContract.GetClrTypeFullName(this.GetType()), DataContract.GetClrTypeFullName(UnderlyingType)))); } - public bool IsValueType + internal bool IsValueType { get { return _helper.IsValueType; } @@ -234,7 +194,7 @@ public bool IsValueType { _helper.IsValueType = value; } } - public bool IsReference + internal bool IsReference { get { return _helper.IsReference; } @@ -243,7 +203,7 @@ public bool IsReference { _helper.IsReference = value; } } - public XmlQualifiedName StableName + internal XmlQualifiedName StableName { get { return _helper.StableName; } @@ -252,7 +212,7 @@ public XmlQualifiedName StableName { _helper.StableName = value; } } - public virtual DataContractDictionary? KnownDataContracts + internal virtual DataContractDictionary? KnownDataContracts { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get @@ -262,28 +222,26 @@ public virtual DataContractDictionary? KnownDataContracts { _helper.KnownDataContracts = value; } } - public virtual bool IsISerializable + internal virtual bool IsISerializable { get { return _helper.IsISerializable; } set { _helper.IsISerializable = value; } } - public XmlDictionaryString Name + internal XmlDictionaryString Name { get { return _name; } - set { _name = value; } } - public virtual XmlDictionaryString Namespace + internal virtual XmlDictionaryString Namespace { get { return _ns; } - set { _ns = value; } } - public virtual bool HasRoot + internal virtual bool HasRoot { get { return true; } @@ -292,7 +250,7 @@ public virtual bool HasRoot { } } - public virtual XmlDictionaryString? TopLevelElementName + internal virtual XmlDictionaryString? TopLevelElementName { get { return _helper.TopLevelElementName; } @@ -301,7 +259,7 @@ public virtual XmlDictionaryString? TopLevelElementName { _helper.TopLevelElementName = value; } } - public virtual XmlDictionaryString? TopLevelElementNamespace + internal virtual XmlDictionaryString? TopLevelElementNamespace { get { return _helper.TopLevelElementNamespace; } @@ -328,32 +286,30 @@ internal virtual void WriteRootElement(XmlWriterDelegator writer, XmlDictionaryS writer.WriteStartElement(name, ns); } - internal virtual DataContract GetValidContract(SerializationMode mode) - { - return this; - } - - internal virtual DataContract GetValidContract() + internal virtual DataContract GetValidContract(bool verifyConstructor = false) { return this; } - internal virtual bool IsValidContract(SerializationMode mode) + internal virtual bool IsValidContract() { return true; } internal class DataContractCriticalHelper { - private static readonly Dictionary s_typeToIDCache = new Dictionary(new TypeHandleRefEqualityComparer()); + private static readonly Hashtable s_typeToIDCache = new Hashtable(new HashTableEqualityComparer()); private static DataContract[] s_dataContractCache = new DataContract[32]; private static int s_dataContractID; private static Dictionary? s_typeToBuiltInContract; private static Dictionary? s_nameToBuiltInContract; - private static Dictionary? s_namespaces; + private static Dictionary? s_typeNameToBuiltInContract; + private static Hashtable s_namespaces = new Hashtable(); private static Dictionary? s_clrTypeStrings; private static XmlDictionary? s_clrTypeStringsDictionary; - private static readonly TypeHandleRef s_typeHandleRef = new TypeHandleRef(); + + [ThreadStatic] + private static TypeHandleRef? s_typeHandleRef; private static readonly object s_cacheLock = new object(); private static readonly object s_createDataContractLock = new object(); @@ -362,10 +318,11 @@ internal class DataContractCriticalHelper private static readonly object s_clrTypeStringsLock = new object(); [DynamicallyAccessedMembers(ClassDataContract.DataContractPreserveMemberTypes)] - private Type _underlyingType; + private readonly Type _underlyingType; private Type? _originalUnderlyingType; private bool _isReference; private bool _isValueType; + private GenericInfo? _genericInfo; private XmlQualifiedName _stableName = null!; // StableName is always set in concrete ctors set except for the "invalid" CollectionDataContract private XmlDictionaryString _name = null!; // Name is always set in concrete ctors set except for the "invalid" CollectionDataContract private XmlDictionaryString _ns = null!; // Namespace is always set in concrete ctors set except for the "invalid" CollectionDataContract @@ -385,11 +342,10 @@ internal static DataContract GetDataContractSkipValidation(int id, RuntimeTypeHa if (dataContract == null) { dataContract = CreateDataContract(id, typeHandle, type); - AssignDataContractToId(dataContract, id); } else { - return dataContract.GetValidContract(); + return dataContract.GetValidContract(verifyConstructor: true); } return dataContract; } @@ -401,7 +357,6 @@ internal static DataContract GetGetOnlyCollectionDataContractSkipValidation(int if (dataContract == null) { dataContract = CreateGetOnlyCollectionDataContract(id, typeHandle, type); - s_dataContractCache[id] = dataContract; } return dataContract; } @@ -418,7 +373,7 @@ internal static DataContract GetDataContractForInitialization(int id) internal static int GetIdForInitialization(ClassDataContract classContract) { - int id = DataContract.GetId(classContract.TypeForInitialization!.TypeHandle); + int id = DataContract.GetId(classContract.TypeForInitialization.TypeHandle); if (id < s_dataContractCache.Length && ContractMatches(classContract, s_dataContractCache[id])) { return id; @@ -441,35 +396,42 @@ private static bool ContractMatches(DataContract contract, DataContract cachedCo internal static int GetId(RuntimeTypeHandle typeHandle) { - lock (s_cacheLock) + typeHandle = GetDataContractAdapterTypeHandle(typeHandle); + s_typeHandleRef ??= new TypeHandleRef(); + s_typeHandleRef.Value = typeHandle; + + object? value = s_typeToIDCache[s_typeHandleRef]; + if (value != null) + return ((IntRef)value).Value; + + try { - IntRef? id; - typeHandle = GetDataContractAdapterTypeHandle(typeHandle); - s_typeHandleRef.Value = typeHandle; - if (!s_typeToIDCache.TryGetValue(s_typeHandleRef, out id)) + lock (s_cacheLock) { - int value = s_dataContractID++; - if (value >= s_dataContractCache.Length) + value = s_typeToIDCache[s_typeHandleRef]; + if (value != null) + return ((IntRef)value).Value; + + int nextId = s_dataContractID++; + if (nextId >= s_dataContractCache.Length) { - int newSize = (value < int.MaxValue / 2) ? value * 2 : int.MaxValue; - if (newSize <= value) + int newSize = (nextId < int.MaxValue / 2) ? nextId * 2 : int.MaxValue; + if (newSize <= nextId) { DiagnosticUtility.DebugAssert("DataContract cache overflow"); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR.DataContractCacheOverflow)); } Array.Resize(ref s_dataContractCache, newSize); } - id = new IntRef(value); - try - { - s_typeToIDCache.Add(new TypeHandleRef(typeHandle), id); - } - catch (Exception ex) - { - throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(ex.Message, ex); - } + IntRef id = new IntRef(nextId); + + s_typeToIDCache.Add(new TypeHandleRef(typeHandle), id); + return id.Value; } - return id.Value; + } + catch (Exception ex) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(ex.Message, ex); } } @@ -486,16 +448,8 @@ private static DataContract CreateDataContract(int id, RuntimeTypeHandle typeHan if (dataContract == null) { type ??= Type.GetTypeFromHandle(typeHandle)!; - type = UnwrapNullableType(type); - - dataContract = DataContract.GetDataContractFromGeneratedAssembly(type); - if (dataContract != null) - { - AssignDataContractToId(dataContract, id); - return dataContract; - } - dataContract = CreateDataContract(type); + AssignDataContractToId(dataContract, id); } } } @@ -517,18 +471,18 @@ private static DataContract CreateDataContract(Type type) dataContract = new CollectionDataContract(type); else if (type.IsEnum) dataContract = new EnumDataContract(type); + else if (type.IsGenericParameter) + dataContract = new GenericParameterDataContract(type); else if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type)) dataContract = new XmlDataContract(type); - else if (Globals.TypeOfScriptObject_IsAssignableFrom(type)) - dataContract = Globals.CreateScriptObjectClassDataContract(); else { - //if (type.ContainsGenericParameters) - // ThrowInvalidDataContractException(SR.Format(SR.TypeMustNotBeOpenGeneric, type), type); + if (type.IsPointer) + type = Globals.TypeOfReflectionPointer; if (!CollectionDataContract.TryCreate(type, out dataContract)) { - if (!type.IsSerializable && !type.IsDefined(Globals.TypeOfDataContractAttribute, false) && !ClassDataContract.IsNonAttributedTypeValidForSerialization(type) && !ClassDataContract.IsKnownSerializableType(type)) + if (!type.IsSerializable && !type.IsDefined(Globals.TypeOfDataContractAttribute, false) && !ClassDataContract.IsNonAttributedTypeValidForSerialization(type)) { ThrowInvalidDataContractException(SR.Format(SR.TypeNotSerializable, type), type); } @@ -574,8 +528,10 @@ private static DataContract CreateGetOnlyCollectionDataContract(int id, RuntimeT { ThrowInvalidDataContractException(SR.Format(SR.TypeNotSerializable, type), type); } + AssignDataContractToId(dataContract, id); } } + // !; // If null after the lookup and creation attempts above, the 'ThrowInvalidDataContractException' kicks in. return dataContract; } @@ -594,10 +550,6 @@ internal static Type GetDataContractAdapterType(Type type) { return Globals.TypeOfMemoryStreamAdapter; } - if (type.IsGenericType && type.GetGenericTypeDefinition() == Globals.TypeOfKeyValuePair) - { - return Globals.TypeOfKeyValuePairAdapter.MakeGenericType(type.GetGenericArguments()); - } return type; } @@ -659,8 +611,10 @@ private static RuntimeTypeHandle GetDataContractAdapterTypeHandle(RuntimeTypeHan XmlQualifiedName qname = new XmlQualifiedName(name, ns); if (!s_nameToBuiltInContract.TryGetValue(qname, out dataContract)) { - TryCreateBuiltInDataContract(name, ns, out dataContract); - s_nameToBuiltInContract.Add(qname, dataContract); + if (TryCreateBuiltInDataContract(name, ns, out dataContract)) + { + s_nameToBuiltInContract.Add(qname, dataContract); + } } return dataContract; } @@ -674,11 +628,10 @@ private static RuntimeTypeHandle GetDataContractAdapterTypeHandle(RuntimeTypeHan lock (s_initBuiltInContractsLock) { - s_nameToBuiltInContract ??= new Dictionary(); + s_typeNameToBuiltInContract ??= new Dictionary(); DataContract? dataContract; - XmlQualifiedName qname = new XmlQualifiedName(typeName); - if (!s_nameToBuiltInContract.TryGetValue(qname, out dataContract)) + if (!s_typeNameToBuiltInContract.TryGetValue(typeName, out dataContract)) { Type? type = null; string name = typeName.Substring(7); @@ -738,7 +691,7 @@ private static RuntimeTypeHandle GetDataContractAdapterTypeHandle(RuntimeTypeHan if (type != null) TryCreateBuiltInDataContract(type, out dataContract); - s_nameToBuiltInContract.Add(qname, dataContract); + s_typeNameToBuiltInContract.Add(typeName, dataContract); } return dataContract; } @@ -753,7 +706,7 @@ public static bool TryCreateBuiltInDataContract(Type type, [NotNullWhen(true)] o return false; } dataContract = null; - switch (type.GetTypeCode()) + switch (Type.GetTypeCode(type)) { case TypeCode.Boolean: dataContract = new BooleanDataContract(); @@ -951,23 +904,27 @@ public static bool TryCreateBuiltInDataContract(string name, string ns, [NotNull internal static string GetNamespace(string key) { - lock (s_namespacesLock) + object? value = s_namespaces[key]; + + if (value != null) + return (string)value; + + try { - s_namespaces ??= new Dictionary(); - if (s_namespaces.TryGetValue(key, out string? value)) + lock (s_namespacesLock) { - return value; - } + value = s_namespaces[key]; + + if (value != null) + return (string)value; - try - { s_namespaces.Add(key, key); + return key; } - catch (Exception ex) - { - throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(ex.Message, ex); - } - return key; + } + catch (Exception ex) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(ex.Message, ex); } } @@ -1011,14 +968,15 @@ internal static void ThrowInvalidDataContractException(string? message, Type? ty { lock (s_cacheLock) { + s_typeHandleRef ??= new TypeHandleRef(); s_typeHandleRef.Value = GetDataContractAdapterTypeHandle(type.TypeHandle); - try - { - s_typeToIDCache.Remove(s_typeHandleRef); - } - catch (Exception ex) + + if (s_typeToIDCache.ContainsKey(s_typeHandleRef)) { - throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(ex.Message, ex); + lock (s_cacheLock) + { + s_typeToIDCache.Remove(s_typeHandleRef); + } } } } @@ -1039,13 +997,11 @@ internal DataContractCriticalHelper( internal Type UnderlyingType { get { return _underlyingType; } - set { _underlyingType = value; } } internal Type OriginalUnderlyingType { - get => _originalUnderlyingType ??= GetDataContractOriginalType(this._underlyingType); - set => _originalUnderlyingType = value; + get => _originalUnderlyingType ??= GetDataContractOriginalType(_underlyingType); } internal virtual bool IsBuiltInDataContract @@ -1064,6 +1020,11 @@ internal Type TypeForInitialization [MemberNotNull(nameof(_typeForInitialization))] private void SetTypeForInitialization(Type classType) { + // NOTE TODO smolloy - This 'if' was not commented in 4.8. But 4.8 was not dealing with nullable notations, which we do have here in Core. + // With the absence of schema importing, it does not make sense to have a data contract without a valid serializable underlying type. (Even + // with schema importing it doesn't make sense, but there is a building period while we're still figuring out all the data types and contracts + // where the underlying type may be null.) Anyway... might it make sense to re-instate this if clause - but use it to throw an exception if + // we don't meet the criteria? That way we can maintain nullable semantics and not do anything silly trying to keep them simple. //if (classType.IsSerializable || classType.IsDefined(Globals.TypeOfDataContractAttribute, false)) { _typeForInitialization = classType; @@ -1091,6 +1052,12 @@ internal XmlQualifiedName StableName set { _stableName = value; } } + internal GenericInfo? GenericInfo + { + get { return _genericInfo; } + set { _genericInfo = value; } + } + internal virtual DataContractDictionary? KnownDataContracts { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -1234,9 +1201,34 @@ private static void ValidatePreviousCollectionTypes(Type collectionType, Type it { itemType = itemType.GetElementType()!; } - if (previousCollectionTypes.Contains(itemType)) + + // Do a breadth first traversal of the generic type tree to + // produce the closure of all generic argument types and + // check that none of these is in the previousCollectionTypes + List itemTypeClosure = new List(); + Queue itemTypeQueue = new Queue(); + + itemTypeQueue.Enqueue(itemType); + itemTypeClosure.Add(itemType); + + while (itemTypeQueue.Count > 0) { - throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.RecursiveCollectionType, GetClrTypeFullName(itemType)))); + itemType = itemTypeQueue.Dequeue(); + if (previousCollectionTypes.Contains(itemType)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.RecursiveCollectionType, GetClrTypeFullName(itemType)))); + } + if (itemType.IsGenericType) + { + foreach (Type argType in itemType.GetGenericArguments()) + { + if (!itemTypeClosure.Contains(argType)) + { + itemTypeQueue.Enqueue(argType); + itemTypeClosure.Add(argType); + } + } + } } } @@ -1295,10 +1287,6 @@ internal static bool IsValidNCName(string name) { return false; } - catch (Exception) - { - return false; - } } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -1309,10 +1297,16 @@ internal static XmlQualifiedName GetStableName(Type type) [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal static XmlQualifiedName GetStableName(Type type, out bool hasDataContract) + { + return GetStableName(type, new HashSet(), out hasDataContract); + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal static XmlQualifiedName GetStableName(Type type, HashSet previousCollectionTypes, out bool hasDataContract) { type = UnwrapRedundantNullableType(type); XmlQualifiedName? stableName; - if (TryGetBuiltInXmlAndArrayTypeStableName(type, out stableName)) + if (TryGetBuiltInXmlAndArrayTypeStableName(type, previousCollectionTypes, out stableName)) { hasDataContract = false; } @@ -1326,7 +1320,7 @@ internal static XmlQualifiedName GetStableName(Type type, out bool hasDataContra } else { - stableName = GetNonDCTypeStableName(type); + stableName = GetNonDCTypeStableName(type, previousCollectionTypes); hasDataContract = false; } } @@ -1364,13 +1358,16 @@ private static XmlQualifiedName GetDCTypeStableName(Type type, DataContractAttri } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private static XmlQualifiedName GetNonDCTypeStableName(Type type) + private static XmlQualifiedName GetNonDCTypeStableName(Type type, HashSet previousCollectionTypes) { string? name, ns; Type? itemType; if (CollectionDataContract.IsCollection(type, out itemType)) - return GetCollectionStableName(type, itemType, out _); + { + ValidatePreviousCollectionTypes(type, itemType, previousCollectionTypes); + return GetCollectionStableName(type, itemType, previousCollectionTypes, out _); + } name = GetDefaultStableLocalName(type); // ensures that ContractNamespaceAttribute is honored when used with non-attributed types @@ -1386,7 +1383,7 @@ private static XmlQualifiedName GetNonDCTypeStableName(Type type) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private static bool TryGetBuiltInXmlAndArrayTypeStableName(Type type, [NotNullWhen(true)] out XmlQualifiedName? stableName) + private static bool TryGetBuiltInXmlAndArrayTypeStableName(Type type, HashSet previousCollectionTypes, [NotNullWhen(true)] out XmlQualifiedName? stableName) { stableName = null; @@ -1403,7 +1400,9 @@ private static bool TryGetBuiltInXmlAndArrayTypeStableName(Type type, [NotNullWh } else if (type.IsArray) { - stableName = GetCollectionStableName(type, type.GetElementType()!, out _); + Type itemType = type.GetElementType()!; + ValidatePreviousCollectionTypes(type, itemType, previousCollectionTypes); + stableName = GetCollectionStableName(type, itemType, previousCollectionTypes, out _); } return stableName != null; } @@ -1427,6 +1426,12 @@ internal static bool TryGetDCAttribute(Type type, [NotNullWhen(true)] out DataCo [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal static XmlQualifiedName GetCollectionStableName(Type type, Type itemType, out CollectionDataContractAttribute? collectionContractAttribute) + { + return GetCollectionStableName(type, itemType, new HashSet(), out collectionContractAttribute); + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal static XmlQualifiedName GetCollectionStableName(Type type, Type itemType, HashSet previousCollectionTypes, out CollectionDataContractAttribute? collectionContractAttribute) { string? name, ns; object[] collectionContractAttributes = type.GetCustomAttributes(Globals.TypeOfCollectionDataContractAttribute, false).ToArray(); @@ -1463,7 +1468,7 @@ internal static XmlQualifiedName GetCollectionStableName(Type type, Type itemTyp { collectionContractAttribute = null; string arrayOfPrefix = Globals.ArrayPrefix + GetArrayPrefix(ref itemType); - XmlQualifiedName elementStableName = GetStableName(itemType); + XmlQualifiedName elementStableName = GetStableName(itemType, previousCollectionTypes, out _); name = arrayOfPrefix + elementStableName.Name; ns = GetCollectionNamespace(elementStableName.Namespace); } @@ -1588,7 +1593,7 @@ internal static List GetDataContractNameForGenericName(string typeName, Str if (localName != null) { string tempLocalName = typeName.Substring(startIndex, endIndex - startIndex); - localName.Append((tempLocalName.Equals("KeyValuePairAdapter") ? "KeyValuePair" : tempLocalName)); + localName.Append(tempLocalName); } while ((startIndex = typeName.IndexOf('.', startIndex + 1, endIndex - startIndex - 1)) >= 0) nestedParamCounts.Add(0); @@ -1670,7 +1675,7 @@ private static void GetDefaultStableName(CodeTypeReference typeReference, out st { foreach (int count in nestedParamCounts) { - argNamespacesBuilder.Insert(0, count).Insert(0, ' '); + argNamespacesBuilder.Insert(0, count.ToString(CultureInfo.InvariantCulture)).Insert(0, ' '); } localNameBuilder.Append(GetNamespacesDigest(argNamespacesBuilder.ToString())); @@ -2037,6 +2042,7 @@ private static void ImportKnownTypeAttributes(Type? type, Dictionary } } + // NOTE TODO smolloy - This try/catch block is new in CoreFx from the beginning. I wonder why it wasn't there in NetFx. Is it needed there? Or not-needed here? //For Json we need to add KeyValuePair to KnownTypes if the UnderLyingType is a Dictionary try { @@ -2074,9 +2080,9 @@ internal static void CheckAndAdd(Type type, Dictionary typesChecked, } else if (nameToDataContractTable.TryGetValue(dataContract.StableName, out alreadyExistingContract)) { + // NOTE TODO smolloy - The existing contract type was used as-is in NetFx. The call to get the appropriate adapter type was added in CoreFx with https://github.com/dotnet/runtime/commit/50c0a70c52fa66fafa1227be552ccdab5e4cf8e4 // Don't throw duplicate if its a KeyValuePair as it could have been added by Dictionary - if (DataContractCriticalHelper.GetDataContractAdapterType(alreadyExistingContract.UnderlyingType) != DataContractCriticalHelper.GetDataContractAdapterType(type) && - !(alreadyExistingContract is ClassDataContract && ((ClassDataContract)alreadyExistingContract).IsKeyValuePairAdapter)) + if (DataContractCriticalHelper.GetDataContractAdapterType(alreadyExistingContract.UnderlyingType) != DataContractCriticalHelper.GetDataContractAdapterType(type)) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.DupContractInKnownTypes, type, alreadyExistingContract.UnderlyingType, dataContract.StableName.Namespace, dataContract.StableName.Name))); return; } @@ -2084,6 +2090,48 @@ internal static void CheckAndAdd(Type type, Dictionary typesChecked, ImportKnownTypeAttributes(type, typesChecked, ref nameToDataContractTable); } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", + Justification = "DataContract is an internal type, but the override here is the very public Object.Equals(). Being an internal type" + + "though, we control when this is called, and all callers are annotated with [RequiresUnreferencedCode].")] + public sealed override bool Equals(object? other) + { + if ((object)this == other) + return true; + return Equals(other, new HashSet()); + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal virtual bool Equals(object? other, HashSet checkedContracts) + { + DataContract? dataContract = other as DataContract; + if (dataContract != null) + { + return (StableName.Name == dataContract.StableName.Name && StableName.Namespace == dataContract.StableName.Namespace && IsReference == dataContract.IsReference); + } + return false; + } + + internal bool IsEqualOrChecked(object? other, HashSet checkedContracts) + { + if (other == null) + return false; + + if ((object)this == other) + return true; + + DataContractPairKey contractPairKey = new DataContractPairKey(this, other); + if (checkedContracts.Contains(contractPairKey)) + return true; + checkedContracts.Add(contractPairKey); + + return false; + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + /// /// Review - checks type visibility to calculate if access to it requires MemberAccessPermission. /// since this information is used to determine whether to give the generated code access @@ -2091,18 +2139,46 @@ internal static void CheckAndAdd(Type type, Dictionary typesChecked, /// internal static bool IsTypeVisible(Type t) { - if (!t.IsVisible && !IsTypeVisibleInSerializationModule(t)) + // Generic parameters are always considered visible. + if (t.IsGenericParameter) + { + return true; + } + + // The normal Type.IsVisible check requires all nested types to be IsNestedPublic. + // This does not comply with our convention where they can also have InternalsVisibleTo + // with our assembly. The following method performs a recursive walk back the declaring + // type hierarchy to perform this enhanced IsVisible check. + if (!IsTypeAndDeclaringTypeVisible(t)) return false; foreach (Type genericType in t.GetGenericArguments()) { - if (!genericType.IsGenericParameter && !IsTypeVisible(genericType)) + if (!IsTypeVisible(genericType)) return false; } return true; } + internal static bool IsTypeAndDeclaringTypeVisible(Type t) + { + // Arrays, etc. must consider the underlying element type because the + // non-element type does not reflect the same type nesting. For example, + // MyClass[] would not show as a nested type, even when MyClass is nested. + if (t.HasElementType) + { + return IsTypeVisible(t.GetElementType()!); + } + + // Nested types are not visible unless their declaring type is visible. + // Additionally, they must be either IsNestedPublic or in an assembly with InternalsVisibleTo this current assembly. + // Non-nested types must be public or have this same InternalsVisibleTo relation. + return t.IsNested + ? (t.IsNestedPublic || IsTypeVisibleInSerializationModule(t)) && IsTypeVisible(t.DeclaringType!) + : t.IsPublic || IsTypeVisibleInSerializationModule(t); + } + /// /// Review - checks constructor visibility to calculate if access to it requires MemberAccessPermission. /// note: does local check for visibility, assuming that the declaring Type visibility has been checked. @@ -2207,7 +2283,7 @@ internal interface IGenericNameProvider string GetParameterName(int paramIndex); [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] string GetNamespaces(); - string GetGenericTypeName(); + string? GetGenericTypeName(); bool ParametersFromBuiltInNamespaces { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -2261,7 +2337,7 @@ public string GetNamespaces() return namespaces.ToString(); } - public string GetGenericTypeName() + public string? GetGenericTypeName() { return _genericTypeName; } @@ -2300,7 +2376,158 @@ private XmlQualifiedName GetStableName(int i) } } + internal sealed class GenericInfo : IGenericNameProvider + { + private string? _genericTypeName; + private XmlQualifiedName _stableName; + private List? _paramGenericInfos; + private List _nestedParamCounts; + + internal GenericInfo(XmlQualifiedName stableName, string? genericTypeName) + { + _stableName = stableName; + _genericTypeName = genericTypeName; + _nestedParamCounts = new List(); + _nestedParamCounts.Add(0); + } + + internal void Add(GenericInfo actualParamInfo) + { + if (_paramGenericInfos == null) + _paramGenericInfos = new List(); + _paramGenericInfos.Add(actualParamInfo); + } + + internal void AddToLevel(int level, int count) + { + if (level >= _nestedParamCounts.Count) + { + do + { + _nestedParamCounts.Add((level == _nestedParamCounts.Count) ? count : 0); + } while (level >= _nestedParamCounts.Count); + } + else + _nestedParamCounts[level] = _nestedParamCounts[level] + count; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal XmlQualifiedName GetExpandedStableName() + { + if (_paramGenericInfos == null) + return _stableName; + return new XmlQualifiedName(DataContract.EncodeLocalName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(_stableName.Name), this)), _stableName.Namespace); + } + + internal string GetStableNamespace() + { + return _stableName.Namespace; + } + + internal XmlQualifiedName StableName + { + get { return _stableName; } + } + + internal IList? Parameters + { + get { return _paramGenericInfos; } + } + + public int GetParameterCount() + { + return _paramGenericInfos?.Count ?? 0; + } + + public IList GetNestedParameterCounts() + { + return _nestedParamCounts; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + public string GetParameterName(int paramIndex) + { + Debug.Assert(_paramGenericInfos != null); + return _paramGenericInfos[paramIndex].GetExpandedStableName().Name; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + public string GetNamespaces() + { + if (_paramGenericInfos == null || _paramGenericInfos.Count == 0) + return ""; + + StringBuilder namespaces = new StringBuilder(); + for (int j = 0; j < _paramGenericInfos.Count; j++) + namespaces.Append(' ').Append(_paramGenericInfos[j].GetStableNamespace()); + return namespaces.ToString(); + } + + public string? GetGenericTypeName() + { + return _genericTypeName; + } + + public bool ParametersFromBuiltInNamespaces + { + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + get + { + bool parametersFromBuiltInNamespaces = true; + + if (_paramGenericInfos == null || _paramGenericInfos.Count == 0) + return parametersFromBuiltInNamespaces; + + for (int j = 0; j < _paramGenericInfos.Count; j++) + { + if (parametersFromBuiltInNamespaces) + parametersFromBuiltInNamespaces = DataContract.IsBuiltInNamespace(_paramGenericInfos[j].GetStableNamespace()); + else + break; + } + return parametersFromBuiltInNamespaces; + } + } + + } + + internal sealed class DataContractPairKey + { + private object _object1; + private object _object2; + public DataContractPairKey(object object1, object object2) + { + _object1 = object1; + _object2 = object2; + } + + public override bool Equals(object? other) + { + DataContractPairKey? otherKey = other as DataContractPairKey; + if (otherKey == null) + return false; + return ((otherKey._object1 == _object1 && otherKey._object2 == _object2) || (otherKey._object1 == _object2 && otherKey._object2 == _object1)); + } + + public override int GetHashCode() + { + return _object1.GetHashCode() ^ _object2.GetHashCode(); + } + } + + internal sealed class HashTableEqualityComparer : IEqualityComparer + { + bool IEqualityComparer.Equals(object? x, object? y) + { + return ((TypeHandleRef)x!).Value.Equals(((TypeHandleRef)y!).Value); + } + + public int GetHashCode(object obj) + { + return ((TypeHandleRef)obj).Value.GetHashCode(); + } + } internal sealed class TypeHandleRefEqualityComparer : IEqualityComparer { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs index c42b4854c82a7..6db625cc1cd67 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs @@ -34,19 +34,19 @@ public sealed class DataContractSerializer : XmlObjectSerializer private ISerializationSurrogateProvider? _serializationSurrogateProvider; private bool _serializeReadOnlyTypes; - private static SerializationOption _option = IsReflectionBackupAllowed() ? SerializationOption.ReflectionAsBackup : SerializationOption.CodeGenOnly; - private static bool _optionAlreadySet; + private static SerializationOption s_option = IsReflectionBackupAllowed() ? SerializationOption.ReflectionAsBackup : SerializationOption.CodeGenOnly; + private static bool s_optionAlreadySet; internal static SerializationOption Option { - get { return RuntimeFeature.IsDynamicCodeSupported ? _option : SerializationOption.ReflectionOnly; } + get { return RuntimeFeature.IsDynamicCodeSupported ? s_option : SerializationOption.ReflectionOnly; } set { - if (_optionAlreadySet) + if (s_optionAlreadySet) { throw new InvalidOperationException(SR.CannotSetTwice); } - _optionAlreadySet = true; - _option = value; + s_optionAlreadySet = true; + s_option = value; } } @@ -61,11 +61,10 @@ public DataContractSerializer(Type type) } public DataContractSerializer(Type type, IEnumerable? knownTypes) + : this(type, knownTypes, int.MaxValue, false, false) { - Initialize(type, knownTypes, int.MaxValue, false, false, null, false); } - public DataContractSerializer(Type type, string rootName, string rootNamespace) : this(type, rootName, rootNamespace, null) { @@ -77,7 +76,6 @@ public DataContractSerializer(Type type, string rootName, string rootNamespace, Initialize(type, dictionary.Add(rootName), dictionary.Add(DataContract.GetNamespace(rootNamespace)), knownTypes, int.MaxValue, false, false, null, false); } - public DataContractSerializer(Type type, XmlDictionaryString rootName, XmlDictionaryString rootNamespace) : this(type, rootName, rootNamespace, null) { @@ -88,7 +86,7 @@ public DataContractSerializer(Type type, XmlDictionaryString rootName, XmlDictio Initialize(type, rootName, rootNamespace, knownTypes, int.MaxValue, false, false, null, false); } - internal DataContractSerializer(Type type, IEnumerable knownTypes, int maxItemsInObjectGraph, bool ignoreExtensionDataObject, bool preserveObjectReferences) + internal DataContractSerializer(Type type, IEnumerable? knownTypes, int maxItemsInObjectGraph, bool ignoreExtensionDataObject, bool preserveObjectReferences) { Initialize(type, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, preserveObjectReferences, null, false); } @@ -96,7 +94,7 @@ internal DataContractSerializer(Type type, IEnumerable knownTypes, int max public DataContractSerializer(Type type, DataContractSerializerSettings? settings) { settings ??= new DataContractSerializerSettings(); - Initialize(type, settings.RootName, settings.RootNamespace, settings.KnownTypes, settings.MaxItemsInObjectGraph, false, + Initialize(type, settings.RootName, settings.RootNamespace, settings.KnownTypes, settings.MaxItemsInObjectGraph, settings.IgnoreExtensionDataObject, settings.PreserveObjectReferences, settings.DataContractResolver, settings.SerializeReadOnlyTypes); } @@ -408,7 +406,7 @@ internal static DataContract GetDataContract(DataContract declaredTypeContract, } else { - return DataContract.GetDataContract(objectType.TypeHandle, objectType, SerializationMode.SharedContract); + return DataContract.GetDataContract(objectType.TypeHandle, objectType); } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs index 41bae413f816a..70f49a0a108cd 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs @@ -17,26 +17,11 @@ internal sealed class DataContractSet private readonly ICollection _referencedTypes; private readonly ICollection _referencedCollectionTypes; -#if SUPPORT_SURROGATE - private IDataContractSurrogate _dataContractSurrogate; - private Hashtable _surrogateDataTable; - - internal DataContractSet(IDataContractSurrogate dataContractSurrogate) : this(dataContractSurrogate, null, null) { } - - internal DataContractSet(IDataContractSurrogate dataContractSurrogate, ICollection referencedTypes, ICollection referencedCollectionTypes) - { - _dataContractSurrogate = dataContractSurrogate; - _referencedTypes = referencedTypes; - _referencedCollectionTypes = referencedCollectionTypes; - } -#endif - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal DataContractSet(DataContractSet dataContractSet) { ArgumentNullException.ThrowIfNull(dataContractSet); - //this.dataContractSurrogate = dataContractSet.dataContractSurrogate; _referencedTypes = dataContractSet._referencedTypes; _referencedCollectionTypes = dataContractSet._referencedCollectionTypes; @@ -60,10 +45,6 @@ internal DataContractSet(DataContractSet dataContractSet) private Dictionary ProcessedContracts => _processedContracts ??= new Dictionary(); -#if SUPPORT_SURROGATE - private Hashtable SurrogateDataTable => _surrogateDataTable ??= new Hashtable(); -#endif - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal void Add(Type type) { @@ -143,17 +124,6 @@ private void AddClassDataContract(ClassDataContract classDataContract) { DataMember dataMember = classDataContract.Members[i]; DataContract memberDataContract = GetMemberTypeDataContract(dataMember); -#if SUPPORT_SURROGATE - if (_dataContractSurrogate != null && dataMember.MemberInfo != null) - { - object customData = DataContractSurrogateCaller.GetCustomDataToExport( - _dataContractSurrogate, - dataMember.MemberInfo, - memberDataContract.UnderlyingType); - if (customData != null) - SurrogateDataTable.Add(dataMember, customData); - } -#endif Add(memberDataContract.StableName, memberDataContract); } } @@ -199,30 +169,12 @@ private void AddKnownDataContracts(DataContractDictionary? knownDataContracts) [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal static DataContract GetDataContract(Type clrType) { -#if SUPPORT_SURROGATE - if (_dataContractSurrogate == null) - return DataContract.GetDataContract(clrType); -#endif DataContract? dataContract = DataContract.GetBuiltInDataContract(clrType); if (dataContract != null) return dataContract; -#if SUPPORT_SURROGATE - Type dcType = DataContractSurrogateCaller.GetDataContractType(_dataContractSurrogate, clrType); - if (clrType.IsValueType != dcType.IsValueType) - throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.ValueTypeMismatchInSurrogatedType, dcType, clrType))); -#endif Type dcType = clrType; dataContract = DataContract.GetDataContract(dcType); -#if SUPPORT_SURROGATE - if (!SurrogateDataTable.Contains(dataContract)) - { - object customData = DataContractSurrogateCaller.GetCustomDataToExport( - _dataContractSurrogate, clrType, dcType); - if (customData != null) - SurrogateDataTable.Add(dataContract, customData); - } -#endif return dataContract; } @@ -232,18 +184,7 @@ internal static DataContract GetMemberTypeDataContract(DataMember dataMember) Type dataMemberType = dataMember.MemberType; if (dataMember.IsGetOnlyCollection) { -#if SUPPORT_SURROGATE - if (_dataContractSurrogate != null) - { - Type dcType = DataContractSurrogateCaller.GetDataContractType(_dataContractSurrogate, dataMemberType); - if (dcType != dataMemberType) - { - throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.GetString(SR.SurrogatesWithGetOnlyCollectionsNotSupported, - DataContract.GetClrTypeFullName(dataMemberType), DataContract.GetClrTypeFullName(dataMember.MemberInfo.DeclaringType), dataMember.MemberInfo.Name))); - } - } -#endif - return DataContract.GetGetOnlyCollectionDataContract(DataContract.GetId(dataMemberType.TypeHandle), dataMemberType.TypeHandle, dataMemberType, SerializationMode.SharedContract); + return DataContract.GetGetOnlyCollectionDataContract(DataContract.GetId(dataMemberType.TypeHandle), dataMemberType.TypeHandle, dataMemberType); } else { @@ -259,23 +200,6 @@ internal static DataContract GetItemTypeDataContract(CollectionDataContract coll return collectionContract.ItemContract; } -#if SUPPORT_SURROGATE - internal object GetSurrogateData(object key) - { - return SurrogateDataTable[key]; - } - - internal void SetSurrogateData(object key, object surrogateData) - { - SurrogateDataTable[key] = surrogateData; - } - - public IDataContractSurrogate DataContractSurrogate - { - get { return _dataContractSurrogate; } - } -#endif - public IEnumerator> GetEnumerator() { return Contracts.GetEnumerator(); @@ -290,20 +214,5 @@ internal void SetContractProcessed(DataContract dataContract) { ProcessedContracts.Add(dataContract, dataContract); } - -#if SUPPORT_SURROGATE - internal ContractCodeDomInfo GetContractCodeDomInfo(DataContract dataContract) - { - object info; - if (ProcessedContracts.TryGetValue(dataContract, out info)) - return (ContractCodeDomInfo)info; - return null; - } - - internal void SetContractCodeDomInfo(DataContract dataContract, ContractCodeDomInfo info) - { - ProcessedContracts.Add(dataContract, info); - } -#endif } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs index 251e896e86488..4c85f38678447 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs @@ -9,6 +9,7 @@ using System.Xml; using System.Security; using System.Diagnostics.CodeAnalysis; +using System.Diagnostics; namespace System.Runtime.Serialization { @@ -98,9 +99,7 @@ internal PrimitiveDataContract? MemberPrimitiveContract { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get - { - return _helper.MemberPrimitiveContract; - } + { return _helper.MemberPrimitiveContract; } } public bool HasConflictingNameAndType @@ -137,6 +136,7 @@ private sealed class CriticalHelper private bool _isNullable; private bool _isGetOnlyCollection; private readonly MemberInfo _memberInfo; + private Type? _memberType; private bool _hasConflictingNameAndType; private DataMember? _conflictingMember; @@ -188,8 +188,6 @@ internal bool IsGetOnlyCollection set { _isGetOnlyCollection = value; } } - private Type? _memberType; - internal Type MemberType { get @@ -216,7 +214,7 @@ internal DataContract MemberTypeContract { if (this.IsGetOnlyCollection) { - _memberTypeContract = DataContract.GetGetOnlyCollectionDataContract(DataContract.GetId(MemberType.TypeHandle), MemberType.TypeHandle, MemberType, SerializationMode.SharedContract); + _memberTypeContract = DataContract.GetGetOnlyCollectionDataContract(DataContract.GetId(MemberType.TypeHandle), MemberType.TypeHandle, MemberType); } else { @@ -310,5 +308,25 @@ internal bool RequiresMemberAccessForSet() } return false; } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal bool Equals(object? other, HashSet checkedContracts) + { + if (this == other) + return true; + + if (other is DataMember dataMember) + { + // Note: comparison does not use Order hint since it influences element order but does not specify exact order + bool thisIsNullable = (MemberTypeContract == null) ? false : !MemberTypeContract.IsValueType; + bool dataMemberIsNullable = (dataMember.MemberTypeContract == null) ? false : !dataMember.MemberTypeContract.IsValueType; + return (Name == dataMember.Name + && (IsNullable || thisIsNullable) == (dataMember.IsNullable || dataMemberIsNullable) + && IsRequired == dataMember.IsRequired + && EmitDefaultValue == dataMember.EmitDefaultValue + && MemberTypeContract!.Equals(dataMember.MemberTypeContract, checkedContracts)); + } + return false; + } } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs index 148efe5f81fc8..ab26f6195ee9b 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs @@ -12,6 +12,7 @@ using System.Security; using System.Linq; using System.Diagnostics.CodeAnalysis; +using System.Diagnostics; namespace System.Runtime.Serialization { @@ -19,13 +20,18 @@ internal sealed class EnumDataContract : DataContract { private readonly EnumDataContractCriticalHelper _helper; - public XmlQualifiedName? BaseContractName { get; set; } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal EnumDataContract(Type type) : base(new EnumDataContractCriticalHelper(type)) { _helper = (base.Helper as EnumDataContractCriticalHelper)!; } + + public XmlQualifiedName BaseContractName + { + get => _helper.BaseContractName; + set => _helper.BaseContractName = value; + } + public List Members { get @@ -51,14 +57,12 @@ public bool IsULong { get { return _helper.IsULong; } - set { _helper.IsULong = value; } } public XmlDictionaryString[]? ChildElementNames { get { return _helper.ChildElementNames; } - set { _helper.ChildElementNames = value; } } internal override bool CanContainReferences @@ -71,6 +75,7 @@ private sealed class EnumDataContractCriticalHelper : DataContract.DataContractC private static readonly Dictionary s_typeToName = new Dictionary(); private static readonly Dictionary s_nameToType = new Dictionary(); + private XmlQualifiedName _baseContractName; private List _members; private List? _values; private bool _isULong; @@ -97,6 +102,22 @@ internal static void Add(Type type, string localName) s_nameToType.Add(stableName, type); } + internal static XmlQualifiedName GetBaseContractName(Type type) + { + XmlQualifiedName? retVal; + s_typeToName.TryGetValue(type, out retVal); + + Debug.Assert(retVal != null); // Enums can only have certain base types. We shouldn't come up empty here. + return retVal; + } + + internal static Type? GetBaseType(XmlQualifiedName baseContractName) + { + Type? retVal; + s_nameToType.TryGetValue(baseContractName, out retVal); + return retVal; + } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal EnumDataContractCriticalHelper( [DynamicallyAccessedMembers(ClassDataContract.DataContractPreserveMemberTypes)] @@ -104,6 +125,7 @@ internal EnumDataContractCriticalHelper( { this.StableName = DataContract.GetStableName(type, out _hasDataContract); Type baseType = Enum.GetUnderlyingType(type); + _baseContractName = GetBaseContractName(baseType); ImportBaseType(baseType); IsFlags = type.IsDefined(Globals.TypeOfFlagsAttribute, false); ImportDataMembers(); @@ -128,6 +150,22 @@ internal EnumDataContractCriticalHelper( } } } + + internal XmlQualifiedName BaseContractName + { + get { return _baseContractName; } + + set + { + _baseContractName = value; + Type? baseType = GetBaseType(_baseContractName); + if (baseType == null) + ThrowInvalidDataContractException( + SR.Format(SR.InvalidEnumBaseType, value.Name, value.Namespace, StableName.Name, StableName.Namespace)); + ImportBaseType(baseType); + } + } + internal List Members { get { return _members; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExportOptions.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExportOptions.cs index 435415d1ca565..88a8a1c148934 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExportOptions.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExportOptions.cs @@ -8,20 +8,6 @@ namespace System.Runtime.Serialization public class ExportOptions { private Collection? _knownTypes; -#if SUPPORT_SURROGATE - private IDataContractSurrogate? _dataContractSurrogate; - - public IDataContractSurrogate? DataContractSurrogate - { - get { return _dataContractSurrogate; } - set { _dataContractSurrogate = value; } - } - - internal IDataContractSurrogate? GetSurrogate() - { - return _dataContractSurrogate; - } -#endif public Collection KnownTypes => _knownTypes ??= new Collection(); } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExtensionDataObject.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExtensionDataObject.cs index be5723fb3b09a..6004b41c84e3c 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExtensionDataObject.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExtensionDataObject.cs @@ -36,7 +36,7 @@ public ExtensionDataMember(string name, string ns) public string Name { get; } - public string? Namespace { get; } + public string Namespace { get; } public IDataNode? Value { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExtensionDataReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExtensionDataReader.cs index df8b296a45713..08c7d552ec5c9 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExtensionDataReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExtensionDataReader.cs @@ -4,6 +4,9 @@ using System.Xml; using System.Collections; using System.Diagnostics.CodeAnalysis; +using System.Collections.Generic; +using System.Globalization; +using System.Diagnostics; namespace System.Runtime.Serialization { @@ -27,7 +30,7 @@ private enum ExtensionDataNodeType private ElementData? _nextElement; private ReadState _readState = ReadState.Initial; - private readonly ExtensionDataNodeType _internalNodeType; + private ExtensionDataNodeType _internalNodeType; private XmlNodeType _nodeType; private int _depth; private string? _localName; @@ -37,11 +40,12 @@ private enum ExtensionDataNodeType private int _attributeCount; private int _attributeIndex; + private Hashtable _cache = new Hashtable(); + private XmlNodeReader? _xmlNodeReader; + private Queue? _deserializedDataNodes; + private static readonly object s_prefixLock = new object(); -#pragma warning disable 0649 - private readonly XmlNodeReader? _xmlNodeReader; -#pragma warning restore 0649 private readonly XmlObjectSerializerReadContext _context; @@ -62,6 +66,16 @@ internal ExtensionDataReader(XmlObjectSerializerReadContext context) _context = context; } + internal void SetDeserializedValue(object? obj) + { + IDataNode? deserializedDataNode = (_deserializedDataNodes == null || _deserializedDataNodes.Count == 0) ? null : _deserializedDataNodes.Dequeue(); + if (deserializedDataNode != null && !(obj is IDataNode)) + { + deserializedDataNode.Value = obj; + deserializedDataNode.IsFinalValue = true; + } + } + internal IDataNode? GetCurrentNode() { IDataNode? retVal = _element!.dataNode; @@ -69,6 +83,14 @@ internal ExtensionDataReader(XmlObjectSerializerReadContext context) return retVal; } + internal void SetDataNode(IDataNode dataNode, string? name, string? ns) + { + SetNextElement(dataNode, name, ns, null); + _element = _nextElement; + _nextElement = null; + SetElement(); + } + internal void Reset() { _localName = null; @@ -427,11 +449,295 @@ public override bool ReadAttributeValue() return false; } - private static void MoveNext(IDataNode? dataNode) + private void MoveNext(IDataNode? dataNode) + { + switch (_internalNodeType) + { + case ExtensionDataNodeType.Text: + case ExtensionDataNodeType.ReferencedElement: + case ExtensionDataNodeType.NullElement: + _internalNodeType = ExtensionDataNodeType.EndElement; + return; + default: + Type? dataNodeType = dataNode?.DataType; + if (dataNodeType == Globals.TypeOfClassDataNode) + MoveNextInClass((ClassDataNode)dataNode!); + else if (dataNodeType == Globals.TypeOfCollectionDataNode) + MoveNextInCollection((CollectionDataNode)dataNode!); + else if (dataNodeType == Globals.TypeOfISerializableDataNode) + MoveNextInISerializable((ISerializableDataNode)dataNode!); + else if (dataNodeType == Globals.TypeOfXmlDataNode) + MoveNextInXml((XmlDataNode)dataNode!); + else if (dataNode?.Value != null) + MoveToDeserializedObject(dataNode!); + else + { + Fx.Assert("Encountered invalid data node when deserializing unknown data"); + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException(SR.Format(SR.InvalidStateInExtensionDataReader))); + } + break; + } + } + + private void SetNextElement(IDataNode? node, string? name, string? ns, string? prefix) + { + _internalNodeType = ExtensionDataNodeType.Element; + _nextElement = GetNextElement(); + _nextElement.localName = name; + _nextElement.ns = ns; + _nextElement.prefix = prefix; + if (node == null) + { + _nextElement.attributeCount = 0; + _nextElement.AddAttribute(Globals.XsiPrefix, Globals.SchemaInstanceNamespace, Globals.XsiNilLocalName, Globals.True); + _internalNodeType = ExtensionDataNodeType.NullElement; + } + else if (!CheckIfNodeHandled(node)) + { + AddDeserializedDataNode(node); + node.GetData(_nextElement); + if (node is XmlDataNode xdn) + MoveNextInXml(xdn); + } + } + + private void AddDeserializedDataNode(IDataNode node) + { + if (node.Id != Globals.NewObjectId && (node.Value == null || !node.IsFinalValue)) + { + if (_deserializedDataNodes == null) + _deserializedDataNodes = new Queue(); + _deserializedDataNodes.Enqueue(node); + } + } + + private bool CheckIfNodeHandled(IDataNode node) + { + bool handled = false; + if (node.Id != Globals.NewObjectId) + { + handled = (_cache[node] != null); + if (handled) + { + if (_nextElement == null) + _nextElement = GetNextElement(); + _nextElement.attributeCount = 0; + _nextElement.AddAttribute(Globals.SerPrefix, Globals.SerializationNamespace, Globals.RefLocalName, node.Id.ToString(NumberFormatInfo.InvariantInfo)); + _nextElement.AddAttribute(Globals.XsiPrefix, Globals.SchemaInstanceNamespace, Globals.XsiNilLocalName, Globals.True); + _internalNodeType = ExtensionDataNodeType.ReferencedElement; + } + else + { + _cache.Add(node, node); + } + } + return handled; + } + + private void MoveNextInClass(ClassDataNode dataNode) + { + // Two frames above here in Read(), _element is asserted not null. + Fx.Assert(_element != null, ""); + if (dataNode.Members != null && _element.childElementIndex < dataNode.Members.Count) + { + if (_element.childElementIndex == 0) + _context.IncrementItemCount(-dataNode.Members.Count); + + ExtensionDataMember member = dataNode.Members[_element.childElementIndex++]; + SetNextElement(member.Value, member.Name, member.Namespace, GetPrefix(member.Namespace)); + } + else + { + _internalNodeType = ExtensionDataNodeType.EndElement; + _element.childElementIndex = 0; + } + } + + private void MoveNextInCollection(CollectionDataNode dataNode) { - throw NotImplemented.ByDesign; + // Two frames above here in Read(), _element is asserted not null. + Fx.Assert(_element != null, ""); + if (dataNode.Items != null && _element.childElementIndex < dataNode.Items.Count) + { + if (_element.childElementIndex == 0) + _context.IncrementItemCount(-dataNode.Items.Count); + + IDataNode? item = dataNode.Items[_element.childElementIndex++]; + SetNextElement(item, dataNode.ItemName, dataNode.ItemNamespace, GetPrefix(dataNode.ItemNamespace)); + } + else + { + _internalNodeType = ExtensionDataNodeType.EndElement; + _element.childElementIndex = 0; + } } + private void MoveNextInISerializable(ISerializableDataNode dataNode) + { + // Two frames above here in Read(), _element is asserted not null. + Fx.Assert(_element != null, ""); + if (dataNode.Members != null && _element.childElementIndex < dataNode.Members.Count) + { + if (_element.childElementIndex == 0) + _context.IncrementItemCount(-dataNode.Members.Count); + + ISerializableDataMember member = dataNode.Members[_element.childElementIndex++]; + SetNextElement(member.Value, member.Name, string.Empty, string.Empty); + } + else + { + _internalNodeType = ExtensionDataNodeType.EndElement; + _element.childElementIndex = 0; + } + } + + private void MoveNextInXml(XmlDataNode dataNode) + { + if (IsXmlDataNode) + { + _xmlNodeReader.Read(); + if (_xmlNodeReader.Depth == 0) + { + _internalNodeType = ExtensionDataNodeType.EndElement; + _xmlNodeReader = null; + } + } + else + { + _internalNodeType = ExtensionDataNodeType.Xml; + if (_element == null) + _element = _nextElement; + else + PushElement(); + + Debug.Assert(dataNode.OwnerDocument != null); // OwnerDocument is always set on initialized dataNodes + + XmlElement wrapperElement = XmlObjectSerializerReadContext.CreateWrapperXmlElement(dataNode.OwnerDocument, + dataNode.XmlAttributes, dataNode.XmlChildNodes, _element?.prefix, _element?.localName, _element?.ns); + if (_element != null) + { + for (int i = 0; i < _element.attributeCount; i++) + { + AttributeData a = _element.attributes![i]; + XmlAttribute xmlAttr = dataNode.OwnerDocument.CreateAttribute(a.prefix, a.localName!, a.ns); + xmlAttr.Value = a.value; + wrapperElement.Attributes.Append(xmlAttr); + } + } + _xmlNodeReader = new XmlNodeReader(wrapperElement); + _xmlNodeReader.Read(); + } + } + + private void MoveToDeserializedObject(IDataNode dataNode) + { + Type type = dataNode.DataType; + bool isTypedNode = true; + if (type == Globals.TypeOfObject && dataNode.Value != null) + { + type = dataNode.Value.GetType(); + if (type == Globals.TypeOfObject) + { + _internalNodeType = ExtensionDataNodeType.EndElement; + return; + } + isTypedNode = false; + } + + if (!MoveToText(type, dataNode, isTypedNode)) + { + if (dataNode.IsFinalValue) + { + _internalNodeType = ExtensionDataNodeType.EndElement; + } + else + { + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.Format(SR.InvalidDataNode, DataContract.GetClrTypeFullName(type)))); + } + } + } + + private bool MoveToText(Type type, IDataNode dataNode, bool isTypedNode) + { + Fx.Assert(dataNode.Value != null, ""); + + bool handled = true; + switch (Type.GetTypeCode(type)) + { + case TypeCode.Boolean: + _value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (bool)dataNode.Value); + break; + case TypeCode.Char: + _value = XmlConvert.ToString((int)(isTypedNode ? ((DataNode)dataNode).GetValue() : (char)dataNode.Value)); + break; + case TypeCode.Byte: + _value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (byte)dataNode.Value); + break; + case TypeCode.Int16: + _value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (short)dataNode.Value); + break; + case TypeCode.Int32: + _value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (int)dataNode.Value); + break; + case TypeCode.Int64: + _value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (long)dataNode.Value); + break; + case TypeCode.Single: + _value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (float)dataNode.Value); + break; + case TypeCode.Double: + _value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (double)dataNode.Value); + break; + case TypeCode.Decimal: + _value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (decimal)dataNode.Value); + break; + case TypeCode.DateTime: + DateTime dateTime = isTypedNode ? ((DataNode)dataNode).GetValue() : (DateTime)dataNode.Value; + _value = dateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffffffK", DateTimeFormatInfo.InvariantInfo); + break; + case TypeCode.String: + _value = isTypedNode ? ((DataNode)dataNode).GetValue() : (string?)dataNode.Value; + break; + case TypeCode.SByte: + _value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (sbyte)dataNode.Value); + break; + case TypeCode.UInt16: + _value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (ushort)dataNode.Value); + break; + case TypeCode.UInt32: + _value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (uint)dataNode.Value); + break; + case TypeCode.UInt64: + _value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (ulong)dataNode.Value); + break; + case TypeCode.Object: + default: + if (type == Globals.TypeOfByteArray) + { + byte[]? bytes = isTypedNode ? ((DataNode)dataNode).GetValue() : (byte[])dataNode.Value; + _value = (bytes == null) ? string.Empty : Convert.ToBase64String(bytes); + } + else if (type == Globals.TypeOfTimeSpan) + _value = XmlConvert.ToString(isTypedNode ? ((DataNode)dataNode).GetValue() : (TimeSpan)dataNode.Value); + else if (type == Globals.TypeOfGuid) + { + Guid guid = isTypedNode ? ((DataNode)dataNode).GetValue() : (Guid)dataNode.Value; + _value = guid.ToString(); + } + else if (type == Globals.TypeOfUri) + { + Uri uri = isTypedNode ? ((DataNode)dataNode).GetValue() : (Uri)dataNode.Value; + _value = uri.GetComponents(UriComponents.SerializationInfoString, UriFormat.UriEscaped); + } + else + handled = false; + break; + } + + if (handled) + _internalNodeType = ExtensionDataNodeType.Text; + return handled; + } private void PushElement() { GrowElementsIfNeeded(); @@ -477,11 +783,11 @@ private void GrowElementsIfNeeded() } } - private ElementData? GetNextElement() + private ElementData GetNextElement() { int nextDepth = _depth + 1; return (_elements == null || _elements.Length <= nextDepth || _elements[nextDepth] == null) - ? new ElementData() : _elements[nextDepth]; + ? new ElementData() : _elements[nextDepth]!; } internal static string GetPrefix(string? ns) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs index 8f5bd20805c9d..e768ceba55532 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs @@ -24,7 +24,7 @@ internal int ParameterPosition { return _helper.ParameterPosition; } } - public override bool IsBuiltInDataContract + internal override bool IsBuiltInDataContract { get { @@ -51,10 +51,5 @@ internal int ParameterPosition get { return _parameterPosition; } } } - - internal DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) - { - return paramContracts[ParameterPosition]; - } } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs index bcdf77aa6aa02..9ed56ce418144 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.ComponentModel; using System.Collections; using System.Collections.Generic; using System.Diagnostics; @@ -227,6 +226,10 @@ internal static partial class Globals internal static Type TypeOfNullable => s_typeOfNullable ??= typeof(Nullable<>); + private static Type? s_typeOfReflectionPointer; + internal static Type TypeOfReflectionPointer => + s_typeOfReflectionPointer ??= typeof(System.Reflection.Pointer); + private static Type? s_typeOfIDictionaryGeneric; internal static Type TypeOfIDictionaryGeneric => s_typeOfIDictionaryGeneric ??= typeof(IDictionary<,>); @@ -271,10 +274,6 @@ internal static partial class Globals internal static Type TypeOfKeyValuePair => s_typeOfKeyValuePair ??= typeof(KeyValuePair<,>); - private static Type? s_typeOfKeyValuePairAdapter; - internal static Type TypeOfKeyValuePairAdapter => - s_typeOfKeyValuePairAdapter ??= typeof(KeyValuePairAdapter<,>); - private static Type? s_typeOfKeyValue; internal static Type TypeOfKeyValue => s_typeOfKeyValue ??= typeof(KeyValue<,>); @@ -318,18 +317,6 @@ internal static Type TypeOfHashtable internal static Uri DataContractXsdBaseNamespaceUri => s_dataContractXsdBaseNamespaceUri ??= new Uri(DataContractXsdBaseNamespace); - private static readonly Type? s_typeOfScriptObject; - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static ClassDataContract CreateScriptObjectClassDataContract() - { - Debug.Assert(s_typeOfScriptObject != null); - return new ClassDataContract(s_typeOfScriptObject); - } - - internal static bool TypeOfScriptObject_IsAssignableFrom(Type type) => - s_typeOfScriptObject != null && s_typeOfScriptObject.IsAssignableFrom(type); - public const bool DefaultIsRequired = false; public const bool DefaultEmitDefaultValue = true; public const int DefaultOrder = 0; @@ -341,6 +328,10 @@ internal static bool TypeOfScriptObject_IsAssignableFrom(Type type) => public const string FullSRSInternalsVisiblePattern = @"^[\s]*System\.Runtime\.Serialization[\s]*,[\s]*PublicKey[\s]*=[\s]*(?i:00240000048000009400000006020000002400005253413100040000010001008d56c76f9e8649383049f383c44be0ec204181822a6c31cf5eb7ef486944d032188ea1d3920763712ccb12d75fb77e9811149e6148e5d32fbaab37611c1878ddc19e20ef135d0cb2cff2bfec3d115810c3d9069638fe4be215dbf795861920e5ab6f7db2e2ceef136ac23d5dd2bf031700aec232f6c6b1c785b4305c123b37ab)[\s]*$"; [RegexGenerator(FullSRSInternalsVisiblePattern)] public static partial Regex FullSRSInternalsVisibleRegex(); + public const char SpaceChar = ' '; + public const char OpenBracketChar = '['; + public const char CloseBracketChar = ']'; + public const char CommaChar = ','; public const string Space = " "; public const string XsiPrefix = "i"; public const string XsdPrefix = "x"; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs index beeb3faa7976d..4c033708d591b 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs @@ -32,7 +32,7 @@ public sealed class DataContractJsonSerializer : XmlObjectSerializer private XmlDictionaryString? _rootName; private bool _rootNameRequiresMapping; private Type _rootType; - + private ISerializationSurrogateProvider? _serializationSurrogateProvider; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] public DataContractJsonSerializer(Type type) @@ -92,6 +92,12 @@ internal DataContractJsonSerializer(Type type, Initialize(type, rootName, knownTypes, maxItemsInObjectGraph, ignoreExtensionDataObject, emitTypeInformation, false, null, false); } + internal ISerializationSurrogateProvider? SerializationSurrogateProvider + { + get { return _serializationSurrogateProvider; } + set { _serializationSurrogateProvider = value; } + } + public bool IgnoreExtensionDataObject { get { return _ignoreExtensionDataObject; } @@ -451,6 +457,11 @@ internal override void InternalWriteObjectContent(XmlWriterDelegator writer, obj Type declaredType = contract.UnderlyingType; Type graphType = (graph == null) ? declaredType : graph.GetType(); + if (_serializationSurrogateProvider != null) + { + graph = DataContractSerializer.SurrogateToDataContractType(_serializationSurrogateProvider, graph, declaredType, ref graphType); + } + if (graph == null) { WriteJsonNull(writer); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializerExtensions.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializerExtensions.cs new file mode 100644 index 0000000000000..0c52dee3789a8 --- /dev/null +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializerExtensions.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Runtime.Serialization.Json +{ + public static class DataContractJsonSerializerExtensions + { + public static ISerializationSurrogateProvider? GetSerializationSurrogateProvider(this DataContractJsonSerializer serializer) + { + return serializer.SerializationSurrogateProvider; + } + + public static void SetSerializationSurrogateProvider(this DataContractJsonSerializer serializer, ISerializationSurrogateProvider? provider) + { + serializer.SerializationSurrogateProvider = provider; + } + } +} diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs index ceee570b7475e..a835648fb74a0 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs @@ -109,12 +109,6 @@ public JsonFormatClassReaderDelegate GenerateClassReader(ClassDataContract class _ilg.Call(XmlFormatGeneratorStatics.GetMemoryStreamMethod); _ilg.ConvertValue(Globals.TypeOfMemoryStream, _ilg.CurrentMethod.ReturnType); } - //Copy the KeyValuePairAdapter to a KeyValuePair. - else if (classContract.IsKeyValuePairAdapter) - { - _ilg.Call(classContract.GetKeyValuePairMethodInfo); - _ilg.ConvertValue(Globals.TypeOfKeyValuePair.MakeGenericType(classContract.KeyValuePairGenericArguments), _ilg.CurrentMethod.ReturnType); - } else { _ilg.ConvertValue(_objectLocal.LocalType, _ilg.CurrentMethod.ReturnType); @@ -174,7 +168,7 @@ private CodeGenerator GenerateCollectionReaderHelper(CollectionDataContract coll private static void BeginMethod(CodeGenerator ilg, string methodName, Type delegateType, bool allowPrivateMemberAccess) { - MethodInfo signature = JsonFormatWriterGenerator.GetInvokeMethod(delegateType); + MethodInfo signature = CodeGenerator.GetInvokeMethod(delegateType); ParameterInfo[] parameters = signature.GetParameters(); Type[] paramTypes = new Type[parameters.Length]; for (int i = 0; i < parameters.Length; i++) @@ -906,7 +900,7 @@ private bool TryReadPrimitiveArray(Type itemType) return false; string? readArrayMethod = null; - switch (itemType.GetTypeCode()) + switch (Type.GetTypeCode(itemType)) { case TypeCode.Boolean: readArrayMethod = "TryReadBooleanArray"; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs index afe02b062b6a7..9a7797a9882f4 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs @@ -36,14 +36,6 @@ internal JsonFormatCollectionWriterDelegate GenerateCollectionWriter(CollectionD return _helper.GenerateCollectionWriter(collectionContract); } - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", - Justification = "The trimmer will never remove the Invoke method from delegates.")] - internal static MethodInfo GetInvokeMethod(Type delegateType) - { - Debug.Assert(typeof(Delegate).IsAssignableFrom(delegateType)); - return delegateType.GetMethod("Invoke")!; - } - private sealed class CriticalHelper { private CodeGenerator _ilg = null!; // initialized in GenerateXXXWriter @@ -114,7 +106,7 @@ internal JsonFormatCollectionWriterDelegate GenerateCollectionWriter(CollectionD private static void BeginMethod(CodeGenerator ilg, string methodName, Type delegateType, bool allowPrivateMemberAccess) { - MethodInfo signature = GetInvokeMethod(delegateType); + MethodInfo signature = CodeGenerator.GetInvokeMethod(delegateType); ParameterInfo[] parameters = signature.GetParameters(); Type[] paramTypes = new Type[parameters.Length]; for (int i = 0; i < parameters.Length; i++) @@ -149,13 +141,6 @@ private void InitArgs(Type objType) _ilg.ConvertValue(objectArg.ArgType, Globals.TypeOfMemoryStream); _ilg.Call(XmlFormatGeneratorStatics.GetMemoryStreamAdapterMethod); } - //Copy the KeyValuePair to a KeyValuePairAdapter. - else if (objType.IsGenericType && objType.GetGenericTypeDefinition() == Globals.TypeOfKeyValuePairAdapter) - { - ClassDataContract dc = (ClassDataContract)DataContract.GetDataContract(objType); - _ilg.ConvertValue(objectArg.ArgType, Globals.TypeOfKeyValuePair.MakeGenericType(dc.KeyValuePairGenericArguments!)); - _ilg.New(dc.KeyValuePairAdapterConstructorInfo!); - } else { _ilg.ConvertValue(objectArg.ArgType, objType); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatWriter.cs index 74fbefe525979..c65752936b5ce 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatWriter.cs @@ -146,7 +146,7 @@ private static bool ReflectionTryWritePrimitiveArray(JsonWriterDelegator jsonWri XmlDictionaryString? itemNamespace = null; - switch (itemType.GetTypeCode()) + switch (Type.GetTypeCode(itemType)) { case TypeCode.Boolean: ReflectionWriteArrayAttribute(jsonWriter); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs index 8cd388f9601b0..2179116d3c4f9 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs @@ -39,7 +39,7 @@ protected PrimitiveDataContract( internal abstract string WriteMethodName { get; } internal abstract string ReadMethodName { get; } - public override XmlDictionaryString? TopLevelElementNamespace + internal override XmlDictionaryString? TopLevelElementNamespace { get { return DictionaryGlobals.SerializationNamespace; } @@ -52,7 +52,7 @@ public override XmlDictionaryString? TopLevelElementNamespace internal override bool IsPrimitive => true; - public override bool IsBuiltInDataContract => true; + internal override bool IsBuiltInDataContract => true; internal MethodInfo XmlFormatWriterMethod { @@ -115,6 +115,18 @@ protected static bool TryReadNullAtTopLevel(XmlReaderDelegator reader) return false; } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal override bool Equals(object? other, HashSet checkedContracts) + { + if (other is PrimitiveDataContract) + { + Type thisType = this.GetType(); + Type otherType = other.GetType(); + return (thisType.Equals(otherType) || thisType.IsSubclassOf(otherType) || otherType.IsSubclassOf(thisType)); + } + return false; + } + private sealed class PrimitiveDataContractCriticalHelper : DataContract.DataContractCriticalHelper { private MethodInfo? _xmlFormatWriterMethod; @@ -842,7 +854,7 @@ public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObj public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { object obj; - if (XmlReaderDelegator.IsEmptyElement) + if (reader.IsEmptyElement) { reader.Skip(); obj = new object(); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionClassWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionClassWriter.cs index 3cc3c97a7261e..a8df2b1d0ca3f 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionClassWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionClassWriter.cs @@ -155,11 +155,6 @@ private static object ResolveAdapterType(object obj, ClassDataContract classCont { obj = MemoryStreamAdapter.GetMemoryStreamAdapter((MemoryStream)obj); } - else if (type.IsGenericType && type.GetGenericTypeDefinition() == Globals.TypeOfKeyValuePair) - { - obj = classContract.KeyValuePairAdapterConstructorInfo!.Invoke(new object[] { obj }); - } - return obj; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs index b28f41784478c..319fb0fdbfb37 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs @@ -426,11 +426,6 @@ private static object ResolveAdapterObject(object obj, ClassDataContract classCo { obj = MemoryStreamAdapter.GetMemoryStream((MemoryStreamAdapter)obj); } - else if (obj is IKeyValuePairAdapter) - { - obj = classContract.GetKeyValuePairMethodInfo!.Invoke(obj, Array.Empty())!; - } - return obj; } @@ -612,7 +607,7 @@ private static bool ReflectionTryReadPrimitiveArray(XmlReaderDelegator xmlReader if (primitiveContract == null) return false; - switch (itemType.GetTypeCode()) + switch (Type.GetTypeCode(itemType)) { case TypeCode.Boolean: { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatWriter.cs index dc70a9cb4ae83..35916664cae7b 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatWriter.cs @@ -95,7 +95,7 @@ private static bool ReflectionTryWritePrimitiveArray(XmlWriterDelegator xmlWrite if (primitiveContract == null) return false; - switch (itemType.GetTypeCode()) + switch (Type.GetTypeCode(itemType)) { case TypeCode.Boolean: xmlWriter.WriteBooleanArray((bool[])obj, collectionItemName, itemNamespace); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs index 1c76e5760047e..625b5a197a025 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs @@ -400,8 +400,6 @@ private void ExportEnumDataContract(EnumDataContract enumDataContract, XmlSchema { XmlSchemaSimpleType type = new XmlSchemaSimpleType(); type.Name = enumDataContract.StableName.Name; - // https://github.com/dotnet/runtime/issues/41448 - enumDataContract.BaseContractName is always null, but this method is not reachable - Debug.Assert(enumDataContract.BaseContractName != null, "BaseContractName is always null, but this method is not reachable. Suppressing compiler error."); XmlElement? actualTypeElement = (enumDataContract.BaseContractName == DefaultEnumBaseTypeName) ? null : ExportActualType(enumDataContract.BaseContractName); type.Annotation = GetSchemaAnnotation(actualTypeElement, ExportSurrogateData(enumDataContract)); schema.Items.Add(type); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs index da820ba98babb..8d2698ede2620 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs @@ -11,7 +11,6 @@ namespace System.Runtime.Serialization { internal static class SchemaHelper { - internal static bool NamespacesEqual(string? ns1, string? ns2) { if (ns1 == null || ns1.Length == 0) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SerializationMode.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SerializationMode.cs deleted file mode 100644 index 142ae2c009638..0000000000000 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SerializationMode.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Runtime.Serialization -{ - internal enum SerializationMode - { - SharedContract - } -} diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SpecialTypeDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SpecialTypeDataContract.cs index 010871e02e13a..b3c315d0943a0 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SpecialTypeDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SpecialTypeDataContract.cs @@ -18,7 +18,7 @@ public SpecialTypeDataContract( _helper = (base.Helper as SpecialTypeDataContractCriticalHelper)!; } - public override bool IsBuiltInDataContract => true; + internal override bool IsBuiltInDataContract => true; private sealed class SpecialTypeDataContractCriticalHelper : DataContract.DataContractCriticalHelper { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/TypeCode.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/TypeCode.cs deleted file mode 100644 index f9b2b9d4ca526..0000000000000 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/TypeCode.cs +++ /dev/null @@ -1,80 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Runtime.Serialization -{ - internal static class TypeExtensionMethods - { - public static TypeCode GetTypeCode(this Type type) - { - if (type == null) - { - return TypeCode.Empty; - } - else if (type == typeof(bool)) - { - return TypeCode.Boolean; - } - else if (type == typeof(char)) - { - return TypeCode.Char; - } - else if (type == typeof(sbyte)) - { - return TypeCode.SByte; - } - else if (type == typeof(byte)) - { - return TypeCode.Byte; - } - else if (type == typeof(short)) - { - return TypeCode.Int16; - } - else if (type == typeof(ushort)) - { - return TypeCode.UInt16; - } - else if (type == typeof(int)) - { - return TypeCode.Int32; - } - else if (type == typeof(uint)) - { - return TypeCode.UInt32; - } - else if (type == typeof(long)) - { - return TypeCode.Int64; - } - else if (type == typeof(ulong)) - { - return TypeCode.UInt64; - } - else if (type == typeof(float)) - { - return TypeCode.Single; - } - else if (type == typeof(double)) - { - return TypeCode.Double; - } - else if (type == typeof(decimal)) - { - return TypeCode.Decimal; - } - else if (type == typeof(DateTime)) - { - return TypeCode.DateTime; - } - else if (type == typeof(string)) - { - return TypeCode.String; - } - else - { - return TypeCode.Object; - } - } - } -} diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs index 9ca8757798163..22bb9320f429c 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs @@ -27,7 +27,7 @@ internal XmlDataContract(Type type) : base(new XmlDataContractCriticalHelper(typ _helper = (base.Helper as XmlDataContractCriticalHelper)!; } - public override DataContractDictionary? KnownDataContracts + internal override DataContractDictionary? KnownDataContracts { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get @@ -50,7 +50,7 @@ internal bool IsAnonymous { return _helper.IsAnonymous; } } - public override bool HasRoot + internal override bool HasRoot { get { return _helper.HasRoot; } @@ -59,7 +59,7 @@ public override bool HasRoot { _helper.HasRoot = value; } } - public override XmlDictionaryString? TopLevelElementName + internal override XmlDictionaryString? TopLevelElementName { get { return _helper.TopLevelElementName; } @@ -68,7 +68,7 @@ public override XmlDictionaryString? TopLevelElementName { _helper.TopLevelElementName = value; } } - public override XmlDictionaryString? TopLevelElementNamespace + internal override XmlDictionaryString? TopLevelElementNamespace { get { return _helper.TopLevelElementNamespace; } @@ -83,6 +83,12 @@ internal bool IsTopLevelElementNullable set { _helper.IsTopLevelElementNullable = value; } } + internal bool IsTypeDefinedOnImport + { + get { return _helper.IsTypeDefinedOnImport; } + set { _helper.IsTypeDefinedOnImport = value; } + } + internal CreateXmlSerializableDelegate CreateXmlSerializableDelegate { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -113,7 +119,7 @@ internal CreateXmlSerializableDelegate CreateXmlSerializableDelegate internal override bool CanContainReferences => false; - public override bool IsBuiltInDataContract => UnderlyingType == Globals.TypeOfXmlElement || UnderlyingType == Globals.TypeOfXmlNodeArray; + internal override bool IsBuiltInDataContract => UnderlyingType == Globals.TypeOfXmlElement || UnderlyingType == Globals.TypeOfXmlNodeArray; private sealed class XmlDataContractCriticalHelper : DataContract.DataContractCriticalHelper { @@ -122,6 +128,7 @@ private sealed class XmlDataContractCriticalHelper : DataContract.DataContractCr private XmlDictionaryString? _topLevelElementName; private XmlDictionaryString? _topLevelElementNamespace; private bool _isTopLevelElementNullable; + private bool _isTypeDefinedOnImport; private bool _hasRoot; private CreateXmlSerializableDelegate? _createXmlSerializable; private XmlSchemaType? _xsdType; @@ -136,9 +143,11 @@ internal XmlDataContractCriticalHelper( if (type.IsDefined(Globals.TypeOfCollectionDataContractAttribute, false)) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.IXmlSerializableCannotHaveCollectionDataContract, DataContract.GetClrTypeFullName(type)))); bool hasRoot; + XmlSchemaType? xsdType; XmlQualifiedName stableName; - SchemaExporter.GetXmlTypeInfo(type, out stableName, out _, out hasRoot); + SchemaExporter.GetXmlTypeInfo(type, out stableName, out xsdType, out hasRoot); this.StableName = stableName; + this.XsdType = xsdType; this.HasRoot = hasRoot; XmlDictionary dictionary = new XmlDictionary(); this.Name = dictionary.Add(StableName.Name); @@ -234,6 +243,12 @@ internal bool IsTopLevelElementNullable set { _isTopLevelElementNullable = value; } } + internal bool IsTypeDefinedOnImport + { + get { return _isTypeDefinedOnImport; } + set { _isTypeDefinedOnImport = value; } + } + internal CreateXmlSerializableDelegate? CreateXmlSerializableDelegate { get { return _createXmlSerializable; } @@ -253,6 +268,16 @@ internal CreateXmlSerializableDelegate? CreateXmlSerializableDelegate return ctor; } + internal void SetTopLevelElementName(XmlQualifiedName? elementName) + { + if (elementName != null) + { + XmlDictionary dictionary = new XmlDictionary(); + TopLevelElementName = dictionary.Add(elementName.Name); + TopLevelElementNamespace = dictionary.Add(elementName.Namespace); + } + } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal CreateXmlSerializableDelegate GenerateCreateXmlSerializableDelegate() { @@ -370,6 +395,29 @@ internal IXmlSerializable ReflectionCreateXmlSerializable(Type type) } } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal override bool Equals(object? other, HashSet checkedContracts) + { + if (IsEqualOrChecked(other, checkedContracts)) + return true; + + if (other is XmlDataContract dataContract) + { + if (this.HasRoot != dataContract.HasRoot) + return false; + + if (this.IsAnonymous) + { + return dataContract.IsAnonymous; + } + else + { + return (StableName.Name == dataContract.StableName.Name && StableName.Namespace == dataContract.StableName.Namespace); + } + } + return false; + } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext? context) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatGeneratorStatics.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatGeneratorStatics.cs index 6791ee9e45f58..ba1a955f8044d 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatGeneratorStatics.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatGeneratorStatics.cs @@ -70,6 +70,9 @@ internal static MethodInfo WriteNamespaceDeclMethod private static PropertyInfo? s_extensionDataProperty; internal static PropertyInfo ExtensionDataProperty => s_extensionDataProperty ??= typeof(IExtensibleDataObject).GetProperty("ExtensionData")!; + private static MethodInfo? s_boxPointer; + internal static MethodInfo BoxPointer => s_boxPointer ??= typeof(Pointer).GetMethod("Box")!; + private static ConstructorInfo? s_dictionaryEnumeratorCtor; internal static ConstructorInfo DictionaryEnumeratorCtor { @@ -163,7 +166,7 @@ internal static MethodInfo GetUninitializedObjectMethod { if (s_getUninitializedObjectMethod == null) { - s_getUninitializedObjectMethod = typeof(XmlFormatReaderGenerator).GetMethod("UnsafeGetUninitializedObject", Globals.ScanAllMembers, new Type[] { typeof(int) }); + s_getUninitializedObjectMethod = typeof(XmlFormatReaderGenerator).GetMethod("UnsafeGetUninitializedObject", Globals.ScanAllMembers, new Type[] { typeof(int) })!; Debug.Assert(s_getUninitializedObjectMethod != null); } return s_getUninitializedObjectMethod; @@ -184,6 +187,9 @@ internal static MethodInfo OnDeserializationMethod } } + private static MethodInfo? s_unboxPointer; + internal static MethodInfo UnboxPointer => s_unboxPointer ??= typeof(Pointer).GetMethod("Unbox")!; + private static PropertyInfo? s_nodeTypeProperty; internal static PropertyInfo NodeTypeProperty { @@ -198,9 +204,11 @@ internal static PropertyInfo NodeTypeProperty } } + private static ConstructorInfo? s_serializationExceptionCtor; + internal static ConstructorInfo SerializationExceptionCtor => s_serializationExceptionCtor ??= typeof(SerializationException).GetConstructor(new Type[] { typeof(string) })!; + private static ConstructorInfo? s_extensionDataObjectCtor; - internal static ConstructorInfo ExtensionDataObjectCtor => s_extensionDataObjectCtor ??= - typeof(ExtensionDataObject).GetConstructor(Globals.ScanAllMembers, Type.EmptyTypes)!; + internal static ConstructorInfo ExtensionDataObjectCtor => s_extensionDataObjectCtor ??= typeof(ExtensionDataObject).GetConstructor(Globals.ScanAllMembers, Type.EmptyTypes)!; private static ConstructorInfo? s_hashtableCtor; internal static ConstructorInfo HashtableCtor @@ -529,9 +537,24 @@ internal static MethodInfo AddNewObjectWithIdMethod } } + private static MethodInfo? s_replaceDeserializedObjectMethod; + internal static MethodInfo ReplaceDeserializedObjectMethod + { + get + { + if (s_replaceDeserializedObjectMethod == null) + { + s_replaceDeserializedObjectMethod = typeof(XmlObjectSerializerReadContext).GetMethod("ReplaceDeserializedObject", Globals.ScanAllMembers); + Debug.Assert(s_replaceDeserializedObjectMethod != null); + } + return s_replaceDeserializedObjectMethod; + } + } + private static MethodInfo? s_getExistingObjectMethod; internal static MethodInfo GetExistingObjectMethod { + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get { if (s_getExistingObjectMethod == null) @@ -613,20 +636,6 @@ internal static MethodInfo GetArrayLengthMethod } } - private static MethodInfo? s_createSerializationExceptionMethod; - internal static MethodInfo CreateSerializationExceptionMethod - { - get - { - if (s_createSerializationExceptionMethod == null) - { - s_createSerializationExceptionMethod = typeof(XmlObjectSerializerReadContext).GetMethod("CreateSerializationException", Globals.ScanAllMembers, new Type[] { typeof(string) }); - Debug.Assert(s_createSerializationExceptionMethod != null); - } - return s_createSerializationExceptionMethod; - } - } - private static MethodInfo? s_readSerializationInfoMethod; internal static MethodInfo ReadSerializationInfoMethod { @@ -821,21 +830,6 @@ internal static MethodInfo WriteISerializableMethod } } - - private static MethodInfo? s_isMemberTypeSameAsMemberValue; - internal static MethodInfo IsMemberTypeSameAsMemberValue - { - get - { - if (s_isMemberTypeSameAsMemberValue == null) - { - s_isMemberTypeSameAsMemberValue = typeof(XmlObjectSerializerWriteContext).GetMethod("IsMemberTypeSameAsMemberValue", Globals.ScanAllMembers, new Type[] { typeof(object), typeof(Type) }); - Debug.Assert(s_isMemberTypeSameAsMemberValue != null); - } - return s_isMemberTypeSameAsMemberValue; - } - } - private static MethodInfo? s_writeExtensionDataMethod; internal static MethodInfo WriteExtensionDataMethod { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs index 50ed91a7377f4..e2bf095b7e236 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs @@ -118,14 +118,14 @@ public XmlFormatClassReaderDelegate GenerateClassReader(ClassDataContract classC ReadClass(classContract); } - _ = InvokeFactoryMethod(classContract, objectId); + bool isFactoryType = InvokeFactoryMethod(classContract, objectId); if (Globals.TypeOfIDeserializationCallback.IsAssignableFrom(classContract.UnderlyingType)) { _ilg.Call(_objectLocal, XmlFormatGeneratorStatics.OnDeserializationMethod, null); } InvokeOnDeserialized(classContract); - if (objectId == null) + if (objectId == null || !isFactoryType) { _ilg.Load(_objectLocal); @@ -145,12 +145,6 @@ public XmlFormatClassReaderDelegate GenerateClassReader(ClassDataContract classC _ilg.Call(XmlFormatGeneratorStatics.GetMemoryStreamMethod); _ilg.ConvertValue(Globals.TypeOfMemoryStream, _ilg.CurrentMethod.ReturnType); } - //Copy the KeyValuePairAdapter to a KeyValuePair. - else if (classContract.IsKeyValuePairAdapter) - { - _ilg.Call(classContract.GetKeyValuePairMethodInfo); - _ilg.ConvertValue(Globals.TypeOfKeyValuePair.MakeGenericType(classContract.KeyValuePairGenericArguments), _ilg.CurrentMethod.ReturnType); - } else { _ilg.ConvertValue(_objectLocal.LocalType, _ilg.CurrentMethod.ReturnType); @@ -384,9 +378,16 @@ private void ReadMembers(ClassDataContract classContract, LocalBuilder? extensio _ilg.Call(_contextArg, XmlFormatGeneratorStatics.GetMemberIndexWithRequiredMembersMethod, _xmlReaderArg, _memberNamesArg, _memberNamespacesArg, memberIndexLocal, requiredIndexLocal, extensionDataLocal); else _ilg.Call(_contextArg, XmlFormatGeneratorStatics.GetMemberIndexMethod, _xmlReaderArg, _memberNamesArg, _memberNamespacesArg, memberIndexLocal, extensionDataLocal); - Label[] memberLabels = _ilg.Switch(memberCount); - ReadMembers(classContract, requiredMembers, memberLabels, memberIndexLocal, requiredIndexLocal); - _ilg.EndSwitch(); + if (memberCount > 0) + { + Label[] memberLabels = _ilg.Switch(memberCount); + ReadMembers(classContract, requiredMembers, memberLabels, memberIndexLocal, requiredIndexLocal); + _ilg.EndSwitch(); + } + else + { + _ilg.Pop(); + } _ilg.EndFor(); if (hasRequiredMembers) { @@ -580,14 +581,18 @@ private void InternalDeserialize(LocalBuilder value, Type type, string name, str { _ilg.Load(_contextArg); _ilg.Load(_xmlReaderArg); - Type declaredType = type; + Type declaredType = type.IsPointer ? Globals.TypeOfReflectionPointer : type; _ilg.Load(DataContract.GetId(declaredType.TypeHandle)); _ilg.Ldtoken(declaredType); _ilg.Load(name); _ilg.Load(ns); _ilg.Call(XmlFormatGeneratorStatics.InternalDeserializeMethod); - _ilg.ConvertValue(Globals.TypeOfObject, type); + if (type.IsPointer) + _ilg.Call(XmlFormatGeneratorStatics.UnboxPointer); + else + _ilg.ConvertValue(Globals.TypeOfObject, type); + _ilg.Stloc(value); } @@ -821,7 +826,7 @@ private bool TryReadPrimitiveArray(Type type, Type itemType, LocalBuilder size) return false; string? readArrayMethod = null; - switch (itemType.GetTypeCode()) + switch (Type.GetTypeCode(itemType)) { case TypeCode.Boolean: readArrayMethod = "TryReadBooleanArray"; @@ -953,19 +958,15 @@ private void ThrowUnexpectedStateException(XmlNodeType expectedState) _ilg.Throw(); } - private void ThrowValidationException(string msg, params object[] values) + private void ThrowValidationException(string msg) { - { - _ilg.Load(msg); - } + _ilg.Load(msg); ThrowValidationException(); } private void ThrowValidationException() { - //SerializationException is internal in SL and so cannot be directly invoked from DynamicMethod - //So use helper function to create SerializationException - _ilg.Call(XmlFormatGeneratorStatics.CreateSerializationExceptionMethod); + _ilg.New(XmlFormatGeneratorStatics.SerializationExceptionCtor); _ilg.Throw(); } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs index b510882ffec99..ee38570e49528 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs @@ -92,6 +92,10 @@ internal XmlFormatClassWriterDelegate GenerateClassWriter(ClassDataContract clas } } InitArgs(classContract.UnderlyingType); + if (classContract.IsReadOnlyContract) + { + ThrowIfCannotSerializeReadOnlyTypes(classContract); + } WriteClass(classContract); return (XmlFormatClassWriterDelegate)_ilg.EndMethod(); } @@ -130,6 +134,10 @@ internal XmlFormatCollectionWriterDelegate GenerateCollectionWriter(CollectionDa } } InitArgs(collectionContract.UnderlyingType); + if (collectionContract.IsReadOnlyContract) + { + ThrowIfCannotSerializeReadOnlyTypes(collectionContract); + } WriteCollection(collectionContract); return (XmlFormatCollectionWriterDelegate)_ilg.EndMethod(); } @@ -160,13 +168,6 @@ private void InitArgs(Type objType) _ilg.ConvertValue(objectArg.ArgType, Globals.TypeOfMemoryStream); _ilg.Call(XmlFormatGeneratorStatics.GetMemoryStreamAdapterMethod); } - //Copy the KeyValuePair to a KeyValuePairAdapter. - else if (objType.IsGenericType && objType.GetGenericTypeDefinition() == Globals.TypeOfKeyValuePairAdapter) - { - ClassDataContract dc = (ClassDataContract)DataContract.GetDataContract(objType); - _ilg.ConvertValue(objectArg.ArgType, Globals.TypeOfKeyValuePair.MakeGenericType(dc.KeyValuePairGenericArguments!)); - _ilg.New(dc.KeyValuePairAdapterConstructorInfo!); - } else { _ilg.ConvertValue(objectArg.ArgType, objType); @@ -174,6 +175,27 @@ private void InitArgs(Type objType) _ilg.Stloc(_objectLocal); } + private void ThrowIfCannotSerializeReadOnlyTypes(ClassDataContract classContract) + { + ThrowIfCannotSerializeReadOnlyTypes(XmlFormatGeneratorStatics.ClassSerializationExceptionMessageProperty); + } + + private void ThrowIfCannotSerializeReadOnlyTypes(CollectionDataContract classContract) + { + ThrowIfCannotSerializeReadOnlyTypes(XmlFormatGeneratorStatics.CollectionSerializationExceptionMessageProperty); + } + + private void ThrowIfCannotSerializeReadOnlyTypes(PropertyInfo serializationExceptionMessageProperty) + { + _ilg.Load(_contextArg); + _ilg.LoadMember(XmlFormatGeneratorStatics.SerializeReadOnlyTypesProperty); + _ilg.IfNot(); + _ilg.Load(_dataContractArg); + _ilg.LoadMember(serializationExceptionMessageProperty); + _ilg.Load(null); + _ilg.Call(XmlFormatGeneratorStatics.ThrowInvalidDataContractExceptionMethod); + _ilg.EndIf(); + } private void InvokeOnSerializing(ClassDataContract classContract) { @@ -559,7 +581,7 @@ private bool TryWritePrimitiveArray(Type type, Type itemType, LocalBuilder value return false; string? writeArrayMethod = null; - switch (itemType.GetTypeCode()) + switch (Type.GetTypeCode(itemType)) { case TypeCode.Boolean: writeArrayMethod = "WriteBooleanArray"; @@ -601,6 +623,15 @@ private bool TryWritePrimitiveArray(Type type, Type itemType, LocalBuilder value private void WriteValue(LocalBuilder memberValue, bool writeXsiType) { Type memberType = memberValue.LocalType; + if (memberType.IsPointer) + { + _ilg.Load(memberValue); + _ilg.Load(memberType); + _ilg.Call(XmlFormatGeneratorStatics.BoxPointer); + memberType = Globals.TypeOfReflectionPointer; + memberValue = _ilg.DeclareLocal(memberType, "memberValueRefPointer"); + _ilg.Store(memberValue); + } bool isNullableOfT = (memberType.IsGenericType && memberType.GetGenericTypeDefinition() == Globals.TypeOfNullable); if (memberType.IsValueType && !isNullableOfT) @@ -670,10 +701,12 @@ private void InternalSerialize(MethodInfo methodInfo, LocalBuilder memberValue, _ilg.Load(_xmlWriterArg); _ilg.Load(memberValue); _ilg.ConvertValue(memberValue.LocalType, Globals.TypeOfObject); - //In SL GetTypeHandle throws MethodAccessException as its internal and extern. - //So as a workaround, call XmlObjectSerializerWriteContext.IsMemberTypeSameAsMemberValue that - //does the actual comparison and returns the bool value we care. - _ilg.Call(null, XmlFormatGeneratorStatics.IsMemberTypeSameAsMemberValue, memberValue, memberType); + LocalBuilder typeHandleValue = _ilg.DeclareLocal(typeof(RuntimeTypeHandle), "typeHandleValue"); + _ilg.Call(null, typeof(Type).GetMethod("GetTypeHandle")!, memberValue); + _ilg.Stloc(typeHandleValue); + _ilg.LoadAddress(typeHandleValue); + _ilg.Ldtoken(memberType); + _ilg.Call(typeof(RuntimeTypeHandle).GetMethod("Equals", new Type[] { typeof(RuntimeTypeHandle) })!); _ilg.Load(writeXsiType); _ilg.Load(DataContract.GetId(memberType.TypeHandle)); _ilg.Ldtoken(memberType); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializer.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializer.cs index 8ba00fd704175..5e300472c8a6e 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializer.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializer.cs @@ -220,7 +220,7 @@ internal static bool CheckIfNeedsContractNsAtRoot(XmlDictionaryString? name, Xml if (name == null) return false; - if (contract.IsBuiltInDataContract || !contract.CanContainReferences) + if (contract.IsBuiltInDataContract || !contract.CanContainReferences || contract.IsISerializable) { return false; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs index 66ce7c6f8f8c0..56cb7458123f0 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs @@ -46,7 +46,7 @@ internal XmlObjectSerializerContext(XmlObjectSerializer serializer, int maxItems internal XmlObjectSerializerContext(DataContractSerializer serializer, DataContract rootTypeDataContract, DataContractResolver? dataContractResolver) : this(serializer, serializer.MaxItemsInObjectGraph, - default(StreamingContext), + new StreamingContext(StreamingContextStates.All), serializer.IgnoreExtensionDataObject, dataContractResolver ) @@ -55,19 +55,12 @@ internal XmlObjectSerializerContext(DataContractSerializer serializer, DataContr this.serializerKnownTypeList = serializer.knownTypeList; } - - internal virtual SerializationMode Mode - { - get { return SerializationMode.SharedContract; } - } - internal virtual bool IsGetOnlyCollection { get { return false; } set { } } - internal StreamingContext GetStreamingContext() { return _streamingContext; @@ -109,11 +102,11 @@ internal virtual DataContract GetDataContract(RuntimeTypeHandle typeHandle, Type { if (IsGetOnlyCollection) { - return DataContract.GetGetOnlyCollectionDataContract(DataContract.GetId(typeHandle), typeHandle, type, Mode); + return DataContract.GetGetOnlyCollectionDataContract(DataContract.GetId(typeHandle), typeHandle, type); } else { - return DataContract.GetDataContract(typeHandle, type, Mode); + return DataContract.GetDataContract(typeHandle, type); } } @@ -135,11 +128,11 @@ internal virtual DataContract GetDataContract(int id, RuntimeTypeHandle typeHand { if (IsGetOnlyCollection) { - return DataContract.GetGetOnlyCollectionDataContract(id, typeHandle, null /*type*/, Mode); + return DataContract.GetGetOnlyCollectionDataContract(id, typeHandle, null /*type*/); } else { - return DataContract.GetDataContract(id, typeHandle, Mode); + return DataContract.GetDataContract(id, typeHandle); } } @@ -227,7 +220,7 @@ internal bool IsKnownType(DataContract dataContract, Type? declaredType) internal Type? ResolveNameFromKnownTypes(XmlQualifiedName typeName) { DataContract? dataContract = ResolveDataContractFromKnownTypes(typeName); - return dataContract?.UnderlyingType; + return dataContract?.OriginalUnderlyingType; } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -284,23 +277,5 @@ internal bool IsKnownType(DataContract dataContract, Type? declaredType) } return null; } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal void PushKnownTypes(DataContract dc) - { - if (dc != null && dc.KnownDataContracts != null) - { - scopedKnownTypes.Push(dc.KnownDataContracts); - } - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal void PopKnownTypes(DataContract dc) - { - if (dc != null && dc.KnownDataContracts != null) - { - scopedKnownTypes.Pop(); - } - } } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContext.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContext.cs index 09fb6e269353d..628640e4d1e19 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContext.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContext.cs @@ -21,6 +21,7 @@ internal class XmlObjectSerializerReadContext : XmlObjectSerializerContext private XmlSerializableReader? _xmlSerializableReader; private XmlDocument? _xmlDocument; private Attributes? _attributesInXmlData; + private XmlReaderDelegator? _extensionDataReader; private object? _getOnlyCollectionValue; private bool _isGetOnlyCollection; @@ -89,7 +90,7 @@ internal XmlObjectSerializerReadContext(DataContractSerializer serializer, DataC } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal virtual object? InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, string name, string ns) + internal virtual object? InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, string? name, string? ns) { DataContract dataContract = GetDataContract(declaredType); return InternalDeserialize(xmlReader, name, ns, declaredType, ref dataContract); @@ -102,6 +103,7 @@ internal XmlObjectSerializerReadContext(DataContractSerializer serializer, DataC return InternalDeserialize(xmlReader, name, ns, declaredType, ref dataContract); } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] protected bool TryHandleNullOrRef(XmlReaderDelegator reader, Type declaredType, string? name, string? ns, ref object? retObj) { ReadAttributes(reader); @@ -331,6 +333,8 @@ internal void AddNewObjectWithId(string id, object? obj) { if (id != Globals.NewObjectId) DeserializedObjects.Add(id, obj); + if (_extensionDataReader?.UnderlyingExtensionDataReader != null) + _extensionDataReader.UnderlyingExtensionDataReader.SetDeserializedValue(obj); } public void ReplaceDeserializedObject(string id, object? oldObj, object? newObj) @@ -355,13 +359,22 @@ public void ReplaceDeserializedObject(string id, object? oldObj, object? newObj) DeserializedObjects.Remove(id); DeserializedObjects.Add(id, newObj); } + if (_extensionDataReader?.UnderlyingExtensionDataReader != null) + _extensionDataReader.UnderlyingExtensionDataReader.SetDeserializedValue(newObj); } - internal object GetExistingObject(string id, Type? type, string? name, string? ns) + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal object? GetExistingObject(string id, Type? type, string? name, string? ns) { object? retObj = DeserializedObjects.GetObject(id); + if (retObj == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.DeserializedObjectWithIdNotFound, id))); + + if (retObj is IDataNode dataNode) + { + retObj = (dataNode.Value != null && dataNode.IsFinalValue) ? dataNode.Value : DeserializeFromExtensionData(dataNode, type ?? dataNode.DataType, name, ns); + } return retObj; } @@ -392,6 +405,18 @@ public object GetRealObject(IObjectReference obj, string id) return realObj; } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private object? DeserializeFromExtensionData(IDataNode dataNode, Type type, string? name, string? ns) + { + // _extensionDataRead is only ever created here, so we know the casting property 'UnderlyingExtensionDataReader' won't be null. + _extensionDataReader ??= CreateReaderDelegatorForReader(new ExtensionDataReader(this)); + _extensionDataReader.UnderlyingExtensionDataReader!.SetDataNode(dataNode, name, ns); + object? retObj = InternalDeserialize(_extensionDataReader, type, name, ns); + dataNode.Clear(); + _extensionDataReader.UnderlyingExtensionDataReader!.Reset(); + return retObj; + } + internal static void Read(XmlReaderDelegator xmlReader) { if (!xmlReader.Read()) @@ -842,9 +867,11 @@ private ISerializableDataNode ReadUnknownISerializableData(XmlReaderDelegator xm private IDataNode ReadUnknownXmlData(XmlReaderDelegator xmlReader, string? dataContractName, string? dataContractNamespace) { - XmlDataNode dataNode = new XmlDataNode(); + XmlDataNode dataNode = new XmlDataNode() + { + OwnerDocument = Document + }; InitializeExtensionDataNode(dataNode, dataContractName, dataContractNamespace); - dataNode.OwnerDocument = Document; if (xmlReader.NodeType == XmlNodeType.EndElement) return dataNode; @@ -957,9 +984,11 @@ private IDataNode ReadAndResolveUnknownXmlData(XmlReaderDelegator xmlReader, IDi return ReadUnknownClassData(CreateReaderOverChildNodes(xmlAttributes, xmlChildNodes), dataContractName, dataContractNamespace); else { - XmlDataNode dataNode = new XmlDataNode(); + XmlDataNode dataNode = new XmlDataNode() + { + OwnerDocument = Document + }; InitializeExtensionDataNode(dataNode, dataContractName, dataContractNamespace); - dataNode.OwnerDocument = Document; dataNode.XmlChildNodes = xmlChildNodes; dataNode.XmlAttributes = xmlAttributes; return dataNode; @@ -983,14 +1012,14 @@ private static bool IsContentNode(XmlNodeType nodeType) internal XmlReaderDelegator CreateReaderOverChildNodes(IList? xmlAttributes, IList xmlChildNodes) { - XmlNode wrapperElement = CreateWrapperXmlElement(Document, xmlAttributes, xmlChildNodes, null, null, null); + XmlElement wrapperElement = CreateWrapperXmlElement(Document, xmlAttributes, xmlChildNodes, null, null, null); XmlReaderDelegator nodeReader = CreateReaderDelegatorForReader(new XmlNodeReader(wrapperElement)); nodeReader.MoveToContent(); Read(nodeReader); return nodeReader; } - internal static XmlNode CreateWrapperXmlElement(XmlDocument document, IList? xmlAttributes, IList xmlChildNodes, string? prefix, string? localName, string? ns) + internal static XmlElement CreateWrapperXmlElement(XmlDocument document, IList? xmlAttributes, IList? xmlChildNodes, string? prefix, string? localName, string? ns) { localName ??= "wrapper"; ns ??= string.Empty; @@ -1026,12 +1055,6 @@ internal static Exception CreateUnexpectedStateException(XmlNodeType expectedSta return XmlObjectSerializer.CreateSerializationExceptionWithReaderDetails(SR.Format(SR.ExpectingState, expectedState), xmlReader); } - //Silverlight only helper function to create SerializationException - internal static Exception CreateSerializationException(string message) - { - return XmlObjectSerializer.CreateSerializationException(message); - } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] protected virtual object? ReadDataContractValue(DataContract dataContract, XmlReaderDelegator reader) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContextComplex.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContextComplex.cs index 53f4021549ec1..333a0d400a247 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContextComplex.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContextComplex.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; @@ -10,13 +11,11 @@ namespace System.Runtime.Serialization internal class XmlObjectSerializerReadContextComplex : XmlObjectSerializerReadContext { private readonly bool _preserveObjectReferences; - private readonly SerializationMode _mode; private readonly ISerializationSurrogateProvider? _serializationSurrogateProvider; internal XmlObjectSerializerReadContextComplex(DataContractSerializer serializer, DataContract rootTypeDataContract, DataContractResolver? dataContractResolver) : base(serializer, rootTypeDataContract, dataContractResolver) { - _mode = SerializationMode.SharedContract; _preserveObjectReferences = serializer.PreserveObjectReferences; _serializationSurrogateProvider = serializer.SerializationSurrogateProvider; } @@ -26,99 +25,31 @@ internal XmlObjectSerializerReadContextComplex(XmlObjectSerializer serializer, i { } - internal override SerializationMode Mode - { - get { return _mode; } - } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal override object? InternalDeserialize(XmlReaderDelegator xmlReader, int declaredTypeID, RuntimeTypeHandle declaredTypeHandle, string name, string ns) { - if (_mode == SerializationMode.SharedContract) - { - if (_serializationSurrogateProvider == null) - return base.InternalDeserialize(xmlReader, declaredTypeID, declaredTypeHandle, name, ns); - else - return InternalDeserializeWithSurrogate(xmlReader, Type.GetTypeFromHandle(declaredTypeHandle)!, null /*surrogateDataContract*/, name, ns); - } + if (_serializationSurrogateProvider == null) + return base.InternalDeserialize(xmlReader, declaredTypeID, declaredTypeHandle, name, ns); else - { - return InternalDeserializeInSharedTypeMode(xmlReader, declaredTypeID, Type.GetTypeFromHandle(declaredTypeHandle)!, name, ns); - } + return InternalDeserializeWithSurrogate(xmlReader, Type.GetTypeFromHandle(declaredTypeHandle)!, null /*surrogateDataContract*/, name, ns); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal override object? InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, string name, string ns) + internal override object? InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, string? name, string? ns) { - if (_mode == SerializationMode.SharedContract) - { - if (_serializationSurrogateProvider == null) - return base.InternalDeserialize(xmlReader, declaredType, name, ns); - else - return InternalDeserializeWithSurrogate(xmlReader, declaredType, null /*surrogateDataContract*/, name, ns); - } + if (_serializationSurrogateProvider == null) + return base.InternalDeserialize(xmlReader, declaredType, name, ns); else - { - return InternalDeserializeInSharedTypeMode(xmlReader, -1, declaredType, name, ns); - } + return InternalDeserializeWithSurrogate(xmlReader, declaredType, null /*surrogateDataContract*/, name, ns); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal override object? InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, DataContract? dataContract, string? name, string? ns) { - if (_mode == SerializationMode.SharedContract) - { - if (_serializationSurrogateProvider == null) - return base.InternalDeserialize(xmlReader, declaredType, dataContract, name, ns); - else - return InternalDeserializeWithSurrogate(xmlReader, declaredType, dataContract, name, ns); - } - else - { - return InternalDeserializeInSharedTypeMode(xmlReader, -1, declaredType, name, ns); - } - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private object? InternalDeserializeInSharedTypeMode(XmlReaderDelegator xmlReader, int declaredTypeID, Type declaredType, string? name, string? ns) - { - Debug.Assert(attributes != null); - - object? retObj = null; - if (TryHandleNullOrRef(xmlReader, declaredType, name, ns, ref retObj)) - return retObj; - - DataContract dataContract; - string? assemblyName = attributes.ClrAssembly; - string? typeName = attributes.ClrType; - if (assemblyName != null && typeName != null) - { - Assembly assembly; - DataContract? tempDataContract = ResolveDataContractInSharedTypeMode(assemblyName, typeName, out assembly, out _); - if (tempDataContract == null) - { - if (assembly == null) - throw XmlObjectSerializer.CreateSerializationException(SR.Format(SR.AssemblyNotFound, assemblyName)); - - throw XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ClrTypeNotFound, assembly.FullName, typeName)); - } - - dataContract = tempDataContract; - //Array covariance is not supported in XSD. If declared type is array, data is sent in format of base array - if (declaredType != null && declaredType.IsArray) - dataContract = (declaredTypeID < 0) ? GetDataContract(declaredType) : GetDataContract(declaredTypeID, declaredType.TypeHandle); - } + if (_serializationSurrogateProvider == null) + return base.InternalDeserialize(xmlReader, declaredType, dataContract, name, ns); else - { - if (assemblyName != null) - throw XmlObjectSerializer.CreateSerializationException(XmlObjectSerializer.TryAddLineInfo(xmlReader, SR.Format(SR.AttributeNotFound, Globals.SerializationNamespace, Globals.ClrTypeLocalName, xmlReader.NodeType, xmlReader.NamespaceURI, xmlReader.LocalName))); - else if (typeName != null) - throw XmlObjectSerializer.CreateSerializationException(XmlObjectSerializer.TryAddLineInfo(xmlReader, SR.Format(SR.AttributeNotFound, Globals.SerializationNamespace, Globals.ClrAssemblyLocalName, xmlReader.NodeType, xmlReader.NamespaceURI, xmlReader.LocalName))); - else if (declaredType == null) - throw XmlObjectSerializer.CreateSerializationException(XmlObjectSerializer.TryAddLineInfo(xmlReader, SR.Format(SR.AttributeNotFound, Globals.SerializationNamespace, Globals.ClrTypeLocalName, xmlReader.NodeType, xmlReader.NamespaceURI, xmlReader.LocalName))); - dataContract = (declaredTypeID < 0) ? GetDataContract(declaredType) : GetDataContract(declaredTypeID, declaredType.TypeHandle); - } - return ReadDataContractValue(dataContract, xmlReader); + return InternalDeserializeWithSurrogate(xmlReader, declaredType, dataContract, name, ns); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -141,44 +72,6 @@ internal override SerializationMode Mode return obj; } - private static Type ResolveDataContractTypeInSharedTypeMode(string assemblyName, string typeName, out Assembly assembly) - { - // The method is used only when _mode == SerializationMode.SharedType. - // _mode is set to SerializationMode.SharedType only when the context is for NetDataContractSerializer. - throw new PlatformNotSupportedException(SR.PlatformNotSupported_NetDataContractSerializer); - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private DataContract? ResolveDataContractInSharedTypeMode(string assemblyName, string typeName, out Assembly assembly, out Type type) - { - type = ResolveDataContractTypeInSharedTypeMode(assemblyName, typeName, out assembly); - if (type != null) - { - return GetDataContract(type); - } - - return null; - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - protected override DataContract? ResolveDataContractFromTypeName() - { - Debug.Assert(attributes != null); - - if (_mode == SerializationMode.SharedContract) - { - return base.ResolveDataContractFromTypeName(); - } - else - { - if (attributes.ClrAssembly != null && attributes.ClrType != null) - { - return ResolveDataContractInSharedTypeMode(attributes.ClrAssembly, attributes.ClrType, out _, out _); - } - } - return null; - } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal override void CheckIfTypeSerializable(Type memberType, bool isMemberTypeSerializable) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerWriteContext.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerWriteContext.cs index 00abd388dc092..317e2638cb4dc 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerWriteContext.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerWriteContext.cs @@ -140,7 +140,7 @@ internal virtual void SerializeWithXsiTypeAtTopLevel(DataContract dataContract, Debug.Assert(rootTypeDataContract != null); bool verifyKnownType = false; - Type declaredType = rootTypeDataContract.UnderlyingType; + Type declaredType = rootTypeDataContract.OriginalUnderlyingType; if (declaredType.IsInterface && CollectionDataContract.IsCollectionInterface(declaredType)) { @@ -501,11 +501,12 @@ public void WriteISerializable(XmlWriterDelegator xmlWriter, ISerializable obj) var serInfo = new SerializationInfo(objType, XmlObjectSerializer.FormatterConverter /*!UnsafeTypeForwardingEnabled is always false*/); GetObjectData(obj, serInfo, GetStreamingContext()); - if (!UnsafeTypeForwardingEnabled && serInfo.AssemblyName == Globals.MscorlibAssemblyName) - { - // Throw if a malicious type tries to set its assembly name to "0" to get deserialized in mscorlib - throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ISerializableAssemblyNameSetToZero, DataContract.GetClrTypeFullName(obj.GetType())))); - } + // (!UnsafeTypeForwardingEnabled) is always false + //if (!UnsafeTypeForwardingEnabled && serInfo.AssemblyName == Globals.MscorlibAssemblyName) + //{ + // // Throw if a malicious type tries to set its assembly name to "0" to get deserialized in mscorlib + // throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ISerializableAssemblyNameSetToZero, DataContract.GetClrTypeFullName(obj.GetType())))); + //} WriteSerializationInfo(xmlWriter, objType, serInfo); } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerWriteContextComplex.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerWriteContextComplex.cs index b1abf32a8ee00..c71bc9d1b168a 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerWriteContextComplex.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerWriteContextComplex.cs @@ -19,12 +19,10 @@ namespace System.Runtime.Serialization internal class XmlObjectSerializerWriteContextComplex : XmlObjectSerializerWriteContext { private readonly ISerializationSurrogateProvider? _serializationSurrogateProvider; - private readonly SerializationMode _mode; internal XmlObjectSerializerWriteContextComplex(DataContractSerializer serializer, DataContract rootTypeDataContract, DataContractResolver? dataContractResolver) : base(serializer, rootTypeDataContract, dataContractResolver) { - _mode = SerializationMode.SharedContract; this.preserveObjectReferences = serializer.PreserveObjectReferences; _serializationSurrogateProvider = serializer.SerializationSurrogateProvider; } @@ -34,11 +32,6 @@ internal XmlObjectSerializerWriteContextComplex(XmlObjectSerializer serializer, { } - internal override SerializationMode Mode - { - get { return _mode; } - } - internal override bool WriteClrTypeInfo(XmlWriterDelegator xmlWriter, DataContract dataContract) { return false; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlReaderDelegator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlReaderDelegator.cs index 15cc14c4c6a66..ea4dc414f809a 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlReaderDelegator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlReaderDelegator.cs @@ -55,7 +55,8 @@ internal string GetAttribute(int i) return reader.GetAttribute(i); } - internal static bool IsEmptyElement + [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Conceptually, this property describes this instance. Callers should expect to have an instance on hand to 'ask' about this 'emtpy' circumstance.")] + internal bool IsEmptyElement { get { return false; } } @@ -496,7 +497,7 @@ internal virtual DateTime ReadElementContentAsDateTime() if (isEndOfEmptyElement) ThrowNotAtElement(); - return XmlConvert.ToDateTime(reader.ReadElementContentAsString(), XmlDateTimeSerializationMode.RoundtripKind); + return reader.ReadElementContentAsDateTime(); } internal virtual DateTime ReadContentAsDateTime() @@ -783,9 +784,12 @@ private static void CheckExpectedArrayLength(XmlObjectSerializerReadContext cont context.IncrementItemCount(arrayLength); } - protected static int GetArrayLengthQuota(XmlObjectSerializerReadContext context) + protected int GetArrayLengthQuota(XmlObjectSerializerReadContext context) { - return Math.Min(context.RemainingItemCount, int.MaxValue); + if (dictionaryReader?.Quotas == null) + return context.RemainingItemCount; + + return Math.Min(context.RemainingItemCount, dictionaryReader.Quotas.MaxArrayLength); } private static void CheckActualArrayLength(int expectedLength, int actualLength, XmlDictionaryString itemName, XmlDictionaryString itemNamespace) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlSerializableReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlSerializableReader.cs index a6a66b6c44acd..fd312d260f791 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlSerializableReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlSerializableReader.cs @@ -10,7 +10,7 @@ namespace System.Runtime.Serialization { - internal sealed class XmlSerializableReader : XmlReader, IXmlLineInfo + internal sealed class XmlSerializableReader : XmlReader, IXmlLineInfo, IXmlTextParser // IXmlTextParser (Normalized, WhitespaceHandling) was added. Is it ever used? { private XmlReaderDelegator _xmlReader = null!; // initialized in BeginRead private int _startDepth; @@ -79,8 +79,10 @@ public override void Close() public override string BaseURI { get { return InnerReader.BaseURI; } } public override bool IsEmptyElement { get { return InnerReader.IsEmptyElement; } } public override bool IsDefault { get { return InnerReader.IsDefault; } } + public override char QuoteChar { get { return InnerReader.QuoteChar; } } public override XmlSpace XmlSpace { get { return InnerReader.XmlSpace; } } public override string XmlLang { get { return InnerReader.XmlLang; } } + public override IXmlSchemaInfo? SchemaInfo { get { return InnerReader.SchemaInfo; } } public override Type ValueType { get { return InnerReader.ValueType; } } public override int AttributeCount { get { return InnerReader.AttributeCount; } } public override string this[int i] { get { return InnerReader[i]; } } @@ -122,6 +124,43 @@ public override void Close() public override int ReadContentAsBase64(byte[] buffer, int index, int count) { return InnerReader.ReadContentAsBase64(buffer, index, count); } public override int ReadContentAsBinHex(byte[] buffer, int index, int count) { return InnerReader.ReadContentAsBinHex(buffer, index, count); } public override int ReadValueChunk(char[] buffer, int index, int count) { return InnerReader.ReadValueChunk(buffer, index, count); } + public override string ReadString() { return InnerReader.ReadString(); } + + // IXmlTextParser members + bool IXmlTextParser.Normalized + { + get + { + IXmlTextParser? xmlTextParser = InnerReader as IXmlTextParser; + return (xmlTextParser == null) ? _xmlReader.Normalized : xmlTextParser.Normalized; + } + set + { + IXmlTextParser? xmlTextParser = InnerReader as IXmlTextParser; + if (xmlTextParser == null) + _xmlReader.Normalized = value; + else + xmlTextParser.Normalized = value; + } + } + + WhitespaceHandling IXmlTextParser.WhitespaceHandling + { + get + { + IXmlTextParser? xmlTextParser = InnerReader as IXmlTextParser; + return (xmlTextParser == null) ? _xmlReader.WhitespaceHandling : xmlTextParser.WhitespaceHandling; + } + set + { + IXmlTextParser? xmlTextParser = InnerReader as IXmlTextParser; + if (xmlTextParser == null) + _xmlReader.WhitespaceHandling = value; + else + xmlTextParser.WhitespaceHandling = value; + } + } + // IXmlLineInfo members bool IXmlLineInfo.HasLineInfo() { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlWriterDelegator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlWriterDelegator.cs index d9366ebf510cd..ec08e05117772 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlWriterDelegator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlWriterDelegator.cs @@ -281,7 +281,7 @@ internal void WriteAnyType(object value) internal void WriteAnyType(object value, Type valueType) { bool handled = true; - switch (valueType.GetTypeCode()) + switch (Type.GetTypeCode(valueType)) { case TypeCode.Boolean: WriteBoolean((bool)value); @@ -329,6 +329,7 @@ internal void WriteAnyType(object value, Type valueType) WriteUnsignedLong((ulong)value); break; case TypeCode.Empty: + case TypeCode.DBNull: case TypeCode.Object: default: if (valueType == Globals.TypeOfByteArray) @@ -453,7 +454,7 @@ internal void WriteBoolean(bool value, XmlDictionaryString name, XmlDictionarySt internal virtual void WriteDateTime(DateTime value) { - WriteString(XmlConvert.ToString(value, XmlDateTimeSerializationMode.RoundtripKind)); + writer.WriteValue(value); } internal void WriteDateTime(DateTime value, XmlDictionaryString name, XmlDictionaryString? ns) @@ -618,13 +619,6 @@ internal void WriteTimeSpan(TimeSpan value) writer.WriteRaw(XmlConvert.ToString(value)); } - internal void WriteTimeSpan(char value, XmlDictionaryString name, XmlDictionaryString? ns) - { - WriteStartElementPrimitive(name, ns); - writer.WriteRaw(XmlConvert.ToString(value)); - WriteEndElementPrimitive(); - } - internal void WriteTimeSpan(TimeSpan value, XmlDictionaryString name, XmlDictionaryString? ns) { WriteStartElementPrimitive(name, ns); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs index ad147ba1af8fd..1337766eb1535 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs @@ -178,11 +178,6 @@ public XmlQualifiedName GetSchemaTypeName(Type type) private static Type GetSurrogatedType(Type type) { -#if SUPPORT_SURROGATE - IDataContractSurrogate dataContractSurrogate; - if (options != null && (dataContractSurrogate = Options.GetSurrogate()) != null) - type = DataContractSurrogateCaller.GetDataContractType(dataContractSurrogate, type); -#endif return type; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/ArrayHelper.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/ArrayHelper.cs index 3baa246fd2a4e..b343623355ec3 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/ArrayHelper.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/ArrayHelper.cs @@ -17,6 +17,9 @@ public TArray[] ReadArray(XmlDictionaryReader reader, TArgument localName, TArgu int count; if (reader.TryGetArrayLength(out count)) { + if (count > maxArrayLength) + XmlExceptionHelper.ThrowMaxArrayLengthOrMaxItemsQuotaExceeded(reader, maxArrayLength); + if (count > XmlDictionaryReader.MaxInitialArrayLength) count = XmlDictionaryReader.MaxInitialArrayLength; } @@ -35,6 +38,8 @@ public TArray[] ReadArray(XmlDictionaryReader reader, TArgument localName, TArgu break; read += actual; } + if (totalRead > maxArrayLength - read) + XmlExceptionHelper.ThrowMaxArrayLengthOrMaxItemsQuotaExceeded(reader, maxArrayLength); totalRead += read; if (read < array.Length || reader.NodeType == XmlNodeType.EndElement) break; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/EncodingStreamWrapper.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/EncodingStreamWrapper.cs index 0d9437d5443d0..9b88c45d8561d 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/EncodingStreamWrapper.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/EncodingStreamWrapper.cs @@ -556,15 +556,15 @@ public override long Position } } - protected override void Dispose(bool disposing) + public override void Close() { if (_stream.CanWrite) { Flush(); } + base.Close(); _stream.Dispose(); - base.Dispose(disposing); } public override void Flush() @@ -726,8 +726,4 @@ public override void SetLength(long value) throw new NotSupportedException(); } } - - // Add format exceptions - // Do we need to modify the stream position/Seek to account for the buffer? - // ASSUMPTION (Microsoft): This class will only be used for EITHER reading OR writing. } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/StringHandle.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/StringHandle.cs index eacd50236de1e..50dce6014220d 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/StringHandle.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/StringHandle.cs @@ -111,9 +111,11 @@ public string GetString(XmlNameTable nameTable) return _bufferReader.GetString(_offset, _length, nameTable); if (type == StringHandleType.Dictionary) return nameTable.Add(_bufferReader.GetDictionaryString(_key).Value); - DiagnosticUtility.DebugAssert(type == StringHandleType.ConstString, "Should be ConstString"); - //If not Utf8 then the StringHandleType is ConstString - return nameTable.Add(s_constStrings[_key]); + if (type == StringHandleType.ConstString) + return nameTable.Add(s_constStrings[_key]); + // If none of the above, must be StringHandleType.EscapedUTF8 + DiagnosticUtility.DebugAssert(type == StringHandleType.EscapedUTF8, "Should be EscapedUTF8"); + return _bufferReader.GetEscapedString(_offset, _length, nameTable); } public string GetString() @@ -123,9 +125,11 @@ public string GetString() return _bufferReader.GetString(_offset, _length); if (type == StringHandleType.Dictionary) return _bufferReader.GetDictionaryString(_key).Value; - DiagnosticUtility.DebugAssert(type == StringHandleType.ConstString, "Should be ConstString"); - //If not Utf8 then the StringHandleType is ConstString - return s_constStrings[_key]; + if (type == StringHandleType.ConstString) + return s_constStrings[_key]; + // If none of the above, must be StringHandleType.EscapedUTF8 + DiagnosticUtility.DebugAssert(type == StringHandleType.EscapedUTF8, "Should be EscapedUTF8"); + return _bufferReader.GetEscapedString(_offset, _length); } public byte[] GetString(out int offset, out int length) @@ -177,6 +181,7 @@ public bool TryGetDictionaryString([NotNullWhen(true)] out XmlDictionaryString? value = null; return false; } + public override string ToString() { return GetString(); @@ -211,7 +216,7 @@ private bool Equals2(string s2) return _bufferReader.GetDictionaryString(_key).Value == s2; if (type == StringHandleType.UTF8) return _bufferReader.Equals2(_offset, _length, s2); - DiagnosticUtility.DebugAssert(type == StringHandleType.ConstString, ""); + DiagnosticUtility.DebugAssert(type == StringHandleType.EscapedUTF8 || type == StringHandleType.ConstString, ""); return GetString() == s2; } @@ -248,6 +253,7 @@ public bool Equals([NotNullWhen(true)] StringHandle? other) { return !s1.Equals2(xmlString2); } + public static bool operator ==(StringHandle s1, string s2) { return s1.Equals2(s2); @@ -275,6 +281,7 @@ public int CompareTo(StringHandle that) else return string.Compare(this.GetString(), that.GetString(), StringComparison.Ordinal); } + public override bool Equals([NotNullWhen(true)] object? obj) { return Equals(obj as StringHandle); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/ValueHandle.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/ValueHandle.cs index f09a06baa1572..9a1195317eb10 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/ValueHandle.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/ValueHandle.cs @@ -114,6 +114,7 @@ public void SetQNameValue(int prefix, int key) { SetValue(ValueHandleType.QName, key, prefix); } + public void SetValue(ValueHandleType type, int offset, int length) { _type = type; @@ -414,6 +415,7 @@ public Guid ToGuid() return XmlConverter.ToGuid(_bufferReader.Buffer, _offset, _length); return XmlConverter.ToGuid(GetString()); } + public override string ToString() { return GetString(); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBaseReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBaseReader.cs index 38e29e8609563..9afa16593c731 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBaseReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBaseReader.cs @@ -127,6 +127,7 @@ protected void MoveToInitial(XmlDictionaryReaderQuotas quotas) _attributeIndex = -1; _rootElement = false; _readingElement = false; + _signing = false; MoveToNode(s_initialNode); } @@ -191,6 +192,7 @@ private bool CheckDeclAttribute(int index, string localName, string? value, bool return true; } + protected XmlCommentNode MoveToComment() { _commentNode ??= new XmlCommentNode(_bufferReader); @@ -229,6 +231,7 @@ protected XmlTextNode MoveToWhitespaceText() MoveToNode(_whitespaceTextNode); return _whitespaceTextNode; } + protected XmlElementNode ElementNode { get @@ -341,6 +344,7 @@ protected XmlAttributeNode AddXmlAttribute() { return AddAttribute(QNameType.Normal, true); } + protected XmlAttributeNode AddXmlnsAttribute(Namespace ns) { if (!ns.Prefix.IsEmpty && ns.Uri.IsEmpty) @@ -385,6 +389,7 @@ protected void FixXmlAttribute(XmlAttributeNode attributeNode) } } } + protected bool OutsideRootElement { get @@ -392,6 +397,7 @@ protected bool OutsideRootElement return _depth == 0; } } + public override bool CanReadBinaryContent { get { return true; } @@ -612,7 +618,6 @@ private XmlAttributeNode GetAttributeNode(int index) return null; } - public override string GetAttribute(int index) { return GetAttributeNode(index).ValueAsString; @@ -641,6 +646,7 @@ public override string GetAttribute(int index) return null; return attributeNode.ValueAsString; } + public sealed override bool IsEmptyElement { get @@ -783,17 +789,19 @@ private void CheckAttributes(XmlAttributeNode[] attributeNodes, int attributeCou } } - public override void MoveToAttribute(int index) { MoveToNode(GetAttributeNode(index)); + _attributeIndex = index; } + public override bool MoveToAttribute(string name) { XmlNode? attributeNode = GetAttributeNode(name); if (attributeNode == null) return false; MoveToNode(attributeNode); + _attributeIndex = _attributeStart; return true; } @@ -803,6 +811,7 @@ public override bool MoveToAttribute(string localName, string? namespaceUri) if (attributeNode == null) return false; MoveToNode(attributeNode); + _attributeIndex = _attributeStart; return true; } @@ -904,7 +913,7 @@ public override XmlNameTable NameTable { if (_nameTable == null) { - _nameTable = new NameTable(); + _nameTable = new QuotaNameTable(this, _quotas.MaxNameTableCharCount); _nameTable.Add(xml); _nameTable.Add(xmlns); _nameTable.Add(xmlnsNamespace); @@ -955,6 +964,13 @@ public override string Prefix } } + public override char QuoteChar + { + get + { + return _node.QuoteChar; + } + } public override bool IsLocalName(string localName) { @@ -1194,6 +1210,36 @@ public override string ReadElementContentAsString() return s; } } + + public override string ReadElementString() + { + MoveToStartElement(); + if (IsEmptyElement) + { + Read(); + return string.Empty; + } + else + { + Read(); + string s = ReadString(); + ReadEndElement(); + return s; + } + } + + public override string ReadElementString(string name) + { + MoveToStartElement(name); + return ReadElementString(); + } + + public override string ReadElementString(string localName, string namespaceUri) + { + MoveToStartElement(localName, namespaceUri); + return ReadElementString(); + } + public override void ReadStartElement() { if (_node.NodeType != XmlNodeType.Element) @@ -2067,7 +2113,6 @@ protected XmlNode(XmlNodeType nodeType, _depthDelta = depthDelta; _isEmptyElement = false; _quoteChar = '"'; - _qnameType = QNameType.Normal; } @@ -2251,6 +2296,7 @@ public bool IsLocalNameAndNamespaceUri(XmlDictionaryString localName, XmlDiction return this.Namespace.Prefix == localName && ns.Value == xmlnsNamespace; } } + public bool IsPrefixAndLocalName(string prefix, string localName) { if (_qnameType == QNameType.Normal) @@ -2541,6 +2587,7 @@ public XmlCommentNode(XmlBufferReader bufferReader) { } } + protected sealed class XmlEndOfFileNode : XmlNode { public XmlEndOfFileNode(XmlBufferReader bufferReader) @@ -2573,7 +2620,7 @@ public XmlClosedNode(XmlBufferReader bufferReader) private sealed class AttributeSorter : IComparer { - private object[]? _indeces; + private object[]? _indices; private XmlAttributeNode[]? _attributeNodes; private int _attributeCount; private int _attributeIndex1; @@ -2599,9 +2646,9 @@ public void GetIndeces(out int attributeIndex1, out int attributeIndex2) public void Close() { - if (_indeces != null && _indeces.Length > 32) + if (_indices != null && _indices.Length > 32) { - _indeces = null; + _indices = null; } } @@ -2609,25 +2656,25 @@ private bool Sort() { // Optimistically use the last sort order and check to see if that works. This helps the case // where elements with large numbers of attributes are repeated. - if (_indeces != null && _indeces.Length == _attributeCount && IsSorted()) + if (_indices != null && _indices.Length == _attributeCount && IsSorted()) return true; object[] newIndeces = new object[_attributeCount]; for (int i = 0; i < newIndeces.Length; i++) newIndeces[i] = i; - _indeces = newIndeces; - Array.Sort(_indeces, 0, _attributeCount, this); + _indices = newIndeces; + Array.Sort(_indices, 0, _attributeCount, this); return IsSorted(); } private bool IsSorted() { - for (int i = 0; i < _indeces!.Length - 1; i++) + for (int i = 0; i < _indices!.Length - 1; i++) { - if (Compare(_indeces[i], _indeces[i + 1]) >= 0) + if (Compare(_indices[i], _indices[i + 1]) >= 0) { - _attributeIndex1 = (int)_indeces[i]; - _attributeIndex2 = (int)_indeces[i + 1]; + _attributeIndex1 = (int)_indices[i]; + _attributeIndex2 = (int)_indices[i + 1]; return false; } } @@ -2921,6 +2968,7 @@ public Namespace AddNamespace() return XmlNamespace; return null; } + public Namespace? LookupNamespace(string prefix) { PrefixHandleType shortPrefix; @@ -3070,6 +3118,7 @@ public bool IsUri(XmlDictionaryString s) } return false; } + public StringHandle Uri { get @@ -3090,5 +3139,56 @@ public Namespace? OuterUri } } } + + private sealed class QuotaNameTable : XmlNameTable + { + private readonly XmlDictionaryReader _reader; + private readonly XmlNameTable _nameTable; + private readonly int _maxCharCount; + private int _charCount; + + public QuotaNameTable(XmlDictionaryReader reader, int maxCharCount) + { + _reader = reader; + _nameTable = new NameTable(); + _maxCharCount = maxCharCount; + _charCount = 0; + } + + public override string? Get(char[] chars, int offset, int count) + { + return _nameTable.Get(chars, offset, count); + } + + public override string? Get(string value) + { + return _nameTable.Get(value); + } + + private void Add(int charCount) + { + if (charCount > _maxCharCount - _charCount) + XmlExceptionHelper.ThrowMaxNameTableCharCountExceeded(_reader, _maxCharCount); + _charCount += charCount; + } + + public override string Add(char[] chars, int offset, int count) + { + string? s = _nameTable.Get(chars, offset, count); + if (s != null) + return s; + Add(count); + return _nameTable.Add(chars, offset, count); + } + + public override string Add(string value) + { + string? s = _nameTable.Get(value); + if (s != null) + return s; + Add(value.Length); + return _nameTable.Add(value); + } + } } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBaseWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBaseWriter.cs index f009bccb33587..fa4962ad564c4 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBaseWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBaseWriter.cs @@ -13,7 +13,7 @@ namespace System.Xml { - internal abstract class XmlBaseWriter : XmlDictionaryWriter + internal abstract class XmlBaseWriter : XmlDictionaryWriter, IFragmentCapableXmlDictionaryWriter { private XmlNodeWriter _writer = null!; // initialized in SetOutput private readonly NamespaceManager _nsMgr; @@ -29,6 +29,10 @@ internal abstract class XmlBaseWriter : XmlDictionaryWriter private int _trailByteCount; private XmlStreamNodeWriter _nodeWriter = null!; // initialized in SetOutput private XmlSigningNodeWriter? _signingWriter; + private XmlUTF8NodeWriter? _textFragmentWriter; + private XmlNodeWriter? _oldWriter; + private Stream? _oldStream; + private int _oldNamespaceBoundary; private bool _inList; private const string xmlnsNamespace = "http://www.w3.org/2000/xmlns/"; private const string xmlNamespace = "http://www.w3.org/XML/1998/namespace"; @@ -57,6 +61,8 @@ protected void SetOutput(XmlStreamNodeWriter writer) } _attributeLocalName = null; _attributeValue = null; + _oldWriter = null; + _oldStream = null; } public override void Flush() @@ -101,6 +107,12 @@ public override void Close() { _signingWriter.Close(); } + if (_textFragmentWriter != null) + { + _textFragmentWriter.Close(); + } + _oldWriter = null; + _oldStream = null; } } @@ -434,7 +446,7 @@ public override void WriteComment(string? text) { text = string.Empty; } - else if (text.Contains("--") || text.StartsWith('-')) + else if (text.Contains("--") || text.EndsWith('-')) { throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.XmlInvalidCommentChars, nameof(text))); } @@ -929,6 +941,18 @@ public override void WriteEndDocument() _documentState = DocumentState.End; } + protected int NamespaceBoundary + { + get + { + return _nsMgr.NamespaceBoundary; + } + set + { + _nsMgr.NamespaceBoundary = value; + } + } + public override void WriteEntityRef(string name) { throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.Format(SR.XmlMethodNotSupported, "WriteEntityRef"))); @@ -1152,6 +1176,10 @@ public override void WriteValue(object value) { WriteValue((Array)value); } + else if (value is IStreamProvider) + { + WriteValue((IStreamProvider)value); + } else { WritePrimitiveValue(value); @@ -1429,11 +1457,27 @@ public override void WriteValue(TimeSpan value) } } + private static void EnsureBufferBounds(byte[] buffer, int offset, int count) + { + ArgumentNullException.ThrowIfNull(buffer); + + // Not checking upper bound because it will be caught by "count". This is what XmlTextWriter does. + if (offset < 0) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(offset), SR.ValueMustBeNonNegative)); + + if (count < 0) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(count), SR.ValueMustBeNonNegative)); + if (count > buffer.Length - offset) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(count), SR.Format(SR.SizeExceedsRemainingBufferSpace, buffer.Length - offset))); + } + public override void WriteBinHex(byte[] buffer, int offset, int count) { if (IsClosed) ThrowClosed(); + EnsureBufferBounds(buffer, offset, count); + WriteRaw(BinHexEncoding.GetString(buffer, offset, count)); } @@ -1442,16 +1486,7 @@ public override void WriteBase64(byte[] buffer, int offset, int count) if (IsClosed) ThrowClosed(); - ArgumentNullException.ThrowIfNull(buffer); - - // Not checking upper bound because it will be caught by "count". This is what XmlTextWriter does. - if (offset < 0) - throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(offset), SR.ValueMustBeNonNegative)); - - if (count < 0) - throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(count), SR.ValueMustBeNonNegative)); - if (count > buffer.Length - offset) - throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(count), SR.Format(SR.SizeExceedsRemainingBufferSpace, buffer.Length - offset))); + EnsureBufferBounds(buffer, offset, count); if (count > 0) { @@ -1476,6 +1511,7 @@ public override void WriteBase64(byte[] buffer, int offset, int count) WriteAttributeText(XmlConverter.Base64Encoding.GetString(_trailBytes, 0, _trailByteCount)); WriteAttributeText(XmlConverter.Base64Encoding.GetString(buffer, offset, actualByteCount - _trailByteCount)); } + if (!_isXmlnsAttribute) { StartContent(); @@ -1483,6 +1519,7 @@ public override void WriteBase64(byte[] buffer, int offset, int count) EndContent(); } _trailByteCount = (totalByteCount - actualByteCount); + if (_trailByteCount > 0) { int trailOffset = offset + count - _trailByteCount; @@ -1503,16 +1540,7 @@ public override Task WriteBase64Async(byte[] buffer, int offset, int count) if (IsClosed) ThrowClosed(); - ArgumentNullException.ThrowIfNull(buffer); - - // Not checking upper bound because it will be caught by "count". This is what XmlTextWriter does. - if (offset < 0) - throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(offset), SR.ValueMustBeNonNegative)); - - if (count < 0) - throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(count), SR.ValueMustBeNonNegative)); - if (count > buffer.Length - offset) - throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(count), SR.Format(SR.SizeExceedsRemainingBufferSpace, buffer.Length - offset))); + EnsureBufferBounds(buffer, offset, count); return WriteBase64AsyncImpl(buffer, offset, count); } @@ -1606,6 +1634,125 @@ public override void EndCanonicalization() protected abstract XmlSigningNodeWriter CreateSigningNodeWriter(); + public virtual bool CanFragment + { + get + { + return true; + } + } + + public void StartFragment(Stream stream, bool generateSelfContainedTextFragment) + { + if (!CanFragment) + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); + + if (IsClosed) + ThrowClosed(); + + ArgumentNullException.ThrowIfNull(stream); + + if (_oldStream != null || _oldWriter != null) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException()); + if (WriteState == WriteState.Attribute) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.XmlInvalidWriteState, "StartFragment", WriteState.ToString()))); + + FlushElement(); + _writer.Flush(); + + _oldNamespaceBoundary = NamespaceBoundary; + + XmlStreamNodeWriter? fragmentWriter = null; + if (generateSelfContainedTextFragment) + { + this.NamespaceBoundary = _depth + 1; + _textFragmentWriter ??= new XmlUTF8NodeWriter(); + _textFragmentWriter.SetOutput(stream, false, Encoding.UTF8); + fragmentWriter = _textFragmentWriter; + } + + if (Signing) + { + if (fragmentWriter != null) + { + _oldWriter = _signingWriter!.NodeWriter; + _signingWriter.NodeWriter = fragmentWriter; + } + else + { + _oldStream = ((XmlStreamNodeWriter)_signingWriter!.NodeWriter).Stream; + ((XmlStreamNodeWriter)_signingWriter.NodeWriter).Stream = stream; + } + } + else + { + if (fragmentWriter != null) + { + _oldWriter = _writer; + _writer = fragmentWriter; + } + else + { + _oldStream = _nodeWriter.Stream; + _nodeWriter.Stream = stream; + } + } + } + + public void EndFragment() + { + if (IsClosed) + ThrowClosed(); + + if (_oldStream == null && _oldWriter == null) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException()); + if (WriteState == WriteState.Attribute) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.XmlInvalidWriteState, "EndFragment", WriteState.ToString()))); + + FlushElement(); + _writer.Flush(); + + if (Signing) + { + if (_oldWriter != null) + _signingWriter!.NodeWriter = _oldWriter; + else + ((XmlStreamNodeWriter)_signingWriter!.NodeWriter).Stream = _oldStream!; // Checked above. _oldStream can't be null if _oldWriter is. + } + else + { + if (_oldWriter != null) + _writer = _oldWriter; + else + _nodeWriter.Stream = _oldStream!; // Checked above. _oldStream can't be null if _oldWriter is. + } + NamespaceBoundary = _oldNamespaceBoundary; + _oldWriter = null; + _oldStream = null; + } + + public void WriteFragment(byte[] buffer, int offset, int count) + { + if (!CanFragment) + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException()); + + if (IsClosed) + ThrowClosed(); + + EnsureBufferBounds(buffer, offset, count); + + if (WriteState == WriteState.Attribute) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.XmlInvalidWriteState, "WriteFragment", WriteState.ToString()))); + + if (_writer != _nodeWriter) + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException()); + + FlushElement(); + FlushBase64(); + _nodeWriter.Flush(); + _nodeWriter.Stream.Write(buffer, offset, count); + } + private void FlushBase64() { if (_trailByteCount > 0) @@ -1805,6 +1952,7 @@ private sealed class NamespaceManager private int _attributeCount; private XmlSpace _space; private string? _lang; + private int _namespaceBoundary; private int _nsTop; private readonly Namespace _defaultNamespace; @@ -1846,9 +1994,29 @@ public void Clear() _attributeCount = 0; _space = XmlSpace.None; _lang = null; + _namespaceBoundary = 0; _lastNameSpace = null; } + public int NamespaceBoundary + { + get + { + return _namespaceBoundary; + } + set + { + int i; + for (i = 0; i < _nsCount; i++) + if (_namespaces![i].Depth >= value) + break; + + _nsTop = i; + _namespaceBoundary = value; + _lastNameSpace = null; + } + } + public void Close() { if (_depth == 0) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBinaryReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBinaryReader.cs index 9b6911441951b..07765d45883b7 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBinaryReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBinaryReader.cs @@ -29,6 +29,7 @@ internal sealed class XmlBinaryReader : XmlBaseReader, IXmlBinaryReaderInitializ private int _arrayCount; private int _maxBytesPerRead; private XmlBinaryNodeType _arrayNodeType; + private OnXmlDictionaryReaderClose? _onClose; public XmlBinaryReader() { @@ -50,7 +51,7 @@ public void SetInput(byte[] buffer, int offset, int count, throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(count), SR.ValueMustBeNonNegative)); if (count > buffer.Length - offset) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(count), SR.Format(SR.SizeExceedsRemainingBufferSpace, buffer.Length - offset))); - MoveToInitial(quotas, session, null); + MoveToInitial(quotas, session, onClose); BufferReader.SetBuffer(buffer, offset, count, dictionary, session); _buffered = true; } @@ -63,7 +64,7 @@ public void SetInput(Stream stream, { ArgumentNullException.ThrowIfNull(stream); - MoveToInitial(quotas, session, null); + MoveToInitial(quotas, session, onClose); BufferReader.SetBuffer(stream, dictionary, session); _buffered = false; } @@ -73,12 +74,26 @@ private void MoveToInitial(XmlDictionaryReaderQuotas quotas, XmlBinaryReaderSess MoveToInitial(quotas); _maxBytesPerRead = quotas.MaxBytesPerRead; _arrayState = ArrayState.None; + _onClose = onClose; _isTextWithEndElement = false; } public override void Close() { base.Close(); + OnXmlDictionaryReaderClose? onClose = _onClose; + _onClose = null; + if (onClose != null) + { + try + { + onClose(this); + } + catch (Exception e) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e); + } + } } public override string ReadElementContentAsString() @@ -710,8 +725,10 @@ private void ReadAttributes() private void ReadAttributes2() { + int startOffset = 0; + if (_buffered) - _ = BufferReader.Offset; + startOffset = BufferReader.Offset; while (true) { @@ -845,6 +862,8 @@ private void ReadAttributes2() ReadAttributeText(attributeNode.AttributeText!); break; default: + if (_buffered && (BufferReader.Offset - startOffset) > _maxBytesPerRead) + XmlExceptionHelper.ThrowMaxBytesPerReadExceeded(this, _maxBytesPerRead); ProcessAttributes(); return; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBinaryWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBinaryWriter.cs index ef401fd803182..be47e110a151b 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBinaryWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBinaryWriter.cs @@ -807,28 +807,8 @@ public override unsafe void WriteDecimalText(decimal d) public override void WriteDateTimeText(DateTime dt) { - WriteTextNodeWithInt64(XmlBinaryNodeType.DateTimeText, ToBinary(dt)); + WriteTextNodeWithInt64(XmlBinaryNodeType.DateTimeText, dt.ToBinary()); } - private static long ToBinary(DateTime dt) - { - long temp = 0; - switch (dt.Kind) - { - case DateTimeKind.Local: - temp |= -9223372036854775808L; // 0x8000000000000000 - temp |= dt.ToUniversalTime().Ticks; - break; - case DateTimeKind.Utc: - temp |= 0x4000000000000000L; - temp |= dt.Ticks; - break; - case DateTimeKind.Unspecified: - temp = dt.Ticks; - break; - } - return temp; - } - public override void WriteUniqueIdText(UniqueId value) { @@ -906,7 +886,7 @@ public void WriteDateTimeArray(DateTime[] array, int offset, int count) WriteArrayInfo(XmlBinaryNodeType.DateTimeTextWithEndElement, count); for (int i = 0; i < count; i++) { - WriteInt64(ToBinary(array[offset + i])); + WriteInt64(array[offset + i].ToBinary()); } } @@ -1185,7 +1165,6 @@ private unsafe void UnsafeWriteArray(string? prefix, string localName, string? n { WriteStartArray(prefix, localName, namespaceUri, count); _writer.UnsafeWriteArray(nodeType, count, array, arrayMax); - // WriteEndArray(); } private unsafe void UnsafeWriteArray(string? prefix, XmlDictionaryString localName, XmlDictionaryString? namespaceUri, @@ -1193,7 +1172,6 @@ private unsafe void UnsafeWriteArray(string? prefix, XmlDictionaryString localNa { WriteStartArray(prefix, localName, namespaceUri, count); _writer.UnsafeWriteArray(nodeType, count, array, arrayMax); - // WriteEndArray(); } private static void CheckArray(Array array, int offset, int count) @@ -1212,6 +1190,11 @@ private static void CheckArray(Array array, int offset, int count) public override unsafe void WriteArray(string? prefix, string localName, string? namespaceUri, bool[] array, int offset, int count) { + if (Signing) + { + base.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + else { CheckArray(array, offset, count); if (count > 0) @@ -1226,6 +1209,11 @@ public override unsafe void WriteArray(string? prefix, string localName, string? public override unsafe void WriteArray(string? prefix, XmlDictionaryString localName, XmlDictionaryString? namespaceUri, bool[] array, int offset, int count) { + if (Signing) + { + base.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + else { CheckArray(array, offset, count); if (count > 0) @@ -1240,6 +1228,11 @@ public override unsafe void WriteArray(string? prefix, XmlDictionaryString local public override unsafe void WriteArray(string? prefix, string localName, string? namespaceUri, short[] array, int offset, int count) { + if (Signing) + { + base.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + else { CheckArray(array, offset, count); if (count > 0) @@ -1254,6 +1247,11 @@ public override unsafe void WriteArray(string? prefix, string localName, string? public override unsafe void WriteArray(string? prefix, XmlDictionaryString localName, XmlDictionaryString? namespaceUri, short[] array, int offset, int count) { + if (Signing) + { + base.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + else { CheckArray(array, offset, count); if (count > 0) @@ -1268,6 +1266,11 @@ public override unsafe void WriteArray(string? prefix, XmlDictionaryString local public override unsafe void WriteArray(string? prefix, string localName, string? namespaceUri, int[] array, int offset, int count) { + if (Signing) + { + base.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + else { CheckArray(array, offset, count); if (count > 0) @@ -1282,6 +1285,11 @@ public override unsafe void WriteArray(string? prefix, string localName, string? public override unsafe void WriteArray(string? prefix, XmlDictionaryString localName, XmlDictionaryString? namespaceUri, int[] array, int offset, int count) { + if (Signing) + { + base.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + else { CheckArray(array, offset, count); if (count > 0) @@ -1296,6 +1304,11 @@ public override unsafe void WriteArray(string? prefix, XmlDictionaryString local public override unsafe void WriteArray(string? prefix, string localName, string? namespaceUri, long[] array, int offset, int count) { + if (Signing) + { + base.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + else { CheckArray(array, offset, count); if (count > 0) @@ -1310,6 +1323,11 @@ public override unsafe void WriteArray(string? prefix, string localName, string? public override unsafe void WriteArray(string? prefix, XmlDictionaryString localName, XmlDictionaryString? namespaceUri, long[] array, int offset, int count) { + if (Signing) + { + base.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + else { CheckArray(array, offset, count); if (count > 0) @@ -1324,6 +1342,11 @@ public override unsafe void WriteArray(string? prefix, XmlDictionaryString local public override unsafe void WriteArray(string? prefix, string localName, string? namespaceUri, float[] array, int offset, int count) { + if (Signing) + { + base.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + else { CheckArray(array, offset, count); if (count > 0) @@ -1338,6 +1361,11 @@ public override unsafe void WriteArray(string? prefix, string localName, string? public override unsafe void WriteArray(string? prefix, XmlDictionaryString localName, XmlDictionaryString? namespaceUri, float[] array, int offset, int count) { + if (Signing) + { + base.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + else { CheckArray(array, offset, count); if (count > 0) @@ -1352,6 +1380,11 @@ public override unsafe void WriteArray(string? prefix, XmlDictionaryString local public override unsafe void WriteArray(string? prefix, string localName, string? namespaceUri, double[] array, int offset, int count) { + if (Signing) + { + base.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + else { CheckArray(array, offset, count); if (count > 0) @@ -1366,6 +1399,11 @@ public override unsafe void WriteArray(string? prefix, string localName, string? public override unsafe void WriteArray(string? prefix, XmlDictionaryString localName, XmlDictionaryString? namespaceUri, double[] array, int offset, int count) { + if (Signing) + { + base.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + else { CheckArray(array, offset, count); if (count > 0) @@ -1380,6 +1418,11 @@ public override unsafe void WriteArray(string? prefix, XmlDictionaryString local public override unsafe void WriteArray(string? prefix, string localName, string? namespaceUri, decimal[] array, int offset, int count) { + if (Signing) + { + base.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + else { CheckArray(array, offset, count); if (count > 0) @@ -1394,6 +1437,11 @@ public override unsafe void WriteArray(string? prefix, string localName, string? public override unsafe void WriteArray(string? prefix, XmlDictionaryString localName, XmlDictionaryString? namespaceUri, decimal[] array, int offset, int count) { + if (Signing) + { + base.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + else { CheckArray(array, offset, count); if (count > 0) @@ -1409,26 +1457,34 @@ public override unsafe void WriteArray(string? prefix, XmlDictionaryString local // DateTime public override void WriteArray(string? prefix, string localName, string? namespaceUri, DateTime[] array, int offset, int count) { + if (Signing) + { + base.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + else { CheckArray(array, offset, count); if (count > 0) { WriteStartArray(prefix, localName, namespaceUri, count); _writer.WriteDateTimeArray(array, offset, count); - // WriteEndArray(); } } } public override void WriteArray(string? prefix, XmlDictionaryString localName, XmlDictionaryString? namespaceUri, DateTime[] array, int offset, int count) { + if (Signing) + { + base.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + else { CheckArray(array, offset, count); if (count > 0) { WriteStartArray(prefix, localName, namespaceUri, count); _writer.WriteDateTimeArray(array, offset, count); - // WriteEndArray(); } } } @@ -1436,26 +1492,34 @@ public override void WriteArray(string? prefix, XmlDictionaryString localName, X // Guid public override void WriteArray(string? prefix, string localName, string? namespaceUri, Guid[] array, int offset, int count) { + if (Signing) + { + base.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + else { CheckArray(array, offset, count); if (count > 0) { WriteStartArray(prefix, localName, namespaceUri, count); _writer.WriteGuidArray(array, offset, count); - // WriteEndArray(); } } } public override void WriteArray(string? prefix, XmlDictionaryString localName, XmlDictionaryString? namespaceUri, Guid[] array, int offset, int count) { + if (Signing) + { + base.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + else { CheckArray(array, offset, count); if (count > 0) { WriteStartArray(prefix, localName, namespaceUri, count); _writer.WriteGuidArray(array, offset, count); - // WriteEndArray(); } } } @@ -1463,26 +1527,34 @@ public override void WriteArray(string? prefix, XmlDictionaryString localName, X // TimeSpan public override void WriteArray(string? prefix, string localName, string? namespaceUri, TimeSpan[] array, int offset, int count) { + if (Signing) + { + base.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + else { CheckArray(array, offset, count); if (count > 0) { WriteStartArray(prefix, localName, namespaceUri, count); _writer.WriteTimeSpanArray(array, offset, count); - // WriteEndArray(); } } } public override void WriteArray(string? prefix, XmlDictionaryString localName, XmlDictionaryString? namespaceUri, TimeSpan[] array, int offset, int count) { + if (Signing) + { + base.WriteArray(prefix, localName, namespaceUri, array, offset, count); + } + else { CheckArray(array, offset, count); if (count > 0) { WriteStartArray(prefix, localName, namespaceUri, count); _writer.WriteTimeSpanArray(array, offset, count); - // WriteEndArray(); } } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBufferReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBufferReader.cs index fab4fb8531c1c..2ad5b6cdcabc9 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBufferReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBufferReader.cs @@ -12,6 +12,7 @@ using System.Runtime.Serialization; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Buffers.Binary; namespace System.Xml { @@ -210,13 +211,14 @@ private bool TryEnsureBytes(int count) if (_stream == null) return false; + DiagnosticUtility.DebugAssert(_offset <= int.MaxValue - count, ""); + // The data could be coming from an untrusted source, so we use a standard // "multiply by 2" growth algorithm to avoid overly large memory utilization. // Constant value of 256 comes from MemoryStream implementation. do { - DiagnosticUtility.DebugAssert(_offset <= int.MaxValue - count, ""); int newOffsetMax = _offset + count; if (newOffsetMax <= _offsetMax) return true; @@ -427,16 +429,19 @@ public unsafe double ReadDouble() return value; } - public unsafe decimal ReadDecimal() + public decimal ReadDecimal() { - int offset; - byte[] buffer = GetBuffer(ValueHandleLength.Decimal, out offset); - decimal value; - byte* pb = (byte*)&value; - for (int i = 0; i < sizeof(decimal); i++) - pb[i] = buffer[offset + i]; - Advance(ValueHandleLength.Decimal); - return value; + byte[] buffer = GetBuffer(ValueHandleLength.Decimal, out int offset); + ReadOnlySpan bytes = buffer.AsSpan(offset, sizeof(decimal)); + ReadOnlySpan span = stackalloc int[4] + { + BinaryPrimitives.ReadInt32LittleEndian(bytes), + BinaryPrimitives.ReadInt32LittleEndian(bytes.Slice(4)), + BinaryPrimitives.ReadInt32LittleEndian(bytes.Slice(8)), + BinaryPrimitives.ReadInt32LittleEndian(bytes.Slice(12)) + }; + + return new decimal(span); } public UniqueId ReadUniqueId() @@ -680,6 +685,13 @@ public string GetEscapedString(int offset, int length) return new string(chars, 0, charCount); } + public string GetEscapedString(int offset, int length, XmlNameTable nameTable) + { + char[] chars = GetCharBuffer(length); + int charCount = GetEscapedChars(offset, length, chars); + return nameTable.Add(chars, 0, charCount); + } + private int GetLessThanCharEntity(int offset, int length) { byte[] buffer = _buffer; @@ -1059,14 +1071,18 @@ public unsafe double GetDouble(int offset) return value; } - public unsafe decimal GetDecimal(int offset) + public decimal GetDecimal(int offset) { - byte[] buffer = _buffer; - decimal value; - byte* pb = (byte*)&value; - for (int i = 0; i < sizeof(decimal); i++) - pb[i] = buffer[offset + i]; - return value; + ReadOnlySpan bytes = _buffer.AsSpan(offset, sizeof(decimal)); + ReadOnlySpan span = stackalloc int[4] + { + BinaryPrimitives.ReadInt32LittleEndian(bytes), + BinaryPrimitives.ReadInt32LittleEndian(bytes.Slice(4)), + BinaryPrimitives.ReadInt32LittleEndian(bytes.Slice(8)), + BinaryPrimitives.ReadInt32LittleEndian(bytes.Slice(12)) + }; + + return new decimal(span); } public UniqueId GetUniqueId(int offset) @@ -1132,9 +1148,11 @@ public XmlDictionaryString GetDictionaryString(int key) { keyDictionary = _dictionary!; } + XmlDictionaryString? s; if (!keyDictionary.TryLookup(key >> 1, out s)) XmlExceptionHelper.ThrowInvalidBinaryFormat(_reader); + return s; } @@ -1165,6 +1183,7 @@ public int ReadDictionaryKey() XmlExceptionHelper.ThrowXmlDictionaryStringIDUndefinedStatic(_reader, staticKey); } } + return key; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlCanonicalWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlCanonicalWriter.cs index 7ebc16de436f6..8f682f1d98e36 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlCanonicalWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlCanonicalWriter.cs @@ -129,7 +129,8 @@ public void Close() _inclusivePrefixes = null; } - public static void WriteDeclaration() + [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "This class is should roughly mirror the XmlNodeWriter API where this is an instance method.")] + public void WriteDeclaration() { } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlConverter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlConverter.cs index e50ec3865375e..e47b44cf49e4e 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlConverter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlConverter.cs @@ -318,7 +318,7 @@ public static ulong ToUInt64(string value) { try { - return ulong.Parse(value, NumberStyles.Any, NumberFormatInfo.InvariantInfo); + return ulong.Parse(value, NumberStyles.Integer, NumberFormatInfo.InvariantInfo); } catch (ArgumentException exception) { @@ -395,7 +395,6 @@ public static int ToChars(byte[] buffer, int offset, int count, char[] chars, in public static string ToString(double value) { return XmlConvert.ToString(value); } public static string ToString(decimal value) { return XmlConvert.ToString(value); } public static string ToString(TimeSpan value) { return XmlConvert.ToString(value); } - public static string ToString(UniqueId value) { return value.ToString(); } public static string ToString(Guid value) { return value.ToString(); } public static string ToString(ulong value) { return value.ToString(NumberFormatInfo.InvariantInfo); } @@ -795,7 +794,7 @@ private static int ToAsciiChars(string s, byte[] buffer, int offset) { for (int i = 0; i < s.Length; i++) { - Fx.Assert(s[i] < 128, ""); + DiagnosticUtility.DebugAssert(s[i] < 128, ""); buffer[offset++] = (byte)s[i]; } return s.Length; @@ -1139,11 +1138,11 @@ public static string StripWhitespace(string s) private static string Trim(string s) { int i; - for (i = 0; i < s.Length && IsWhitespace(s[i]); i++) - ; + for (i = 0; i < s.Length && IsWhitespace(s[i]); i++); + int j; - for (j = s.Length; j > 0 && IsWhitespace(s[j - 1]); j--) - ; + for (j = s.Length; j > 0 && IsWhitespace(s[j - 1]); j--); + if (i == 0 && j == s.Length) return s; else if (j == 0) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlDictionaryReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlDictionaryReader.cs index 92b5bb6c960d2..141f572e24bea 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlDictionaryReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlDictionaryReader.cs @@ -358,6 +358,9 @@ internal byte[] ReadContentAsBase64(int maxByteArrayContentLength, int maxInitia int length; if (TryGetBase64ContentLength(out length)) { + if (length > maxByteArrayContentLength) + XmlExceptionHelper.ThrowMaxArrayLengthExceeded(this, maxByteArrayContentLength); + if (length <= maxInitialCount) { byte[] buffer = new byte[length]; @@ -522,6 +525,8 @@ private byte[] ReadContentAsBytes(bool base64, int maxByteArrayContentLength) break; read += actual; } + if (totalRead > maxByteArrayContentLength - read) + XmlExceptionHelper.ThrowMaxArrayLengthExceeded(this, maxByteArrayContentLength); totalRead += read; if (read < buffer.Length) break; @@ -1497,6 +1502,13 @@ public override string Prefix } } + public override char QuoteChar + { + get + { + return _reader.QuoteChar; + } + } public override bool Read() { @@ -1508,6 +1520,15 @@ public override bool ReadAttributeValue() return _reader.ReadAttributeValue(); } + public override string ReadElementString(string name) + { + return _reader.ReadElementString(name); + } + + public override string ReadElementString(string localName, string namespaceUri) + { + return _reader.ReadElementString(localName, namespaceUri); + } public override string ReadInnerXml() { @@ -1534,6 +1555,11 @@ public override void ReadEndElement() _reader.ReadEndElement(); } + public override string ReadString() + { + return _reader.ReadString(); + } + public override ReadState ReadState { get diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlDictionaryWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlDictionaryWriter.cs index b39afc2bea8ab..5fb9823249492 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlDictionaryWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlDictionaryWriter.cs @@ -251,7 +251,7 @@ private void WriteElementNode(XmlDictionaryReader reader, bool defattr) { WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI); } - if (defattr || !reader.IsDefault) + if (defattr || (!reader.IsDefault && (reader.SchemaInfo == null || !reader.SchemaInfo.IsDefault))) { if (reader.MoveToFirstAttribute()) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlExceptionHelper.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlExceptionHelper.cs index 3d6cc5cb60655..7170d045183cf 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlExceptionHelper.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlExceptionHelper.cs @@ -142,6 +142,12 @@ public static void ThrowMaxArrayLengthExceeded(XmlDictionaryReader reader, int m ThrowXmlException(reader, SR.XmlMaxArrayLengthExceeded, maxArrayLength.ToString(NumberFormatInfo.CurrentInfo)); } + [DoesNotReturn] + public static void ThrowMaxArrayLengthOrMaxItemsQuotaExceeded(XmlDictionaryReader reader, int maxQuota) + { + ThrowXmlException(reader, SR.XmlMaxArrayLengthOrMaxItemsQuotaExceeded, maxQuota.ToString(NumberFormatInfo.CurrentInfo)); + } + [DoesNotReturn] public static void ThrowMaxBytesPerReadExceeded(XmlDictionaryReader reader, int maxBytesPerRead) { @@ -160,6 +166,12 @@ public static void ThrowMaxStringContentLengthExceeded(XmlDictionaryReader reade ThrowXmlException(reader, SR.XmlMaxStringContentLengthExceeded, maxStringContentLength.ToString(NumberFormatInfo.CurrentInfo)); } + [DoesNotReturn] + public static void ThrowMaxNameTableCharCountExceeded(XmlDictionaryReader reader, int maxNameTableCharCount) + { + ThrowXmlException(reader, SR.XmlMaxNameTableCharCountExceeded, maxNameTableCharCount.ToString(NumberFormatInfo.CurrentInfo)); + } + [DoesNotReturn] public static void ThrowBase64DataExpected(XmlDictionaryReader reader) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlSigningNodeWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlSigningNodeWriter.cs index 7fb89ae6c825d..9f24a0fc8f756 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlSigningNodeWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlSigningNodeWriter.cs @@ -64,7 +64,7 @@ public override void Close() public override void WriteDeclaration() { _writer.WriteDeclaration(); - XmlCanonicalWriter.WriteDeclaration(); + _signingWriter.WriteDeclaration(); } public override void WriteComment(string text) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlStreamNodeWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlStreamNodeWriter.cs index 6075d0a9c608e..a62023e03d397 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlStreamNodeWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlStreamNodeWriter.cs @@ -29,7 +29,22 @@ protected void SetOutput(Stream stream, bool ownsStream, Encoding? encoding) _stream = stream; _ownsStream = ownsStream; _offset = 0; - _encoding = encoding; + + if (encoding != null) + _encoding = encoding; + } + + // Getting/Setting the Stream exists for fragmenting + public Stream Stream + { + get + { + return _stream; + } + set + { + _stream = value; + } } // StreamBuffer/BufferOffset exists only for the BinaryWriter to fix up nodes @@ -56,18 +71,6 @@ public int Position } } - private int GetByteCount(char[] chars) - { - if (_encoding == null) - { - return s_UTF8Encoding.GetByteCount(chars); - } - else - { - return _encoding.GetByteCount(chars); - } - } - protected byte[] GetBuffer(int count, out int offset) { DiagnosticUtility.DebugAssert(count >= 0 && count <= bufferLength, ""); @@ -369,12 +372,7 @@ protected unsafe int UnsafeGetUTF8Length(char* chars, int charCount) if (chars == charsMax) return charCount; - char[] chArray = new char[charsMax - chars]; - for (int i = 0; i < chArray.Length; i++) - { - chArray[i] = chars[i]; - } - return (int)(chars - (charsMax - charCount)) + GetByteCount(chArray); + return (int)(chars - (charsMax - charCount)) + (_encoding ?? s_UTF8Encoding).GetByteCount(chars, (int)(charsMax - chars)); } protected unsafe int UnsafeGetUTF8Chars(char* chars, int charCount, byte[] buffer, int offset) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlUTF8TextWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlUTF8TextWriter.cs index 2a1314d1a8792..16b9b3d61bd7f 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlUTF8TextWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlUTF8TextWriter.cs @@ -14,7 +14,7 @@ public interface IXmlTextWriterInitializer internal sealed class XmlUTF8TextWriter : XmlBaseWriter, IXmlTextWriterInitializer { - private XmlUTF8NodeWriter? _writer; + private XmlUTF8NodeWriter _writer = null!; // initialized in SetOutput public void SetOutput(Stream stream, Encoding encoding, bool ownsStream) { @@ -31,6 +31,15 @@ public void SetOutput(Stream stream, Encoding encoding, bool ownsStream) SetOutput(_writer); } + public override bool CanFragment + { + get + { + // Fragmenting only works for utf8 + return _writer.Encoding == null; + } + } + protected override XmlSigningNodeWriter CreateSigningNodeWriter() { return new XmlSigningNodeWriter(true); @@ -94,6 +103,14 @@ public XmlUTF8NodeWriter(bool[] isEscapedAttributeChar, bool[] isEscapedElementC _inAttribute = false; } + public Encoding? Encoding + { + get + { + return _encoding; + } + } + private byte[] GetCharEntityBuffer() => _entityChars ??= new byte[maxEntityLength]; private char[] GetCharBuffer(int charCount) @@ -686,7 +703,7 @@ public override void WriteUInt64Text(ulong value) { int offset; byte[] buffer = GetBuffer(XmlConverter.MaxUInt64Chars, out offset); - Advance(XmlConverter.ToChars((double)value, buffer, offset)); + Advance(XmlConverter.ToChars(value, buffer, offset)); } public override void WriteGuidText(Guid value) diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/DataContractSerializer.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/DataContractSerializer.cs index a2ada3daf1e30..a6fb375e8ad21 100644 --- a/src/libraries/System.Runtime.Serialization.Xml/tests/DataContractSerializer.cs +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/DataContractSerializer.cs @@ -3867,6 +3867,135 @@ public static void DCS_BasicPerSerializerRoundTripAndCompare_EnumStruct_NotNetFr #endregion + [Fact] + public static void DCS_KnownSerializableTypes_KeyValuePair_2() + { + KeyValuePair kvp = new KeyValuePair("the_key", 42); + Assert.StrictEqual(kvp, DataContractSerializerHelper.SerializeAndDeserialize>(kvp, "the_key42")); + } + + [Fact] + public static void DCS_KnownSerializableTypes_Queue_1() + { + Queue q = new Queue(); + q.Enqueue("first"); + q.Enqueue("second"); + Queue q2 = DataContractSerializerHelper.SerializeAndDeserialize>(q, "<_array xmlns:a=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">firstsecond<_head>0<_size>2<_tail>2<_version>3"); + Assert.Equal(q, q2); + Assert.StrictEqual(q.Count, q2.Count); + Assert.Equal(q.Dequeue(), q2.Dequeue()); + Assert.Equal(q.Dequeue(), q2.Dequeue()); + } + + [Fact] + public static void DCS_KnownSerializableTypes_Stack_1() + { + Stack stk = new Stack(); + stk.Push("first"); + stk.Push("last"); + Stack result = DataContractSerializerHelper.SerializeAndDeserialize>(stk, "<_array xmlns:a=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">firstlast<_size>2<_version>2"); + Assert.Equal(stk, result); + Assert.StrictEqual(stk.Count, result.Count); + Assert.Equal(stk.Pop(), result.Pop()); + Assert.Equal(stk.Pop(), result.Pop()); + } + + [Fact] + public static void DCS_KnownSerializableTypes_ReadOnlyCollection_1() + { + ReadOnlyCollection roc = new ReadOnlyCollection(new string[] { "one", "two", "three", "four" }); + ReadOnlyCollection result = DataContractSerializerHelper.SerializeAndDeserialize>(roc, "onetwothreefour"); + Assert.Equal(roc, result); + Assert.StrictEqual(roc.Count, result.Count); + + for (int i = 0; i < roc.Count; i++) + Assert.Equal(roc[i], result[i]); + } + + [Fact] + public static void DCS_KnownSerializableTypes_ReadOnlyDictionary_2() + { + ReadOnlyDictionary rod = new ReadOnlyDictionary(new Dictionary { { "one", 1 }, { "two", 22 }, { "three", 333 }, { "four", 4444 } }); + ReadOnlyDictionary result = DataContractSerializerHelper.SerializeAndDeserialize>(rod, "one1two22three333four4444"); + Assert.Equal(rod, result); + Assert.StrictEqual(rod.Count, result.Count); + + foreach (var kvp in rod) + { + Assert.True(result.ContainsKey(kvp.Key)); + Assert.Equal(kvp.Value, result[kvp.Key]); + } + } + + [Fact] + public static void DCS_KnownSerializableTypes_Queue() + { + Queue q = new Queue(); + q.Enqueue("first"); + q.Enqueue("second"); + Queue q2 = DataContractSerializerHelper.SerializeAndDeserialize(q, "<_array xmlns:a=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">firstsecond<_growFactor>200<_head>0<_size>2<_tail>2<_version>2"); + Assert.Equal(q, q2); + Assert.StrictEqual(q.Count, q2.Count); + Assert.StrictEqual(q.Dequeue(), q2.Dequeue()); + Assert.StrictEqual(q.Dequeue(), q2.Dequeue()); + } + + [Fact] + public static void DCS_KnownSerializableTypes_Stack() + { + Stack stk = new Stack(); + stk.Push("first"); + stk.Push("last"); + Stack result = DataContractSerializerHelper.SerializeAndDeserialize(stk, "<_array xmlns:a=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">firstlast<_size>2<_version>2"); + Assert.Equal(stk, result); + Assert.StrictEqual(stk.Count, result.Count); + Assert.StrictEqual(stk.Pop(), result.Pop()); + Assert.StrictEqual(stk.Pop(), result.Pop()); + } + + [Fact] + [ActiveIssue("No issue filed yet. Turns out, CultureInfo is not serialzable, even if it is included in s_knownSerializableTypeInfos")] + public static void DCS_KnownSerializableTypes_CultureInfo() + { + CultureInfo ci = new CultureInfo("pl"); + Assert.StrictEqual(ci, DataContractSerializerHelper.SerializeAndDeserialize(ci, "", null, null, true)); + } + + [Fact] + public static void DCS_KnownSerializableTypes_Version() + { + Version ver = new Version(5, 4, 3); + Assert.StrictEqual(ver, DataContractSerializerHelper.SerializeAndDeserialize(ver, "<_Build>3<_Major>5<_Minor>4<_Revision>-1")); + } + + [Fact] + public static void DCS_KnownSerializableTypes_Tuples() + { + Tuple t1 = new Tuple("first"); + Assert.StrictEqual(t1, DataContractSerializerHelper.SerializeAndDeserialize>(t1, "first")); + + Tuple t2 = new Tuple("first", "second"); + Assert.StrictEqual(t2, DataContractSerializerHelper.SerializeAndDeserialize>(t2, "firstsecond")); + + Tuple t3 = new Tuple("first", "second", "third"); + Assert.StrictEqual(t3, DataContractSerializerHelper.SerializeAndDeserialize>(t3, "firstsecondthird")); + + Tuple t4 = new Tuple("first", "second", "third", "fourth"); + Assert.StrictEqual(t4, DataContractSerializerHelper.SerializeAndDeserialize>(t4, "firstsecondthirdfourth")); + + Tuple t5 = new Tuple("first", "second", "third", "fourth", "fifth"); + Assert.StrictEqual(t5, DataContractSerializerHelper.SerializeAndDeserialize>(t5, "firstsecondthirdfourthfifth")); + + Tuple t6 = new Tuple("first", "second", "third", "fourth", "fifth", "sixth"); + Assert.StrictEqual(t6, DataContractSerializerHelper.SerializeAndDeserialize>(t6, "firstsecondthirdfourthfifthsixth")); + + Tuple t7 = new Tuple("first", "second", "third", "fourth", "fifth", "sixth", "seventh"); + Assert.StrictEqual(t7, DataContractSerializerHelper.SerializeAndDeserialize>(t7, "firstsecondthirdfourthfifthsixthseventh")); + + Tuple> t8 = new Tuple>("first", "second", "third", "fourth", "fifth", "sixth", "seventh", new Tuple(8, 9, "tenth")); + Assert.StrictEqual(t8, DataContractSerializerHelper.SerializeAndDeserialize>>(t8, "firstsecondthirdfourthfifthsixthseventh89tenth")); + } + [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/60462", TestPlatforms.iOS | TestPlatforms.tvOS)] public static void DCS_TypeWithVirtualGenericProperty() From 335adfe93e38b1b5cbe011f731b7532212947ae4 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Sun, 3 Jul 2022 14:04:35 -0700 Subject: [PATCH 03/33] External DCS Schema support groundwork. Before DC-tree work and other public APIs. --- .../src/Resources/Strings.resx | 1548 +++++++++++++ .../Serialization/ClassDataContract.cs | 76 +- .../Serialization/CollectionDataContract.cs | 47 + .../Runtime/Serialization/DataContract.cs | 38 + .../Serialization/DataContractSerializer.cs | 8 +- .../Runtime/Serialization/DataContractSet.cs | 320 ++- .../DataContractSurrogateCaller.cs | 27 +- .../Runtime/Serialization/DataMember.cs | 29 + .../Runtime/Serialization/EnumDataContract.cs | 5 + .../GenericParameterDataContract.cs | 6 + .../System/Runtime/Serialization/Globals.cs | 12 + .../Runtime/Serialization/SchemaExporter.cs | 28 +- .../Runtime/Serialization/SchemaHelper.cs | 103 + .../Runtime/Serialization/SchemaImporter.cs | 1471 ++++++++++++ ...System.Runtime.Serialization.Primitives.cs | 9 + ...em.Runtime.Serialization.Primitives.csproj | 1 + ...ISerializationExtendedSurrogateProvider.cs | 16 + .../Directory.Build.props | 7 + .../System.Runtime.Serialization.Schema.sln | 51 + .../System.Runtime.Serialization.Schema.cs | 9 + ...System.Runtime.Serialization.Schema.csproj | 9 + .../src/Resources/Strings.resx | 1534 +++++++++++++ ...System.Runtime.Serialization.Schema.csproj | 52 + .../Serialization/Schema/CodeExporter.cs | 2044 +++++++++++++++++ .../Schema/ContractCodeDomInfo.cs | 54 + .../Serialization/Schema/DiagnosticUtility.cs | 115 + .../Serialization/Schema/ExportOptions.cs | 23 + .../Runtime/Serialization/Schema/Globals.cs | 614 +++++ .../Serialization/Schema/ImportOptions.cs | 38 + .../Serialization/Schema/SchemaHelper.cs | 36 + .../Schema/XsdDataContractExporter.cs | 342 +++ .../Schema/XsdDataContractImporter.cs | 309 +++ .../Runtime/Serialization/Schema/_Stubs.cs | 167 ++ ....Runtime.Serialization.Schema.Tests.csproj | 12 + .../Runtime/Serialization/Schema/Importer.cs | 16 + src/libraries/oob.proj | 1 + src/libraries/tests.proj | 1 + 37 files changed, 9162 insertions(+), 16 deletions(-) create mode 100644 src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs create mode 100644 src/libraries/System.Runtime.Serialization.Primitives/src/System/Runtime/Serialization/ISerializationExtendedSurrogateProvider.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/Directory.Build.props create mode 100644 src/libraries/System.Runtime.Serialization.Schema/System.Runtime.Serialization.Schema.sln create mode 100644 src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.csproj create mode 100644 src/libraries/System.Runtime.Serialization.Schema/src/Resources/Strings.resx create mode 100644 src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj create mode 100644 src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/DiagnosticUtility.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ExportOptions.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/Globals.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ImportOptions.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaHelper.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/_Stubs.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/tests/System.Runtime.Serialization.Schema.Tests.csproj create mode 100644 src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Importer.cs diff --git a/src/libraries/System.Private.DataContractSerialization/src/Resources/Strings.resx b/src/libraries/System.Private.DataContractSerialization/src/Resources/Strings.resx index 985893b4ac42b..cefa459d78bde 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/Resources/Strings.resx +++ b/src/libraries/System.Private.DataContractSerialization/src/Resources/Strings.resx @@ -1176,4 +1176,1552 @@ Unknown Type for null value + + List of referenced types contains more than one type with same data contract name. Need to exclude all but one of the following types. Only matching types can be valid references: {0} + + + List of referenced types contains more than one type with data contract name '{0}' in namespace '{1}'. Need to exclude all but one of the following types. Only matching types can be valid references: {2} + + + List of referenced collection types contains more than one type with same data contract name. Include only one of the following types. Only matching types can be valid references: {0} + + + List of referenced collection types contains more than one type with data contract name '{0}' in namespace '{1}'. Include only one of the following types. Only matching types can be valid references: {2} + + + ReferencedCollectionTypes specified via ImportOptions must contain valid types. Cannot contain null. + + + (matching) + + + (not matching) + + + ReferencedTypes specified via ImportOptions must contain valid types. Cannot contain null. + + + Using surrogates with get-only collection properties is not supported. Consider removing the surrogate associated with '{0}' or adding a setter to '{1}.{2}'. + + + + + The element cannot have 'abstract' set to 'true'. + + + The type cannot have 'abstract' set to 'true'. + + + Invalid '{0}' annotation in type '{1}' from namespace '{2}'. Attribute '{3}' not present. + + + Anonymous type in element '{0}' from namespace '{1}' is not supported. + + + 'anyAttribute' is not supported. + + + Form for element '{0}' must be qualified. + + + Array type '{0}' in namespace '{1}' cannot be imported. {2} + + + One of its base types, '{0}' from namespace '{1}' is not ISerializable. + + + A unique name cannot be computed for '{0}' because there are already Int32.MaxValue types of with the same name. + + + The type contains two attributes with the same name '{0}'. Multiple attributes with the same name in one type are not supported. + + + The type contains two elements with the same name '{0}'. Multiple elements with the same name in one type are not supported because members marked with DataMemberAttribute attribute must have unique names. + + + Cannot import invalid schemas. Compilation on the XmlSchemaSet failed. + + + Cannot import type for null XmlQualifiedName specified via parameter. + + + Cannot import null XmlSchema contained in XmlSchemaSet specified via parameter. + + + An internal error has occurred. Could not load serialization schema. Consider providing schema with namespace '{0}'. + + + Default value on element '{0}' is not supported. + + + It is not ISerializable but its base type '{0}' in namespace '{1}' is ISerializable. + + + 'maxOccurs' on element '{0}' must be 1. + + + 'minOccurs' on element '{0}' must be 0 or 1. + + + Ref to element '{0}' in '{1}' namespace is not supported. + + + Enumeration facets without 'value' are not supported. + + + Anonymous type with <list> cannot be used to create Flags enumeration because it is not a valid enum type. + + + Simple type list must contain an anonymous type specifying enumeration facets. + + + Facets other than enumeration facets are not supported. + + + Anonymous type with <restriction> cannot be used to create Flags enumeration because it is not a valid enum type. + + + Enum type '{0}' in namespace '{1}' cannot be imported. {2} + + + Anonymous type with <union>. cannot be used to create Flags enumeration because it is not a valid enum type. + + + Fixed value on element '{0}' is not supported. + + + Form on element '{0}' must be qualified. + + + Annotation for generic type '{0}' did not have attribute '{1}'. + + + Nested level on annotation elements '{0}' from namespace '{1}' for generic type '{2}' must be in increasing order. + + + Annotation element '{0}' from namespace '{1}' for generic type '{2}' has an invalid value '{3}' for attribute '{4}'. Expecting value to be of type '{5}'. + + + Annotation for generic type '{2}' has an invalid element '{0}' from namespace '{1}'. + + + Annotation '{0}' from namespace '{1}' has an invalid element '{2}' from namespace '{3}'. Expecting text. + + + Type '{0}' in namespace '{1}' cannot be used as the base type of a data contract type, because it itself does not have a data contract. Consider marking type '{0}' with the DataContractAttribute attribute. + + + Annotation for element {0} in type {1} from namespace {2} specifies EmitDefaultValue as 'true'. This requires the element to be either nillable or the element's type must be a value type. + + + Cannot import type '{0}' in namespace '{1}' as its base type because derived type is ISerializable but the base type is not ISerializable. + + + It is an invalid dictionary type. Element '{0}' must reference a complex type containing a sequence with two required elements. Either fix the schema or remove the IsDictionary annotation. + + + It is an invalid dictionary type since element '{0}' references a type from a different namespace '{1}'. Either fix the schema or remove the IsDictionary annotation. + + + '{0}' is an invalid value for IsDictionary annotation. {1} + + + '{0}' is an invalid value for IsValueType annotation. {1} + + + Its root sequence contains more than one particle. + + + Derived ISerializable types cannot contain any particles. + + + It does not contain root sequence with a wildcard element <any>. + + + It does not reference attribute '{0}' from namespace '{1}'. + + + ISerializable type '{0}' in namespace '{1}' cannot be imported. '{2}' + + + 'maxOccurs' on the wildcard element must be '{0}'. + + + 'minOccurs' on the wildcard element must be '{0}'. + + + Namespace on the wildcard element must be '{0}'. + + + ProcessContents on the wildcard element must be '{0}'. + + + Complex type with mixed content is not supported. + + + The root sequence must contain only local elements. Group ref, choice, any and nested sequences are not supported. + + + Redefine is not supported. + + + The root particle must be a sequence. + + + 'maxOccurs' on the root sequence must be 1. + + + 'minOccurs' on the root sequence must be 1. + + + Complex types with simple content extension are not supported. + + + Simple type restriction must specify a base type. + + + =Simple types with <union> content are not supported. + + + Invalid type specified. Type with name '{0}' not found in schema with namespace '{1}'. + + + Substitution group on element '{0}' is not supported. + + + The global element found in the schema with same name references a different type '{0}' in namespace '{1}'. Data contract types must have the same name as their root element name. Consider removing the global element or changing its type. + + + Type '{0}' in namespace '{1}' cannot be imported. {2} + + + {0} Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer. + + + Attributes must be optional and from namespace '{0}'. + + + + + diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs index 47c525eed133f..23122a250f330 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs @@ -62,11 +62,13 @@ private void InitClassDataContract() internal ClassDataContract? BaseContract { get { return _helper.BaseContract; } + set { _helper.BaseContract = value; } } internal List? Members { get { return _helper.Members; } + set { _helper.Members = value; } } public XmlDictionaryString?[]? ChildElementNamespaces @@ -123,6 +125,7 @@ internal override DataContractDictionary? KnownDataContracts { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get { return _helper.KnownDataContracts; } + set { _helper.KnownDataContracts = value; } } internal override bool IsISerializable @@ -173,7 +176,7 @@ internal bool IsReadOnlyContract internal bool CreateNewInstanceViaDefaultConstructor([NotNullWhen(true)] out object? obj) { ConstructorInfo? ci = GetNonAttributedTypeConstructor(); - if (ci == null) + if (ci == null || UnderlyingType == Globals.TypeOfSchemaTypePlaceholder) { obj = null; return false; @@ -195,6 +198,7 @@ internal bool CreateNewInstanceViaDefaultConstructor([NotNullWhen(true)] out obj [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private XmlFormatClassWriterDelegate CreateXmlFormatWriterDelegate() { + Debug.Assert(UnderlyingType != Globals.TypeOfSchemaTypePlaceholder); return new XmlFormatWriterGenerator().GenerateClassWriter(this); } @@ -222,6 +226,7 @@ internal XmlFormatClassWriterDelegate XmlFormatWriterDelegate [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private XmlFormatClassReaderDelegate CreateXmlFormatReaderDelegate() { + Debug.Assert(UnderlyingType != Globals.TypeOfSchemaTypePlaceholder); return new XmlFormatReaderGenerator().GenerateClassReader(this); } @@ -1162,6 +1167,7 @@ internal ClassDataContract? BaseContract internal List? Members { get { return _members; } + set { _members = value; } } internal MethodInfo? OnSerializing @@ -1353,6 +1359,74 @@ public int Compare(Member x, Member y) } } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) + { + Type type = UnderlyingType; + if (!type.IsGenericType || !type.ContainsGenericParameters) + return this; + + lock (this) + { + DataContract? boundContract; + if (boundContracts.TryGetValue(this, out boundContract)) + return boundContract; + + XmlQualifiedName stableName; + object[] genericParams; + Type boundType; + if (type.IsGenericTypeDefinition) + { + stableName = this.StableName; + genericParams = paramContracts; + + // NOTE TODO smolloy - this type-binding ('boundType') stuff is new. We did not do this in NetFx. We used to use default constructors. But default + // constructors for DataContracts runs afoul of requiring an underlying type. Our web of nullable notations make it hard to get around. + // But it also allows us to feel good about using .UnderlyingType from matching parameter contracts. + Type[] underlyingParamTypes = new Type[paramContracts.Length]; + for (int i = 0; i < paramContracts.Length; i++) + underlyingParamTypes[i] = paramContracts[i].UnderlyingType; + boundType = type.MakeGenericType(underlyingParamTypes); + } + else + { + //partial Generic: Construct stable name from its open generic type definition + stableName = DataContract.GetStableName(type.GetGenericTypeDefinition()); + Type[] paramTypes = type.GetGenericArguments(); + genericParams = new object[paramTypes.Length]; + for (int i = 0; i < paramTypes.Length; i++) + { + Type paramType = paramTypes[i]; + if (paramType.IsGenericParameter) + { + genericParams[i] = paramContracts[paramType.GenericParameterPosition]; + paramTypes[i] = paramContracts[paramType.GenericParameterPosition].UnderlyingType; + } + else + { + genericParams[i] = paramType; + } + } + boundType = type.MakeGenericType(paramTypes); + } + ClassDataContract boundClassContract = new ClassDataContract(boundType); + boundContracts.Add(this, boundClassContract); + boundClassContract.StableName = CreateQualifiedName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(stableName.Name), new GenericNameProvider(DataContract.GetClrTypeFullName(this.UnderlyingType), genericParams)), stableName.Namespace); + if (BaseContract != null) + boundClassContract.BaseContract = (ClassDataContract)BaseContract.BindGenericParameters(paramContracts, boundContracts); + boundClassContract.IsISerializable = this.IsISerializable; + boundClassContract.IsValueType = this.IsValueType; + boundClassContract.IsReference = this.IsReference; + if (Members != null) + { + boundClassContract.Members = new List(Members.Count); + foreach (DataMember member in Members) + boundClassContract.Members.Add(member.BindGenericParameters(paramContracts, boundContracts)); + } + return boundClassContract; + } + } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal override bool Equals(object? other, HashSet checkedContracts) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs index 791d592fdb20c..9210091ed38fa 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs @@ -97,6 +97,12 @@ internal CollectionDataContract(Type type, DataContract itemContract) : base(new InitCollectionDataContract(this); } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal CollectionDataContract(Type type, CollectionKind kind) : base(new CollectionDataContractCriticalHelper(type, kind)) + { + InitCollectionDataContract(this); + } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private CollectionDataContract(Type type, CollectionKind kind, Type itemType, MethodInfo getEnumeratorMethod, string? serializationExceptionMessage, string? deserializationExceptionMessage) : base(new CollectionDataContractCriticalHelper(type, kind, itemType, getEnumeratorMethod, serializationExceptionMessage, deserializationExceptionMessage)) @@ -548,6 +554,16 @@ internal CollectionDataContractCriticalHelper( Init(CollectionKind.Array, type.GetElementType(), null); } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal CollectionDataContractCriticalHelper( + [DynamicallyAccessedMembers(ClassDataContract.DataContractPreserveMemberTypes)] + Type type, + CollectionKind kind) : base(type) + { + StableName = DataContract.GetStableName(type); // TODO smolloy - Not sure how much sense this makes with a dummy type + Init(kind, type.GetElementType(), null); + } + // array [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal CollectionDataContractCriticalHelper( @@ -1382,6 +1398,37 @@ private static bool IsKnownInterface(Type type) return false; } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) + { + DataContract boundContract; + if (boundContracts.TryGetValue(this, out boundContract!)) + return boundContract; + + // NOTE TODO smolloy - this type-binding ('boundType') stuff is new. We did not do this in NetFx. We used to use default constructors. But default + // constructors for DataContracts runs afoul of requiring an underlying type. Our web of nullable notations make it hard to get around. + // But it also allows us to feel good about using .UnderlyingType from matching parameter contracts. + Type type = UnderlyingType; + Type[] paramTypes = type.GetGenericArguments(); + for (int i = 0; i < paramTypes.Length; i++) + { + if (paramTypes[i].IsGenericParameter) + paramTypes[i] = paramContracts[paramTypes[i].GenericParameterPosition].UnderlyingType; + } + Type boundType = type.MakeGenericType(paramTypes); + + CollectionDataContract boundCollectionContract = new CollectionDataContract(boundType); + boundContracts.Add(this, boundCollectionContract); + boundCollectionContract.ItemContract = this.ItemContract.BindGenericParameters(paramContracts, boundContracts); + boundCollectionContract.IsItemTypeNullable = !boundCollectionContract.ItemContract.IsValueType; + boundCollectionContract.ItemName = ItemNameSetExplicit ? this.ItemName : boundCollectionContract.ItemContract.StableName.Name; + boundCollectionContract.KeyName = this.KeyName; + boundCollectionContract.ValueName = this.ValueName; + boundCollectionContract.StableName = CreateQualifiedName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(this.StableName.Name), new GenericNameProvider(DataContract.GetClrTypeFullName(this.UnderlyingType), paramContracts)), + IsCollectionDataContract(UnderlyingType) ? this.StableName.Namespace : DataContract.GetCollectionNamespace(boundCollectionContract.ItemContract.StableName.Namespace)); + return boundCollectionContract; + } + internal override DataContract GetValidContract(bool verifyConstructor = false) { if (verifyConstructor && this.IsConstructorCheckRequired) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs index 8d8b231b6bb77..5f814135aa89b 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs @@ -212,6 +212,16 @@ internal XmlQualifiedName StableName { _helper.StableName = value; } } + internal GenericInfo? GenericInfo + { + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + get + { return _helper.GenericInfo; } + + set + { _helper.GenericInfo = value; } + } + internal virtual DataContractDictionary? KnownDataContracts { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -286,6 +296,12 @@ internal virtual void WriteRootElement(XmlWriterDelegator writer, XmlDictionaryS writer.WriteStartElement(name, ns); } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal virtual DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) + { + return this; + } + internal virtual DataContract GetValidContract(bool verifyConstructor = false) { return this; @@ -1494,6 +1510,26 @@ internal static string GetCollectionNamespace(string elementNs) return IsBuiltInNamespace(elementNs) ? Globals.CollectionsNamespace : elementNs; } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal XmlQualifiedName GetArrayTypeName(bool isNullable) + { + XmlQualifiedName itemName; + if (this.IsValueType && isNullable) + { + GenericInfo genericInfo = new GenericInfo(DataContract.GetStableName(Globals.TypeOfNullable), Globals.TypeOfNullable.FullName!); + genericInfo.Add(new GenericInfo(this.StableName, null)); + genericInfo.AddToLevel(0, 1); + itemName = genericInfo.GetExpandedStableName(); + } + else + { + itemName = this.StableName; + } + string ns = GetCollectionNamespace(itemName.Namespace); + string name = Globals.ArrayPrefix + itemName.Name; + return new XmlQualifiedName(name, ns); + } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal static XmlQualifiedName GetDefaultStableName(Type type) { @@ -2376,6 +2412,8 @@ private XmlQualifiedName GetStableName(int i) } } + // TODO smolloy - This class looks like it came back in the re-alignment... but much of it is unused in-box. After reworking schema + // import/export, check back on this and see if there are still unused methods that can go away. internal sealed class GenericInfo : IGenericNameProvider { private string? _genericTypeName; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs index 6db625cc1cd67..354f6fd8d09a9 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs @@ -71,9 +71,15 @@ public DataContractSerializer(Type type, string rootName, string rootNamespace) } public DataContractSerializer(Type type, string rootName, string rootNamespace, IEnumerable? knownTypes) + : this(type, rootName, rootNamespace, knownTypes, int.MaxValue, false, false) + { + } + + internal DataContractSerializer(Type type, string rootName, string rootNamespace, IEnumerable? knownTypes, int maxItemsInObjectGraph, + bool ignoreExtensionDataObject, bool preserveObjectReferences) { XmlDictionary dictionary = new XmlDictionary(2); - Initialize(type, dictionary.Add(rootName), dictionary.Add(DataContract.GetNamespace(rootNamespace)), knownTypes, int.MaxValue, false, false, null, false); + Initialize(type, dictionary.Add(rootName), dictionary.Add(DataContract.GetNamespace(rootNamespace)), knownTypes, int.MaxValue, ignoreExtensionDataObject, preserveObjectReferences, null, false); } public DataContractSerializer(Type type, XmlDictionaryString rootName, XmlDictionaryString rootNamespace) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs index 70f49a0a108cd..5056dc0f96289 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs @@ -4,9 +4,10 @@ using System.Xml; using System.Collections; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Text; + using DataContractDictionary = System.Collections.Generic.Dictionary; -using System.Diagnostics.CodeAnalysis; namespace System.Runtime.Serialization { @@ -14,8 +15,18 @@ internal sealed class DataContractSet { private Dictionary? _contracts; private Dictionary? _processedContracts; - private readonly ICollection _referencedTypes; - private readonly ICollection _referencedCollectionTypes; + private ISerializationExtendedSurrogateProvider? _extendedSurrogateProvider; + private Hashtable? _surrogateDataTable; + private DataContractDictionary? _knownTypesForObject; + private readonly ICollection? _referencedTypes; + private readonly ICollection? _referencedCollectionTypes; + + internal DataContractSet(ISerializationExtendedSurrogateProvider? dataContractExtendedSurrogate, ICollection? referencedTypes, ICollection? referencedCollectionTypes) + { + _referencedTypes = referencedTypes; + _referencedCollectionTypes = referencedCollectionTypes; + _extendedSurrogateProvider = dataContractExtendedSurrogate; + } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal DataContractSet(DataContractSet dataContractSet) @@ -24,6 +35,7 @@ internal DataContractSet(DataContractSet dataContractSet) _referencedTypes = dataContractSet._referencedTypes; _referencedCollectionTypes = dataContractSet._referencedCollectionTypes; + _extendedSurrogateProvider = dataContractSet._extendedSurrogateProvider; foreach (KeyValuePair pair in dataContractSet) { @@ -45,6 +57,14 @@ internal DataContractSet(DataContractSet dataContractSet) private Dictionary ProcessedContracts => _processedContracts ??= new Dictionary(); + private Hashtable SurrogateDataTable => _surrogateDataTable ??= new Hashtable(); + + internal DataContractDictionary? KnownTypesForObject + { + get { return _knownTypesForObject; } + set { _knownTypesForObject = value; } + } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal void Add(Type type) { @@ -124,6 +144,17 @@ private void AddClassDataContract(ClassDataContract classDataContract) { DataMember dataMember = classDataContract.Members[i]; DataContract memberDataContract = GetMemberTypeDataContract(dataMember); + + if (_extendedSurrogateProvider != null && dataMember.MemberInfo != null) + { + object? customData = DataContractSurrogateCaller.GetCustomDataToExport( + _extendedSurrogateProvider, + dataMember.MemberInfo, + memberDataContract.UnderlyingType); + if (customData != null) + SurrogateDataTable.Add(dataMember, customData); + } + Add(memberDataContract.StableName, memberDataContract); } } @@ -167,23 +198,55 @@ private void AddKnownDataContracts(DataContractDictionary? knownDataContracts) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static DataContract GetDataContract(Type clrType) + internal XmlQualifiedName GetStableName(Type clrType) { + if (_extendedSurrogateProvider != null) + { + Type dcType = DataContractSurrogateCaller.GetDataContractType(_extendedSurrogateProvider, clrType); + return DataContract.GetStableName(dcType); + } + return DataContract.GetStableName(clrType); + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal DataContract GetDataContract(Type clrType) + { + if (_extendedSurrogateProvider == null) + return DataContract.GetDataContract(clrType); + DataContract? dataContract = DataContract.GetBuiltInDataContract(clrType); if (dataContract != null) return dataContract; - Type dcType = clrType; + Type dcType = DataContractSurrogateCaller.GetDataContractType(_extendedSurrogateProvider, clrType); dataContract = DataContract.GetDataContract(dcType); + if (!SurrogateDataTable.Contains(dataContract)) + { + object? customData = DataContractSurrogateCaller.GetCustomDataToExport(_extendedSurrogateProvider, clrType, dcType); + if (customData != null) + SurrogateDataTable.Add(dataContract, customData); + } + return dataContract; } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static DataContract GetMemberTypeDataContract(DataMember dataMember) + internal DataContract GetMemberTypeDataContract(DataMember dataMember) { Type dataMemberType = dataMember.MemberType; if (dataMember.IsGetOnlyCollection) { + if (_extendedSurrogateProvider != null) + { + Type dcType = DataContractSurrogateCaller.GetDataContractType(_extendedSurrogateProvider, dataMemberType); + if (dcType != dataMemberType) + { + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.SurrogatesWithGetOnlyCollectionsNotSupported, + DataContract.GetClrTypeFullName(dataMemberType), + (dataMember.MemberInfo.DeclaringType != null) ? DataContract.GetClrTypeFullName(dataMember.MemberInfo.DeclaringType) : dataMember.MemberInfo.DeclaringType, + dataMember.MemberInfo.Name))); + } + } return DataContract.GetGetOnlyCollectionDataContract(DataContract.GetId(dataMemberType.TypeHandle), dataMemberType.TypeHandle, dataMemberType); } else @@ -193,13 +256,256 @@ internal static DataContract GetMemberTypeDataContract(DataMember dataMember) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static DataContract GetItemTypeDataContract(CollectionDataContract collectionContract) + internal DataContract GetItemTypeDataContract(CollectionDataContract collectionContract) { if (collectionContract.ItemType != null) return GetDataContract(collectionContract.ItemType); return collectionContract.ItemContract; } + internal DataContract? this[XmlQualifiedName key] + { + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + get + { + DataContract? dataContract = DataContract.GetBuiltInDataContract(key.Name, key.Namespace); + if (dataContract == null) + { + Contracts.TryGetValue(key, out dataContract); + } + return dataContract; + } + } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal bool Remove(XmlQualifiedName key) + { + if (DataContract.GetBuiltInDataContract(key.Name, key.Namespace) != null) + return false; + return Contracts.Remove(key); + } + + private Dictionary? _referencedTypesDictionary; + private Dictionary? _referencedCollectionTypesDictionary; + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private Dictionary GetReferencedTypes() + { + if (_referencedTypesDictionary == null) + { + _referencedTypesDictionary = new Dictionary(); + //Always include Nullable as referenced type + //Do not allow surrogating Nullable + _referencedTypesDictionary.Add(DataContract.GetStableName(Globals.TypeOfNullable), Globals.TypeOfNullable); + if (_referencedTypes != null) + { + foreach (Type type in _referencedTypes) + { + if (type == null) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.ReferencedTypesCannotContainNull))); + + AddReferencedType(_referencedTypesDictionary, type); + } + } + } + return _referencedTypesDictionary; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private Dictionary GetReferencedCollectionTypes() + { + if (_referencedCollectionTypesDictionary == null) + { + _referencedCollectionTypesDictionary = new Dictionary(); + if (_referencedCollectionTypes != null) + { + foreach (Type type in _referencedCollectionTypes) + { + if (type == null) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.ReferencedCollectionTypesCannotContainNull))); + AddReferencedType(_referencedCollectionTypesDictionary, type); + } + } + XmlQualifiedName genericDictionaryName = DataContract.GetStableName(Globals.TypeOfDictionaryGeneric); + if (!_referencedCollectionTypesDictionary.ContainsKey(genericDictionaryName) && GetReferencedTypes().ContainsKey(genericDictionaryName)) + AddReferencedType(_referencedCollectionTypesDictionary, Globals.TypeOfDictionaryGeneric); + } + return _referencedCollectionTypesDictionary; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private void AddReferencedType(Dictionary referencedTypes, Type type) + { + if (IsTypeReferenceable(type)) + { + XmlQualifiedName stableName; + try + { + stableName = GetStableName(type); + } + catch (InvalidDataContractException) + { + // Type not referenceable if we can't get a stable name. + return; + } + catch (InvalidOperationException) + { + // Type not referenceable if we can't get a stable name. + return; + } + + if (referencedTypes.TryGetValue(stableName, out object? value)) + { + if (value is Type referencedType) + { + if (referencedType != type) + { + referencedTypes.Remove(stableName); + List types = new List(); + types.Add(referencedType); + types.Add(type); + referencedTypes.Add(stableName, types); + } + } + else + { + List types = (List)value; + if (!types.Contains(type)) + types.Add(type); + } + } + else + referencedTypes.Add(stableName, type); + } + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private static bool IsTypeReferenceable(Type type) + { + try + { + return (type.IsSerializable || + type.IsDefined(Globals.TypeOfDataContractAttribute, false) || + (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type) && !type.IsGenericTypeDefinition) || + CollectionDataContract.IsCollection(type, out _) || + ClassDataContract.IsNonAttributedTypeValidForSerialization(type)); + } + catch (Exception) + { + // An exception can be thrown in the designer when a project has a runtime binding redirection for a referenced assembly or a reference dependent assembly. + // Type.IsDefined is known to throw System.IO.FileLoadException. + // ClassDataContract.IsNonAttributedTypeValidForSerialization is known to throw System.IO.FileNotFoundException. + // We guard against all non-critical exceptions. + } + + return false; + } + + //[RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + //private bool TryGetReferencedType(XmlQualifiedName stableName, DataContract? dataContract, [NotNullWhen(true)] out Type? type) + //{ + // if (dataContract == null) + // { + // if (_dataContractSet.TryGetReferencedCollectionType(stableName, null, out type)) + // return true; + // if (_dataContractSet.TryGetReferencedType(stableName, null, out type)) + // { + // // enforce that collection types only be specified via ReferencedCollectionTypes + // if (CollectionDataContract.IsCollection(type)) + // { + // type = null; + // return false; + // } + // return true; + // } + // return false; + // } + // else if (dataContract is CollectionDataContract) + // return _dataContractSet.TryGetReferencedCollectionType(stableName, dataContract, out type); + // else + // { + // if (dataContract is XmlDataContract xmlDataContract && xmlDataContract.IsAnonymous) + // { + // stableName = SchemaImporter.ImportActualType(xmlDataContract.XsdType?.Annotation, stableName, dataContract.StableName); + // } + // return _dataContractSet.TryGetReferencedType(stableName, dataContract, out type); + // } + //} + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal bool TryGetReferencedType(XmlQualifiedName stableName, DataContract? dataContract, [NotNullWhen(true)] out Type? type) + { + return TryGetReferencedType(stableName, dataContract, false/*useReferencedCollectionTypes*/, out type); + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal bool TryGetReferencedCollectionType(XmlQualifiedName stableName, DataContract? dataContract, [NotNullWhen(true)] out Type? type) + { + return TryGetReferencedType(stableName, dataContract, true/*useReferencedCollectionTypes*/, out type); + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private bool TryGetReferencedType(XmlQualifiedName stableName, DataContract? dataContract, bool useReferencedCollectionTypes, [NotNullWhen(true)] out Type? type) + { + Dictionary referencedTypes = useReferencedCollectionTypes ? GetReferencedCollectionTypes() : GetReferencedTypes(); + if (referencedTypes.TryGetValue(stableName, out object? value)) + { + type = value as Type; + if (type != null) + { + return true; + } + else + { + // Throw ambiguous type match exception + List types = (List)value; + StringBuilder errorMessage = new StringBuilder(); + bool containsGenericType = false; + for (int i = 0; i < types.Count; i++) + { + Type conflictingType = types[i]; + if (!containsGenericType) + containsGenericType = conflictingType.IsGenericTypeDefinition; + errorMessage.AppendFormat("{0}\"{1}\" ", Environment.NewLine, conflictingType.AssemblyQualifiedName); + if (dataContract != null) + { + DataContract other = GetDataContract(conflictingType); + errorMessage.Append(SR.Format(((other != null && other.Equals(dataContract)) ? SR.ReferencedTypeMatchingMessage : SR.ReferencedTypeNotMatchingMessage))); + } + } + if (containsGenericType) + { + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format( + (useReferencedCollectionTypes ? SR.AmbiguousReferencedCollectionTypes1 : SR.AmbiguousReferencedTypes1), + errorMessage.ToString()))); + } + else + { + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format( + (useReferencedCollectionTypes ? SR.AmbiguousReferencedCollectionTypes3 : SR.AmbiguousReferencedTypes3), + XmlConvert.DecodeName(stableName.Name), + stableName.Namespace, + errorMessage.ToString()))); + } + } + } + type = null; + return false; + } + + internal ISerializationExtendedSurrogateProvider? SerializationExtendedSurrogateProvider + { + get { return _extendedSurrogateProvider; } + } + + internal object? GetSurrogateData(object key) + { + return SurrogateDataTable[key]; + } + + internal void SetSurrogateData(object key, object? surrogateData) + { + SurrogateDataTable[key] = surrogateData; + } public IEnumerator> GetEnumerator() { return Contracts.GetEnumerator(); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSurrogateCaller.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSurrogateCaller.cs index 5a35b3879bbbc..1fffd1c604d47 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSurrogateCaller.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSurrogateCaller.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.CodeDom; using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; using System.Reflection; @@ -40,5 +39,31 @@ internal static Type GetDataContractType(ISerializationSurrogateProvider surroga return obj; return surrogateProvider.GetDeserializedObject(obj, memberType); } + + internal static object? GetCustomDataToExport(ISerializationExtendedSurrogateProvider surrogateProvider, MemberInfo memberInfo, Type dataContractType) + { + return surrogateProvider.GetCustomDataToExport(memberInfo, dataContractType); + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal static object? GetCustomDataToExport(ISerializationExtendedSurrogateProvider surrogateProvider, Type clrType, Type dataContractType) + { + if (DataContract.GetBuiltInDataContract(clrType) != null) + return null; + return surrogateProvider.GetCustomDataToExport(clrType, dataContractType); + } + + internal static void GetKnownCustomDataTypes(ISerializationExtendedSurrogateProvider surrogateProvider, Collection customDataTypes) + { + surrogateProvider.GetKnownCustomDataTypes(customDataTypes); + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal static Type? GetReferencedTypeOnImport(ISerializationExtendedSurrogateProvider surrogateProvider, string typeName, string typeNamespace, object? customData) + { + if (DataContract.GetBuiltInDataContract(typeName, typeNamespace) != null) + return null; + return surrogateProvider.GetReferencedTypeOnImport(typeName, typeNamespace, customData); + } } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs index 4c85f38678447..04e4dd422b0fe 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs @@ -22,6 +22,11 @@ internal DataMember(MemberInfo memberInfo) _helper = new CriticalHelper(memberInfo); } + internal DataMember(DataContract memberTypeContract, string name, bool isNullable, bool isRequired, bool emitDefaultValue, int order) + { + _helper = new CriticalHelper(memberTypeContract, name, isNullable, isRequired, emitDefaultValue, order); + } + internal MemberInfo MemberInfo { get @@ -147,6 +152,17 @@ internal CriticalHelper(MemberInfo memberInfo) _memberPrimitiveContract = PrimitiveDataContract.NullContract; } + internal CriticalHelper(DataContract memberTypeContract, string name, bool isNullable, bool isRequired, bool emitDefaultValue, int order) + { + _memberTypeContract = memberTypeContract; + _name = name; + _isNullable = isNullable; + _isRequired = isRequired; + _emitDefaultValue = emitDefaultValue; + _order = order; + _memberInfo = memberTypeContract.UnderlyingType; + } + internal MemberInfo MemberInfo { get { return _memberInfo; } @@ -309,6 +325,19 @@ internal bool RequiresMemberAccessForSet() return false; } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal DataMember BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) + { + DataContract memberTypeContract = MemberTypeContract.BindGenericParameters(paramContracts, boundContracts); + DataMember boundDataMember = new DataMember(memberTypeContract, + Name, + !memberTypeContract.IsValueType, + IsRequired, + EmitDefaultValue, + Order); + return boundDataMember; + } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal bool Equals(object? other, HashSet checkedContracts) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs index ab26f6195ee9b..98485d0c8e61a 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs @@ -26,6 +26,11 @@ internal EnumDataContract(Type type) : base(new EnumDataContractCriticalHelper(t _helper = (base.Helper as EnumDataContractCriticalHelper)!; } + internal static Type? GetBaseType(XmlQualifiedName baseContractName) + { + return EnumDataContractCriticalHelper.GetBaseType(baseContractName); + } + public XmlQualifiedName BaseContractName { get => _helper.BaseContractName; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs index e768ceba55532..7022db830c03c 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs @@ -51,5 +51,11 @@ internal int ParameterPosition get { return _parameterPosition; } } } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) + { + return paramContracts[ParameterPosition]; + } } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs index 9ed56ce418144..9dcae7f027f79 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs @@ -313,6 +313,18 @@ internal static Type TypeOfHashtable internal static Type TypeOfDBNull => s_typeOfDBNull ??= typeof(DBNull); + // TODO smolloy - change name inline with new name from class defined in SchemaHelper + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicFields)] + private static Type? s_typeOfSchemaTypePlaceholder; + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicFields)] + internal static Type TypeOfSchemaTypePlaceholder => + s_typeOfSchemaTypePlaceholder ??= typeof(SchemaTypePlaceholder); + + // TODO smolloy - change name inline with new name from SchemaHelper + private static MemberInfo? s_schemaMemberInfoPlaceholder; + internal static MemberInfo SchemaMemberInfoPlaceholder => + s_schemaMemberInfoPlaceholder ??= TypeOfSchemaTypePlaceholder.GetField("_stableName", BindingFlags.NonPublic | BindingFlags.Instance)!; + private static Uri? s_dataContractXsdBaseNamespaceUri; internal static Uri DataContractXsdBaseNamespaceUri => s_dataContractXsdBaseNamespaceUri ??= new Uri(DataContractXsdBaseNamespace); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs index 625b5a197a025..744120facdaa7 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs @@ -129,7 +129,7 @@ private void ExportClassDataContract(ClassDataContract classDataContract, XmlSch XmlSchemaElement element = new XmlSchemaElement(); element.Name = dataMember.Name; XmlElement? actualTypeElement = null; - DataContract memberTypeContract = DataContractSet.GetMemberTypeDataContract(dataMember); + DataContract memberTypeContract = _dataContractSet.GetMemberTypeDataContract(dataMember); if (CheckIfMemberHasConflict(dataMember)) { element.SchemaTypeName = AnytypeQualifiedName; @@ -329,10 +329,25 @@ private XmlElement ExportGenericInfo(Type clrType, string elementName, string el return typeElement; } - private static XmlElement? ExportSurrogateData(object key) + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private XmlElement? ExportSurrogateData(object key) { - // IDataContractSurrogate is not available on NetCore. - return null; + object? surrogateData = _dataContractSet.GetSurrogateData(key); + if (surrogateData == null) + return null; + StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); + XmlWriterSettings writerSettings = new XmlWriterSettings(); + writerSettings.OmitXmlDeclaration = true; + XmlWriter xmlWriter = XmlWriter.Create(stringWriter, writerSettings); + Collection knownTypes = new Collection(); + if (_dataContractSet.SerializationExtendedSurrogateProvider != null) + DataContractSurrogateCaller.GetKnownCustomDataTypes(_dataContractSet.SerializationExtendedSurrogateProvider, knownTypes); + DataContractSerializer serializer = new DataContractSerializer(Globals.TypeOfObject, + SurrogateDataAnnotationName.Name, SurrogateDataAnnotationName.Namespace, knownTypes, int.MaxValue, + ignoreExtensionDataObject: false, preserveObjectReferences: true); + serializer.WriteObject(xmlWriter, surrogateData); + xmlWriter.Flush(); + return (XmlElement?)XmlDoc.ReadNode(XmlReader.Create(new StringReader(stringWriter.ToString()))); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -363,7 +378,7 @@ private void ExportCollectionDataContract(CollectionDataContract collectionDataC { XmlSchemaElement keyValueElement = new XmlSchemaElement(); keyValueElement.Name = dataMember.Name; - SetElementType(keyValueElement, DataContractSet.GetMemberTypeDataContract(dataMember), schema); + SetElementType(keyValueElement, _dataContractSet.GetMemberTypeDataContract(dataMember), schema); SchemaHelper.AddElementForm(keyValueElement, schema); if (dataMember.IsNullable) keyValueElement.IsNillable = true; @@ -377,7 +392,7 @@ private void ExportCollectionDataContract(CollectionDataContract collectionDataC { if (collectionDataContract.IsItemTypeNullable) element.IsNillable = true; - DataContract itemContract = DataContractSet.GetItemTypeDataContract(collectionDataContract); + DataContract itemContract = _dataContractSet.GetItemTypeDataContract(collectionDataContract); SetElementType(element, itemContract, schema); } SchemaHelper.AddElementForm(element, schema); @@ -396,6 +411,7 @@ private XmlElement ExportIsDictionary() return isDictionaryElement; } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private void ExportEnumDataContract(EnumDataContract enumDataContract, XmlSchema schema) { XmlSchemaSimpleType type = new XmlSchemaSimpleType(); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs index 8d2698ede2620..01301050919ec 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs @@ -7,8 +7,37 @@ using System.Collections; using System.Collections.Generic; +using SchemaObjectDictionary = System.Collections.Generic.Dictionary; + namespace System.Runtime.Serialization { + internal sealed class SchemaObjectInfo + { + internal XmlSchemaType? _type; + internal XmlSchemaElement? _element; + internal XmlSchema? _schema; + internal List? _knownTypes; + + internal SchemaObjectInfo(XmlSchemaType? type, XmlSchemaElement? element, XmlSchema? schema, List? knownTypes) + { + _type = type; + _element = element; + _schema = schema; + _knownTypes = knownTypes; + } + } + + // TODO smolloy - change name to something without placeholder. Like SchemaDefinedType or something. + internal sealed class SchemaTypePlaceholder + { + private XmlQualifiedName _stableName; + + public SchemaTypePlaceholder(XmlQualifiedName stableName) + { + _stableName = stableName; + } + } + internal static class SchemaHelper { internal static bool NamespacesEqual(string? ns1, string? ns2) @@ -19,6 +48,16 @@ internal static bool NamespacesEqual(string? ns1, string? ns2) return ns1 == ns2; } + internal static XmlSchemaType? GetSchemaType(SchemaObjectDictionary schemaInfo, XmlQualifiedName typeName) + { + SchemaObjectInfo? schemaObjectInfo; + if (schemaInfo.TryGetValue(typeName, out schemaObjectInfo)) + { + return schemaObjectInfo._type; + } + return null; + } + internal static XmlSchemaType? GetSchemaType(XmlSchemaSet schemas, XmlQualifiedName typeQName, out XmlSchema? outSchema) { outSchema = null; @@ -42,6 +81,16 @@ internal static bool NamespacesEqual(string? ns1, string? ns2) return null; } + internal static XmlSchemaElement? GetSchemaElement(SchemaObjectDictionary schemaInfo, XmlQualifiedName elementName) + { + SchemaObjectInfo? schemaObjectInfo; + if (schemaInfo.TryGetValue(elementName, out schemaObjectInfo)) + { + return schemaObjectInfo._element; + } + return null; + } + internal static XmlSchemaElement? GetSchemaElement(XmlSchemaSet schemas, XmlQualifiedName elementQName, out XmlSchema? outSchema) { outSchema = null; @@ -123,5 +172,59 @@ internal static void AddSchemaImport(string ns, XmlSchema schema) import.Namespace = ns; schema.Includes.Add(import); } + + internal static XmlSchema? GetSchemaWithType(SchemaObjectDictionary schemaInfo, XmlSchemaSet schemas, XmlQualifiedName typeName) + { + SchemaObjectInfo? schemaObjectInfo; + if (schemaInfo.TryGetValue(typeName, out schemaObjectInfo)) + { + if (schemaObjectInfo._schema != null) + return schemaObjectInfo._schema; + } + ICollection currentSchemas = schemas.Schemas(); + string ns = typeName.Namespace; + foreach (XmlSchema schema in currentSchemas) + { + if (NamespacesEqual(ns, schema.TargetNamespace)) + { + return schema; + } + } + return null; + } + + internal static XmlSchema? GetSchemaWithGlobalElementDeclaration(XmlSchemaElement element, XmlSchemaSet schemas) + { + ICollection currentSchemas = schemas.Schemas(); + foreach (XmlSchema schema in currentSchemas) + { + foreach (XmlSchemaObject schemaObject in schema.Items) + { + if (schemaObject is XmlSchemaElement schemaElement && schemaElement == element) + { + return schema; + } + } + } + return null; + } + + internal static XmlQualifiedName? GetGlobalElementDeclaration(XmlSchemaSet schemas, XmlQualifiedName typeQName, out bool isNullable) + { + ICollection currentSchemas = schemas.Schemas(); + isNullable = false; + foreach (XmlSchema schema in currentSchemas) + { + foreach (XmlSchemaObject schemaObject in schema.Items) + { + if (schemaObject is XmlSchemaElement schemaElement && schemaElement.SchemaTypeName.Equals(typeQName)) + { + isNullable = schemaElement.IsNillable; + return new XmlQualifiedName(schemaElement.Name, schema.TargetNamespace); + } + } + } + return null; + } } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs new file mode 100644 index 0000000000000..6728f81ae3e80 --- /dev/null +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs @@ -0,0 +1,1471 @@ +// 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.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.Xml; +using System.Xml.Schema; + +using DataContractDictionary = System.Collections.Generic.Dictionary; +using SchemaObjectDictionary = System.Collections.Generic.Dictionary; + +namespace System.Runtime.Serialization +{ + + internal sealed class SchemaImporter + { + private DataContractSet _dataContractSet; + private XmlSchemaSet _schemaSet; + private ICollection? _typeNames; + private ICollection _elements; + private XmlQualifiedName[] _elementTypeNames; + private bool _importXmlDataType; + private SchemaObjectDictionary _schemaObjects = null!; // Not directly referenced. Always lazy initialized by property getter. + private List _redefineList = null!; // Not directly referenced. Always lazy initialized by property getter. + private bool _needToImportKnownTypesForObject; + + private static Hashtable? s_serializationSchemaElements; + + internal SchemaImporter(XmlSchemaSet schemas, ICollection? typeNames, ICollection elements, XmlQualifiedName[] elementTypeNames, DataContractSet dataContractSet, bool importXmlDataType) + { + _dataContractSet = dataContractSet; + _schemaSet = schemas; + _typeNames = typeNames; + _elements = elements; + _elementTypeNames = elementTypeNames; + _importXmlDataType = importXmlDataType; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal void Import() + { + if (!_schemaSet.Contains(Globals.SerializationNamespace)) + { + StringReader reader = new StringReader(Globals.SerializationSchema); + XmlSchema? schema = XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null); + if (schema == null) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.CouldNotReadSerializationSchema, Globals.SerializationNamespace))); + _schemaSet.Add(schema); + } + + try + { + CompileSchemaSet(_schemaSet); + } +#pragma warning suppress 56500 // covered by FxCOP + catch (Exception ex) + { + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.Format(SR.CannotImportInvalidSchemas), ex)); + } + + if (_typeNames == null) + { + ICollection schemaList = _schemaSet.Schemas(); + foreach (object schemaObj in schemaList) + { + if (schemaObj == null) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.Format(SR.CannotImportNullSchema))); + + XmlSchema schema = (XmlSchema)schemaObj; + if (schema.TargetNamespace != Globals.SerializationNamespace + && schema.TargetNamespace != Globals.SchemaNamespace) + { + foreach (XmlSchemaObject typeObj in schema.SchemaTypes.Values) + { + ImportType((XmlSchemaType)typeObj); + } + foreach (XmlSchemaElement element in schema.Elements.Values) + { + if (element.SchemaType != null) + ImportAnonymousGlobalElement(element, element.QualifiedName, schema.TargetNamespace); + } + } + } + } + else + { + foreach (XmlQualifiedName typeName in _typeNames) + { + if (typeName == null) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.Format(SR.CannotImportNullDataContractName))); + ImportType(typeName); + } + + if (_elements.Count > 0) + { + int i = 0; + foreach (XmlSchemaElement element in _elements) + { + XmlQualifiedName typeName = element.SchemaTypeName; + if (typeName != null && typeName.Name.Length > 0) + { + _elementTypeNames[i++] = ImportType(typeName).StableName; + } + else + { + XmlSchema? schema = SchemaHelper.GetSchemaWithGlobalElementDeclaration(element, _schemaSet); + if (schema == null) + { + _elementTypeNames[i++] = ImportAnonymousElement(element, element.QualifiedName).StableName; + } + else + { + _elementTypeNames[i++] = ImportAnonymousGlobalElement(element, element.QualifiedName, schema.TargetNamespace).StableName; + } + } + } + } + } + ImportKnownTypesForObject(); + } + + internal static void CompileSchemaSet(XmlSchemaSet schemaSet) + { + if (schemaSet.Contains(XmlSchema.Namespace)) + schemaSet.Compile(); + else + { + // Add base XSD schema with top level element named "schema" + XmlSchema xsdSchema = new XmlSchema(); + xsdSchema.TargetNamespace = XmlSchema.Namespace; + XmlSchemaElement element = new XmlSchemaElement(); + element.Name = Globals.SchemaLocalName; + element.SchemaType = new XmlSchemaComplexType(); + xsdSchema.Items.Add(element); + schemaSet.Add(xsdSchema); + schemaSet.Compile(); + } + } + + private SchemaObjectDictionary SchemaObjects + { + get + { + if (_schemaObjects == null) + _schemaObjects = CreateSchemaObjects(); + return _schemaObjects; + } + } + + private List RedefineList + { + get + { + if (_redefineList == null) + _redefineList = CreateRedefineList(); + return _redefineList; + } + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private void ImportKnownTypes(XmlQualifiedName typeName) + { + SchemaObjectInfo? schemaObjectInfo; + if (SchemaObjects.TryGetValue(typeName, out schemaObjectInfo)) + { + List? knownTypes = schemaObjectInfo._knownTypes; + if (knownTypes != null) + { + foreach (XmlSchemaType knownType in knownTypes) + ImportType(knownType); + } + } + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal static bool IsObjectContract(DataContract dataContract) + { + Dictionary previousCollectionTypes = new Dictionary(); + while (dataContract is CollectionDataContract) + { + if (dataContract.OriginalUnderlyingType == null) + { + dataContract = ((CollectionDataContract)dataContract).ItemContract; + continue; + } + + if (!previousCollectionTypes.ContainsKey(dataContract.OriginalUnderlyingType)) + { + previousCollectionTypes.Add(dataContract.OriginalUnderlyingType, dataContract.OriginalUnderlyingType); + dataContract = ((CollectionDataContract)dataContract).ItemContract; + } + else + { + break; + } + } + + return dataContract is PrimitiveDataContract && ((PrimitiveDataContract)dataContract).UnderlyingType == Globals.TypeOfObject; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private void ImportKnownTypesForObject() + { + if (!_needToImportKnownTypesForObject) + return; + _needToImportKnownTypesForObject = false; + if (_dataContractSet.KnownTypesForObject == null) + { + SchemaObjectInfo? schemaObjectInfo; + if (SchemaObjects.TryGetValue(SchemaExporter.AnytypeQualifiedName, out schemaObjectInfo)) + { + List? knownTypes = schemaObjectInfo._knownTypes; + if (knownTypes != null) + { + DataContractDictionary knownDataContracts = new DataContractDictionary(); + foreach (XmlSchemaType knownType in knownTypes) + { + // Expected: will throw exception if schema set contains types that are not supported + DataContract dataContract = ImportType(knownType); + if (!knownDataContracts.TryGetValue(dataContract.StableName, out _)) + { + knownDataContracts.Add(dataContract.StableName, dataContract); + } + } + _dataContractSet.KnownTypesForObject = knownDataContracts; + } + } + } + } + + internal SchemaObjectDictionary CreateSchemaObjects() + { + SchemaObjectDictionary schemaObjects = new SchemaObjectDictionary(); + ICollection schemaList = _schemaSet.Schemas(); + List knownTypesForObject = new List(); + schemaObjects.Add(SchemaExporter.AnytypeQualifiedName, new SchemaObjectInfo(null, null, null, knownTypesForObject)); + + foreach (XmlSchema schema in schemaList) + { + if (schema.TargetNamespace != Globals.SerializationNamespace) + { + foreach (XmlSchemaObject schemaObj in schema.SchemaTypes.Values) + { + XmlSchemaType? schemaType = schemaObj as XmlSchemaType; + if (schemaType != null) + { + knownTypesForObject.Add(schemaType); + + XmlQualifiedName currentTypeName = new XmlQualifiedName(schemaType.Name, schema.TargetNamespace); + SchemaObjectInfo? schemaObjectInfo; + if (schemaObjects.TryGetValue(currentTypeName, out schemaObjectInfo)) + { + schemaObjectInfo._type = schemaType; + schemaObjectInfo._schema = schema; + } + else + { + schemaObjects.Add(currentTypeName, new SchemaObjectInfo(schemaType, null, schema, null)); + } + + XmlQualifiedName? baseTypeName = GetBaseTypeName(schemaType); + if (baseTypeName != null) + { + SchemaObjectInfo? baseTypeInfo; + if (schemaObjects.TryGetValue(baseTypeName, out baseTypeInfo)) + { + if (baseTypeInfo._knownTypes == null) + { + baseTypeInfo._knownTypes = new List(); + } + } + else + { + baseTypeInfo = new SchemaObjectInfo(null, null, null, new List()); + schemaObjects.Add(baseTypeName, baseTypeInfo); + } + baseTypeInfo._knownTypes!.Add(schemaType); // Verified not-null above, or created not-null. + } + } + } + foreach (XmlSchemaObject schemaObj in schema.Elements.Values) + { + XmlSchemaElement? schemaElement = schemaObj as XmlSchemaElement; + if (schemaElement != null) + { + XmlQualifiedName currentElementName = new XmlQualifiedName(schemaElement.Name, schema.TargetNamespace); + SchemaObjectInfo? schemaObjectInfo; + if (schemaObjects.TryGetValue(currentElementName, out schemaObjectInfo)) + { + schemaObjectInfo._element = schemaElement; + schemaObjectInfo._schema = schema; + } + else + { + schemaObjects.Add(currentElementName, new SchemaObjectInfo(null, schemaElement, schema, null)); + } + } + } + } + } + return schemaObjects; + } + + private static XmlQualifiedName? GetBaseTypeName(XmlSchemaType type) + { + XmlQualifiedName? baseTypeName = null; + if (type is XmlSchemaComplexType complexType) + { + if (complexType.ContentModel != null) + { + if (complexType.ContentModel is XmlSchemaComplexContent complexContent) + { + if (complexContent.Content is XmlSchemaComplexContentExtension extension) + { + baseTypeName = extension.BaseTypeName; + } + } + } + } + return baseTypeName; + } + + private List CreateRedefineList() + { + List list = new List(); + + ICollection schemaList = _schemaSet.Schemas(); + foreach (object schemaObj in schemaList) + { + if (schemaObj is XmlSchema schema) + { + foreach (XmlSchemaExternal ext in schema.Includes) + { + if (ext is XmlSchemaRedefine redefine) + list.Add(redefine); + } + } + } + + return list; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private DataContract ImportAnonymousGlobalElement(XmlSchemaElement element, XmlQualifiedName typeQName, string? ns) + { + DataContract contract = ImportAnonymousElement(element, typeQName); + if (contract is XmlDataContract xmlDataContract) + { + xmlDataContract.SetTopLevelElementName(new XmlQualifiedName(element.Name, ns)); + xmlDataContract.IsTopLevelElementNullable = element.IsNillable; + } + return contract; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private DataContract ImportAnonymousElement(XmlSchemaElement element, XmlQualifiedName typeQName) + { + if (SchemaHelper.GetSchemaType(SchemaObjects, typeQName) != null) + { + for (int i = 1;; i++) + { + typeQName = new XmlQualifiedName(typeQName.Name + i.ToString(NumberFormatInfo.InvariantInfo), typeQName.Namespace); + if (SchemaHelper.GetSchemaType(SchemaObjects, typeQName) == null) + break; + if (i == int.MaxValue) + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.CannotComputeUniqueName, element.Name))); + } + } + if (element.SchemaType == null) + return ImportType(SchemaExporter.AnytypeQualifiedName); + else + return ImportType(element.SchemaType, typeQName, true/*isAnonymous*/); + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private DataContract ImportType(XmlQualifiedName typeName) + { + DataContract? dataContract = DataContract.GetBuiltInDataContract(typeName.Name, typeName.Namespace); + if (dataContract == null) + { + XmlSchemaType? type = SchemaHelper.GetSchemaType(SchemaObjects, typeName); + if (type == null) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.SpecifiedTypeNotFoundInSchema, typeName.Name, typeName.Namespace))); + dataContract = ImportType(type); + } + if (IsObjectContract(dataContract)) + _needToImportKnownTypesForObject = true; + return dataContract; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private DataContract ImportType(XmlSchemaType type) + { + return ImportType(type, type.QualifiedName, false/*isAnonymous*/); + } + + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private DataContract ImportType(XmlSchemaType type, XmlQualifiedName typeName, bool isAnonymous) + { + DataContract? dataContract = _dataContractSet[typeName]; + if (dataContract != null) + return dataContract; + + InvalidDataContractException invalidContractException; + try + { + foreach (XmlSchemaRedefine redefine in RedefineList) + { + if (redefine.SchemaTypes[typeName] != null) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.RedefineNotSupported)); + } + + if (type is XmlSchemaSimpleType simpleType) + { + XmlSchemaSimpleTypeContent? content = simpleType.Content; + if (content is XmlSchemaSimpleTypeUnion) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.SimpleTypeUnionNotSupported)); + else if (content is XmlSchemaSimpleTypeList) + dataContract = ImportFlagsEnum(typeName, (XmlSchemaSimpleTypeList)content, simpleType.Annotation); + else if (content is XmlSchemaSimpleTypeRestriction restriction) + { + if (CheckIfEnum(restriction)) + { + dataContract = ImportEnum(typeName, restriction, false /*isFlags*/, simpleType.Annotation); + } + else + { + dataContract = ImportSimpleTypeRestriction(typeName, restriction); + if (dataContract.IsBuiltInDataContract && !isAnonymous) + { + _dataContractSet.InternalAdd(typeName, dataContract); + } + } + } + } + else if (type is XmlSchemaComplexType complexType) + { + if (complexType.ContentModel == null) + { + CheckComplexType(typeName, complexType); + dataContract = ImportType(typeName, complexType.Particle, complexType.Attributes, complexType.AnyAttribute, null /* baseTypeName */, complexType.Annotation); + } + else + { + XmlSchemaContentModel contentModel = complexType.ContentModel; + if (contentModel is XmlSchemaSimpleContent) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.SimpleContentNotSupported)); + else if (contentModel is XmlSchemaComplexContent complexContent) + { + if (complexContent.IsMixed) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.MixedContentNotSupported)); + + if (complexContent.Content is XmlSchemaComplexContentExtension extension) + { + dataContract = ImportType(typeName, extension.Particle, extension.Attributes, extension.AnyAttribute, extension.BaseTypeName, complexType.Annotation); + } + else if (complexContent.Content is XmlSchemaComplexContentRestriction restriction) + { + XmlQualifiedName baseTypeName = restriction.BaseTypeName; + if (baseTypeName == SchemaExporter.AnytypeQualifiedName) + dataContract = ImportType(typeName, restriction.Particle, restriction.Attributes, restriction.AnyAttribute, null /* baseTypeName */, complexType.Annotation); + else + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ComplexTypeRestrictionNotSupported)); + } + } + } + } + + if (dataContract == null) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, string.Empty); + if (type.QualifiedName != XmlQualifiedName.Empty) + ImportTopLevelElement(typeName); + Debug.Assert(dataContract != null); // Throws above if false + ImportDataContractExtension(type, dataContract); + ImportGenericInfo(type, dataContract); + ImportKnownTypes(typeName); + + return dataContract; + } + catch (InvalidDataContractException e) + { + invalidContractException = e; + } + + // Execution gets to this point if InvalidDataContractException was thrown + if (_importXmlDataType) + { + RemoveFailedContract(typeName); + return ImportXmlDataType(typeName, type, isAnonymous); + } + Type? referencedType; + if (_dataContractSet.TryGetReferencedType(typeName, dataContract, out referencedType) + || (string.IsNullOrEmpty(type.Name) && _dataContractSet.TryGetReferencedType(ImportActualType(type.Annotation, typeName, typeName), dataContract, out referencedType))) + { + if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(referencedType)) + { + RemoveFailedContract(typeName); + return ImportXmlDataType(typeName, type, isAnonymous); + } + } + XmlDataContract? specialContract = ImportSpecialXmlDataType(type, isAnonymous); + if (specialContract != null) + { + _dataContractSet.Remove(typeName); + return specialContract; + } + + throw invalidContractException; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private void RemoveFailedContract(XmlQualifiedName typeName) + { + ClassDataContract? oldContract = _dataContractSet[typeName] as ClassDataContract; + _dataContractSet.Remove(typeName); + if (oldContract != null) + { + ClassDataContract? ancestorDataContract = oldContract.BaseContract; + while (ancestorDataContract != null) + { + ancestorDataContract.KnownDataContracts?.Remove(typeName); + ancestorDataContract = ancestorDataContract.BaseContract; + } + if (_dataContractSet.KnownTypesForObject != null) + _dataContractSet.KnownTypesForObject.Remove(typeName); + } + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private bool CheckIfEnum(XmlSchemaSimpleTypeRestriction restriction) + { + foreach (XmlSchemaFacet facet in restriction.Facets) + { + if (facet is not XmlSchemaEnumerationFacet) + return false; + } + + XmlQualifiedName expectedBase = SchemaExporter.StringQualifiedName; + if (restriction.BaseTypeName != XmlQualifiedName.Empty) + { + return ((restriction.BaseTypeName == expectedBase && restriction.Facets.Count > 0) || ImportType(restriction.BaseTypeName) is EnumDataContract); + } + else if (restriction.BaseType != null) + { + DataContract baseContract = ImportType(restriction.BaseType); + return (baseContract.StableName == expectedBase || baseContract is EnumDataContract); + } + + return false; + } + + private static bool CheckIfCollection(XmlSchemaSequence rootSequence) + { + if (rootSequence.Items == null || rootSequence.Items.Count == 0) + return false; + RemoveOptionalUnknownSerializationElements(rootSequence.Items); + if (rootSequence.Items.Count != 1) + return false; + + XmlSchemaObject o = rootSequence.Items[0]; + if (o is XmlSchemaElement localElement) + return (localElement.MaxOccursString == Globals.OccursUnbounded || localElement.MaxOccurs > 1); + + return false; + } + + private static bool CheckIfISerializable(XmlSchemaSequence rootSequence, XmlSchemaObjectCollection attributes) + { + if (rootSequence.Items == null || rootSequence.Items.Count == 0) + return false; + + RemoveOptionalUnknownSerializationElements(rootSequence.Items); + + if (attributes == null || attributes.Count == 0) + return false; + + return (rootSequence.Items.Count == 1 && rootSequence.Items[0] is XmlSchemaAny); + } + + private static void RemoveOptionalUnknownSerializationElements(XmlSchemaObjectCollection items) + { + for (int i = 0; i < items.Count; i++) + { + XmlSchemaElement? element = items[i] as XmlSchemaElement; + if (element != null && element.RefName != null && + element.RefName.Namespace == Globals.SerializationNamespace && + element.MinOccurs == 0) + { + if (s_serializationSchemaElements == null) + { + XmlSchema serializationSchema = XmlSchema.Read(XmlReader.Create(new StringReader(Globals.SerializationSchema)), null)!; // Source is our constant. Schema is valid. + s_serializationSchemaElements = new Hashtable(); + foreach (XmlSchemaObject schemaObject in serializationSchema.Items) + { + if (schemaObject is XmlSchemaElement schemaElement) + if (schemaElement.Name != null) + s_serializationSchemaElements.Add(schemaElement.Name, schemaElement); + } + } + if (!s_serializationSchemaElements.ContainsKey(element.RefName.Name)) + { + items.RemoveAt(i); + i--; + } + } + } + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private DataContract? ImportType(XmlQualifiedName typeName, XmlSchemaParticle? rootParticle, XmlSchemaObjectCollection attributes, XmlSchemaAnyAttribute? anyAttribute, XmlQualifiedName? baseTypeName, XmlSchemaAnnotation? annotation) + { + DataContract? dataContract = null; + bool isDerived = (baseTypeName != null); + + bool isReference; + ImportAttributes(typeName, attributes, anyAttribute, out isReference); + + if (rootParticle == null) + dataContract = ImportClass(typeName, new XmlSchemaSequence(), baseTypeName, annotation, isReference); + else if (rootParticle is XmlSchemaSequence rootSequence) + { + if (rootSequence.MinOccurs != 1) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.RootSequenceMustBeRequired)); + if (rootSequence.MaxOccurs != 1) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.RootSequenceMaxOccursMustBe)); + + if (!isDerived && CheckIfCollection(rootSequence)) + dataContract = ImportCollection(typeName, rootSequence, attributes, annotation, isReference); + else if (CheckIfISerializable(rootSequence, attributes)) + dataContract = ImportISerializable(typeName, rootSequence, baseTypeName, attributes, annotation); + else + dataContract = ImportClass(typeName, rootSequence, baseTypeName, annotation, isReference); + } + else + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.RootParticleMustBeSequence)); + return dataContract; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private ClassDataContract ImportClass(XmlQualifiedName typeName, XmlSchemaSequence rootSequence, XmlQualifiedName? baseTypeName, XmlSchemaAnnotation? annotation, bool isReference) + { + ClassDataContract dataContract = new ClassDataContract(Globals.TypeOfSchemaTypePlaceholder); + dataContract.StableName = typeName; + AddDataContract(dataContract); + + dataContract.IsValueType = IsValueType(typeName, annotation); + dataContract.IsReference = isReference; + if (baseTypeName != null) + { + ImportBaseContract(baseTypeName, dataContract); + Debug.Assert(dataContract.BaseContract != null); // ImportBaseContract will always set this... or throw. + if (dataContract.BaseContract.IsISerializable) + { + if (IsISerializableDerived(typeName, rootSequence)) + dataContract.IsISerializable = true; + else + ThrowTypeCannotBeImportedException(dataContract.StableName.Name, dataContract.StableName.Namespace, SR.Format(SR.DerivedTypeNotISerializable, baseTypeName.Name, baseTypeName.Namespace)); + } + if (dataContract.BaseContract.IsReference) + { + dataContract.IsReference = true; + } + } + + if (!dataContract.IsISerializable) + { + dataContract.Members = new List(); + RemoveOptionalUnknownSerializationElements(rootSequence.Items); + for (int memberIndex = 0; memberIndex < rootSequence.Items.Count; memberIndex++) + { + XmlSchemaElement? element = rootSequence.Items[memberIndex] as XmlSchemaElement; + if (element == null) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.MustContainOnlyLocalElements)); + ImportClassMember(element!, dataContract); + } + } + + return dataContract; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private DataContract ImportXmlDataType(XmlQualifiedName typeName, XmlSchemaType xsdType, bool isAnonymous) + { + DataContract? dataContract = _dataContractSet[typeName]; + if (dataContract != null) + return dataContract; + + XmlDataContract? xmlDataContract = ImportSpecialXmlDataType(xsdType, isAnonymous); + if (xmlDataContract != null) + return xmlDataContract; + + xmlDataContract = new XmlDataContract(Globals.TypeOfSchemaTypePlaceholder); + xmlDataContract.StableName = typeName; + xmlDataContract.IsValueType = false; + AddDataContract(xmlDataContract); + if (xsdType != null) + { + ImportDataContractExtension(xsdType, xmlDataContract); + xmlDataContract.IsValueType = IsValueType(typeName, xsdType.Annotation); + xmlDataContract.IsTypeDefinedOnImport = true; + xmlDataContract.XsdType = isAnonymous ? xsdType : null; + xmlDataContract.HasRoot = !IsXmlAnyElementType(xsdType as XmlSchemaComplexType); + } + else + { + //Value type can be used by both nillable and non-nillable elements but reference type cannot be used by non nillable elements + xmlDataContract.IsValueType = true; + xmlDataContract.IsTypeDefinedOnImport = false; + xmlDataContract.HasRoot = true; + } + if (!isAnonymous) + { + bool isNullable; + xmlDataContract.SetTopLevelElementName(SchemaHelper.GetGlobalElementDeclaration(_schemaSet, typeName, out isNullable)); + xmlDataContract.IsTopLevelElementNullable = isNullable; + } + return xmlDataContract; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private XmlDataContract? ImportSpecialXmlDataType(XmlSchemaType xsdType, bool isAnonymous) + { + if (!isAnonymous) + return null; + XmlSchemaComplexType? complexType = xsdType as XmlSchemaComplexType; + if (complexType == null) + return null; + if (IsXmlAnyElementType(complexType)) + { + //check if the type is XElement + XmlQualifiedName xlinqTypeName = new XmlQualifiedName("XElement", "http://schemas.datacontract.org/2004/07/System.Xml.Linq"); + Type? referencedType; + if (_dataContractSet.TryGetReferencedType(xlinqTypeName, null, out referencedType) + && Globals.TypeOfIXmlSerializable.IsAssignableFrom(referencedType)) + { + XmlDataContract xmlDataContract = new XmlDataContract(referencedType); + AddDataContract(xmlDataContract); + return xmlDataContract; + } + //otherwise, assume XmlElement + return (XmlDataContract?)DataContract.GetBuiltInDataContract(Globals.TypeOfXmlElement); + } + if (IsXmlAnyType(complexType)) + return (XmlDataContract?)DataContract.GetBuiltInDataContract(Globals.TypeOfXmlNodeArray); + return null; + } + + private static bool IsXmlAnyElementType(XmlSchemaComplexType? xsdType) + { + if (xsdType == null) + return false; + + if (xsdType.Particle is XmlSchemaSequence sequence) + { + if (sequence.Items == null || sequence.Items.Count != 1) + return false; + + XmlSchemaAny? any = sequence.Items[0] as XmlSchemaAny; + if (any == null || any.Namespace != null) + return false; + + if (xsdType.AnyAttribute != null || (xsdType.Attributes != null && xsdType.Attributes.Count > 0)) + return false; + + return true; + } + + return false; + } + + private static bool IsXmlAnyType(XmlSchemaComplexType xsdType) + { + if (xsdType == null) + return false; + + if (xsdType.Particle is XmlSchemaSequence sequence) + { + if (sequence.Items == null || sequence.Items.Count != 1) + return false; + + XmlSchemaAny? any = sequence.Items[0] as XmlSchemaAny; + if (any == null || any.Namespace != null) + return false; + + if (any.MaxOccurs != decimal.MaxValue) + return false; + + if (xsdType.AnyAttribute == null || xsdType.Attributes.Count > 0) + return false; + + return true; + } + + return false; + } + + private static bool IsValueType(XmlQualifiedName typeName, XmlSchemaAnnotation? annotation) + { + string? isValueTypeInnerText = GetInnerText(typeName, ImportAnnotation(annotation, SchemaExporter.IsValueTypeName)); + if (isValueTypeInnerText != null) + { + try + { + return XmlConvert.ToBoolean(isValueTypeInnerText); + } + catch (FormatException fe) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.IsValueTypeFormattedIncorrectly, isValueTypeInnerText, fe.Message)); + } + } + return false; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private ClassDataContract ImportISerializable(XmlQualifiedName typeName, XmlSchemaSequence rootSequence, XmlQualifiedName? baseTypeName, XmlSchemaObjectCollection attributes, XmlSchemaAnnotation? annotation) + { + ClassDataContract dataContract = new ClassDataContract(Globals.TypeOfSchemaTypePlaceholder); + dataContract.StableName = typeName; + dataContract.IsISerializable = true; + AddDataContract(dataContract); + + dataContract.IsValueType = IsValueType(typeName, annotation); + if (baseTypeName == null) + CheckISerializableBase(typeName, rootSequence, attributes); + else + { + ImportBaseContract(baseTypeName, dataContract); + Debug.Assert(dataContract.BaseContract != null); // ImportBaseContract will always set this... or throw. + if (!dataContract.BaseContract.IsISerializable) + ThrowISerializableTypeCannotBeImportedException(dataContract.StableName.Name, dataContract.StableName.Namespace, SR.Format(SR.BaseTypeNotISerializable, baseTypeName.Name, baseTypeName.Namespace)); + if (!IsISerializableDerived(typeName, rootSequence)) + ThrowISerializableTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ISerializableDerivedContainsOneOrMoreItems)); + } + + return dataContract; + } + + private static void CheckISerializableBase(XmlQualifiedName typeName, XmlSchemaSequence? rootSequence, XmlSchemaObjectCollection attributes) + { + if (rootSequence == null) + ThrowISerializableTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ISerializableDoesNotContainAny)); + + if (rootSequence.Items == null || rootSequence.Items.Count < 1) + ThrowISerializableTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ISerializableDoesNotContainAny)); + else if (rootSequence.Items.Count > 1) + ThrowISerializableTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ISerializableContainsMoreThanOneItems)); + + XmlSchemaObject o = rootSequence.Items[0]; + if (!(o is XmlSchemaAny)) + ThrowISerializableTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ISerializableDoesNotContainAny)); + + XmlSchemaAny wildcard = (XmlSchemaAny)o; + XmlSchemaAny iSerializableWildcardElement = SchemaExporter.ISerializableWildcardElement; + if (wildcard.MinOccurs != iSerializableWildcardElement.MinOccurs) + ThrowISerializableTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ISerializableWildcardMinOccursMustBe, iSerializableWildcardElement.MinOccurs)); + if (wildcard.MaxOccursString != iSerializableWildcardElement.MaxOccursString) + ThrowISerializableTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ISerializableWildcardMaxOccursMustBe, iSerializableWildcardElement.MaxOccursString)); + if (wildcard.Namespace != iSerializableWildcardElement.Namespace) + ThrowISerializableTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ISerializableWildcardNamespaceInvalid, iSerializableWildcardElement.Namespace)); + if (wildcard.ProcessContents != iSerializableWildcardElement.ProcessContents) + ThrowISerializableTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ISerializableWildcardProcessContentsInvalid, iSerializableWildcardElement.ProcessContents)); + + XmlQualifiedName factoryTypeAttributeRefName = SchemaExporter.ISerializableFactoryTypeAttribute.RefName; + bool containsFactoryTypeAttribute = false; + if (attributes != null) + { + for (int i = 0; i < attributes.Count; i++) + { + o = attributes[i]; + if (o is XmlSchemaAttribute) + { + if (((XmlSchemaAttribute)o).RefName == factoryTypeAttributeRefName) + { + containsFactoryTypeAttribute = true; + break; + } + } + } + } + if (!containsFactoryTypeAttribute) + ThrowISerializableTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ISerializableMustRefFactoryTypeAttribute, factoryTypeAttributeRefName.Name, factoryTypeAttributeRefName.Namespace)); + } + + private static bool IsISerializableDerived(XmlQualifiedName typeName, XmlSchemaSequence? rootSequence) + { + return (rootSequence == null || rootSequence.Items == null || rootSequence.Items.Count == 0); + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private void ImportBaseContract(XmlQualifiedName baseTypeName, ClassDataContract dataContract) + { + ClassDataContract? baseContract = ImportType(baseTypeName) as ClassDataContract; + if (baseContract == null) + ThrowTypeCannotBeImportedException(dataContract.StableName.Name, dataContract.StableName.Namespace, SR.Format(dataContract.IsISerializable ? SR.InvalidISerializableDerivation : SR.InvalidClassDerivation, baseTypeName.Name, baseTypeName.Namespace)); + + // Note: code ignores IsValueType annotation if derived type exists + if (baseContract.IsValueType) + baseContract.IsValueType = false; + + ClassDataContract? ancestorDataContract = baseContract; + while (ancestorDataContract != null) + { + DataContractDictionary? knownDataContracts = ancestorDataContract.KnownDataContracts; + if (knownDataContracts == null) + { + knownDataContracts = new DataContractDictionary(); + ancestorDataContract.KnownDataContracts = knownDataContracts; + } + knownDataContracts.Add(dataContract.StableName, dataContract); + ancestorDataContract = ancestorDataContract.BaseContract; + } + + dataContract.BaseContract = baseContract; + } + + private void ImportTopLevelElement(XmlQualifiedName typeName) + { + XmlSchemaElement? topLevelElement = SchemaHelper.GetSchemaElement(SchemaObjects, typeName); + // Top level element of same name is not required, but is validated if it is present + if (topLevelElement == null) + return; + else + { + XmlQualifiedName elementTypeName = topLevelElement.SchemaTypeName; + if (elementTypeName.IsEmpty) + { + if (topLevelElement.SchemaType != null) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.AnonymousTypeNotSupported, typeName.Name, typeName.Namespace)); + else + elementTypeName = SchemaExporter.AnytypeQualifiedName; + } + if (elementTypeName != typeName) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.TopLevelElementRepresentsDifferentType, topLevelElement.SchemaTypeName.Name, topLevelElement.SchemaTypeName.Namespace)); + CheckIfElementUsesUnsupportedConstructs(typeName, topLevelElement); + } + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private void ImportClassMember(XmlSchemaElement element, ClassDataContract dataContract) + { + XmlQualifiedName typeName = dataContract.StableName; + + Debug.Assert(element.Name != null); + + if (element.MinOccurs > 1) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ElementMinOccursMustBe, element.Name)); + if (element.MaxOccurs != 1) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ElementMaxOccursMustBe, element.Name)); + + DataContract? memberTypeContract = null; + string memberName = element.Name; + bool memberIsRequired = (element.MinOccurs > 0); + bool memberIsNullable = element.IsNillable; + bool memberEmitDefaultValue; + int memberOrder = 0; + + XmlSchemaForm elementForm = element.Form; + if (elementForm == XmlSchemaForm.None) + { + XmlSchema? schema = SchemaHelper.GetSchemaWithType(SchemaObjects, _schemaSet, typeName); + if (schema != null) + elementForm = schema.ElementFormDefault; + } + if (elementForm != XmlSchemaForm.Qualified) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.FormMustBeQualified, element.Name)); + CheckIfElementUsesUnsupportedConstructs(typeName, element); + + if (element.SchemaTypeName.IsEmpty) + { + if (element.SchemaType != null) + memberTypeContract = ImportAnonymousElement(element, new XmlQualifiedName(string.Format(CultureInfo.InvariantCulture, "{0}.{1}Type", typeName.Name, element.Name), typeName.Namespace)); + else if (!element.RefName.IsEmpty) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ElementRefOnLocalElementNotSupported, element.RefName.Name, element.RefName.Namespace)); + else + memberTypeContract = ImportType(SchemaExporter.AnytypeQualifiedName); + } + else + { + XmlQualifiedName memberTypeName = ImportActualType(element.Annotation, element.SchemaTypeName, typeName); + memberTypeContract = ImportType(memberTypeName); + if (IsObjectContract(memberTypeContract)) + _needToImportKnownTypesForObject = true; + } + bool? emitDefaultValueFromAnnotation = ImportEmitDefaultValue(element.Annotation, typeName); + if (!memberTypeContract.IsValueType && !memberIsNullable) + { + if (emitDefaultValueFromAnnotation != null && emitDefaultValueFromAnnotation.Value) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidEmitDefaultAnnotation, memberName, typeName.Name, typeName.Namespace))); + memberEmitDefaultValue = false; + } + else + memberEmitDefaultValue = emitDefaultValueFromAnnotation != null ? emitDefaultValueFromAnnotation.Value : Globals.DefaultEmitDefaultValue; + + Debug.Assert(dataContract.Members != null); // This method is only called from ImportClass() after that method has initialized the Members collection. + + int prevMemberIndex = dataContract.Members.Count - 1; + if (prevMemberIndex >= 0) + { + DataMember prevMember = dataContract.Members![prevMemberIndex]; + if (prevMember.Order > Globals.DefaultOrder) + memberOrder = dataContract.Members.Count; + DataMember currentMember = new DataMember(memberTypeContract, memberName, memberIsNullable, memberIsRequired, memberEmitDefaultValue, memberOrder); + int compare = ClassDataContract.DataMemberComparer.Singleton.Compare(prevMember, currentMember); + if (compare == 0) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.CannotHaveDuplicateElementNames, memberName)); + else if (compare > 0) + memberOrder = dataContract.Members.Count; + } + DataMember dataMember = new DataMember(memberTypeContract, memberName, memberIsNullable, memberIsRequired, memberEmitDefaultValue, memberOrder); + + XmlQualifiedName surrogateDataAnnotationName = SchemaExporter.SurrogateDataAnnotationName; + _dataContractSet.SetSurrogateData(dataMember, ImportSurrogateData(ImportAnnotation(element.Annotation, surrogateDataAnnotationName), surrogateDataAnnotationName.Name, surrogateDataAnnotationName.Namespace)); + + dataContract.Members.Add(dataMember); + } + + private static bool? ImportEmitDefaultValue(XmlSchemaAnnotation? annotation, XmlQualifiedName typeName) + { + XmlElement? defaultValueElement = ImportAnnotation(annotation, SchemaExporter.DefaultValueAnnotation); + if (defaultValueElement == null) + return null; + XmlNode? emitDefaultValueAttribute = defaultValueElement.Attributes.GetNamedItem(Globals.EmitDefaultValueAttribute); + if (emitDefaultValueAttribute?.Value == null) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.AnnotationAttributeNotFound, SchemaExporter.DefaultValueAnnotation.Name, typeName.Name, typeName.Namespace, Globals.EmitDefaultValueAttribute))); + return XmlConvert.ToBoolean(emitDefaultValueAttribute.Value); + } + + internal static XmlQualifiedName ImportActualType(XmlSchemaAnnotation? annotation, XmlQualifiedName defaultTypeName, XmlQualifiedName typeName) + { + XmlElement? actualTypeElement = ImportAnnotation(annotation, SchemaExporter.ActualTypeAnnotationName); + if (actualTypeElement == null) + return defaultTypeName; + + XmlNode? nameAttribute = actualTypeElement.Attributes.GetNamedItem(Globals.ActualTypeNameAttribute); + if (nameAttribute?.Value == null) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.AnnotationAttributeNotFound, SchemaExporter.ActualTypeAnnotationName.Name, typeName.Name, typeName.Namespace, Globals.ActualTypeNameAttribute))); + XmlNode? nsAttribute = actualTypeElement.Attributes.GetNamedItem(Globals.ActualTypeNamespaceAttribute); + if (nsAttribute?.Value == null) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.AnnotationAttributeNotFound, SchemaExporter.ActualTypeAnnotationName.Name, typeName.Name, typeName.Namespace, Globals.ActualTypeNamespaceAttribute))); + return new XmlQualifiedName(nameAttribute.Value, nsAttribute.Value); + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private CollectionDataContract ImportCollection(XmlQualifiedName typeName, XmlSchemaSequence rootSequence, XmlSchemaObjectCollection attributes, XmlSchemaAnnotation? annotation, bool isReference) + { + CollectionDataContract dataContract = new CollectionDataContract(Globals.TypeOfSchemaTypePlaceholder, CollectionKind.Array); + dataContract.StableName = typeName; + AddDataContract(dataContract); + + dataContract.IsReference = isReference; + + // CheckIfCollection has already checked if sequence contains exactly one item with maxOccurs="unbounded" or maxOccurs > 1 + XmlSchemaElement element = (XmlSchemaElement)rootSequence.Items[0]; + + Debug.Assert(element.Name != null); + + dataContract.IsItemTypeNullable = element.IsNillable; + dataContract.ItemName = element.Name; + + XmlSchemaForm elementForm = element.Form; + if (elementForm == XmlSchemaForm.None) + { + XmlSchema? schema = SchemaHelper.GetSchemaWithType(SchemaObjects, _schemaSet, typeName); + if (schema != null) + elementForm = schema.ElementFormDefault; + } + if (elementForm != XmlSchemaForm.Qualified) + ThrowArrayTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ArrayItemFormMustBe, element.Name)); + CheckIfElementUsesUnsupportedConstructs(typeName, element); + + if (element.SchemaTypeName.IsEmpty) + { + if (element.SchemaType != null) + { + XmlQualifiedName shortName = new XmlQualifiedName(element.Name, typeName.Namespace); + DataContract? contract = _dataContractSet[shortName]; + if (contract == null) + { + dataContract.ItemContract = ImportAnonymousElement(element, shortName); + } + else + { + XmlQualifiedName fullName = new XmlQualifiedName(string.Format(CultureInfo.InvariantCulture, "{0}.{1}Type", typeName.Name, element.Name), typeName.Namespace); + dataContract.ItemContract = ImportAnonymousElement(element, fullName); + } + } + else if (!element.RefName.IsEmpty) + ThrowArrayTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ElementRefOnLocalElementNotSupported, element.RefName.Name, element.RefName.Namespace)); + else + dataContract.ItemContract = ImportType(SchemaExporter.AnytypeQualifiedName); + } + else + { + dataContract.ItemContract = ImportType(element.SchemaTypeName); + } + + if (IsDictionary(typeName, annotation)) + { + ClassDataContract? keyValueContract = dataContract.ItemContract as ClassDataContract; + DataMember key = null!, value = null!; // Set in the following || conditional chain. If the chain triggers before setting these, an exception is thrown. + if (keyValueContract == null || keyValueContract.Members == null || keyValueContract.Members.Count != 2 + || !(key = keyValueContract.Members[0]).IsRequired || !(value = keyValueContract.Members[1]).IsRequired) + { + ThrowArrayTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.InvalidKeyValueType, element.Name)); + } + if (keyValueContract.Namespace != dataContract.Namespace) + { + ThrowArrayTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.InvalidKeyValueTypeNamespace, element.Name, keyValueContract.Namespace)); + } + keyValueContract.IsValueType = true; + dataContract.KeyName = key.Name; + dataContract.ValueName = value.Name; + if (element.SchemaType != null) + { + _dataContractSet.Remove(keyValueContract.StableName); + + GenericInfo genericInfo = new GenericInfo(DataContract.GetStableName(Globals.TypeOfKeyValue), Globals.TypeOfKeyValue.FullName); + genericInfo.Add(GetGenericInfoForDataMember(key)); + genericInfo.Add(GetGenericInfoForDataMember(value)); + genericInfo.AddToLevel(0, 2); + dataContract.ItemContract.StableName = new XmlQualifiedName(genericInfo.GetExpandedStableName().Name, typeName.Namespace); + } + } + + return dataContract; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private static GenericInfo GetGenericInfoForDataMember(DataMember dataMember) + { + GenericInfo genericInfo; + if (dataMember.MemberTypeContract.IsValueType && dataMember.IsNullable) + { + genericInfo = new GenericInfo(DataContract.GetStableName(Globals.TypeOfNullable), Globals.TypeOfNullable.FullName); + genericInfo.Add(new GenericInfo(dataMember.MemberTypeContract.StableName, null)); + } + else + { + genericInfo = new GenericInfo(dataMember.MemberTypeContract.StableName, null); + } + + return genericInfo; + } + + private static bool IsDictionary(XmlQualifiedName typeName, XmlSchemaAnnotation? annotation) + { + string? isDictionaryInnerText = GetInnerText(typeName, ImportAnnotation(annotation, SchemaExporter.IsDictionaryAnnotationName)); + if (isDictionaryInnerText != null) + { + try + { + return XmlConvert.ToBoolean(isDictionaryInnerText); + } + catch (FormatException fe) + { + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.IsDictionaryFormattedIncorrectly, isDictionaryInnerText, fe.Message)); + } + } + return false; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private EnumDataContract? ImportFlagsEnum(XmlQualifiedName typeName, XmlSchemaSimpleTypeList list, XmlSchemaAnnotation? annotation) + { + XmlSchemaSimpleType? anonymousType = list.ItemType; + if (anonymousType == null) + ThrowEnumTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.EnumListMustContainAnonymousType)); + + XmlSchemaSimpleTypeContent? content = anonymousType.Content; + if (content is XmlSchemaSimpleTypeUnion) + ThrowEnumTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.EnumUnionInAnonymousTypeNotSupported)); + else if (content is XmlSchemaSimpleTypeList) + ThrowEnumTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.EnumListInAnonymousTypeNotSupported)); + else if (content is XmlSchemaSimpleTypeRestriction) + { + if (content is XmlSchemaSimpleTypeRestriction restriction && CheckIfEnum(restriction)) + return ImportEnum(typeName, restriction, true /*isFlags*/, annotation); + else + ThrowEnumTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.EnumRestrictionInvalid)); + } + return null; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private EnumDataContract ImportEnum(XmlQualifiedName typeName, XmlSchemaSimpleTypeRestriction restriction, bool isFlags, XmlSchemaAnnotation? annotation) + { + EnumDataContract dataContract = new EnumDataContract(Globals.TypeOfSchemaTypePlaceholder); + dataContract.StableName = typeName; + dataContract.BaseContractName = ImportActualType(annotation, SchemaExporter.DefaultEnumBaseTypeName, typeName); + dataContract.IsFlags = isFlags; + AddDataContract(dataContract); + + // CheckIfEnum has already checked if baseType of restriction is string + dataContract.Values = new List(); + dataContract.Members = new List(); + foreach (XmlSchemaFacet facet in restriction.Facets) + { + XmlSchemaEnumerationFacet? enumFacet = facet as XmlSchemaEnumerationFacet; + if (enumFacet == null) + ThrowEnumTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.EnumOnlyEnumerationFacetsSupported)); + if (enumFacet.Value == null) + ThrowEnumTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.EnumEnumerationFacetsMustHaveValue)); + + string? valueInnerText = GetInnerText(typeName, ImportAnnotation(enumFacet.Annotation, SchemaExporter.EnumerationValueAnnotationName)); + if (valueInnerText == null) + dataContract.Values.Add(SchemaExporter.GetDefaultEnumValue(isFlags, dataContract.Members.Count)); + else + dataContract.Values.Add(dataContract.GetEnumValueFromString(valueInnerText)); + DataMember dataMember = new DataMember(Globals.SchemaMemberInfoPlaceholder) { Name = enumFacet.Value }; + dataContract.Members.Add(dataMember); + } + return dataContract; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private DataContract ImportSimpleTypeRestriction(XmlQualifiedName typeName, XmlSchemaSimpleTypeRestriction restriction) + { + DataContract dataContract = null!; // Always assigned by one of the ImportType()s, or exception is thrown. + + if (!restriction.BaseTypeName.IsEmpty) + dataContract = ImportType(restriction.BaseTypeName); + else if (restriction.BaseType != null) + dataContract = ImportType(restriction.BaseType); + else + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.SimpleTypeRestrictionDoesNotSpecifyBase)); + + return dataContract; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private void ImportDataContractExtension(XmlSchemaType type, DataContract dataContract) + { + if (type.Annotation == null || type.Annotation.Items == null) + return; + foreach (XmlSchemaObject schemaObject in type.Annotation.Items) + { + if (schemaObject is XmlSchemaAppInfo appInfo && appInfo.Markup != null) + { + foreach (XmlNode? xmlNode in appInfo.Markup) + { + XmlElement? typeElement = xmlNode as XmlElement; + XmlQualifiedName surrogateDataAnnotationName = SchemaExporter.SurrogateDataAnnotationName; + if (typeElement != null && typeElement.NamespaceURI == surrogateDataAnnotationName.Namespace && typeElement.LocalName == surrogateDataAnnotationName.Name) + { + object? surrogateData = ImportSurrogateData(typeElement, surrogateDataAnnotationName.Name, surrogateDataAnnotationName.Namespace); + _dataContractSet.SetSurrogateData(dataContract, surrogateData); + } + } + } + } + } + + private void ImportGenericInfo(XmlSchemaType type, DataContract dataContract) + { + if (type.Annotation == null || type.Annotation.Items == null) + return; + foreach (XmlSchemaObject schemaObject in type.Annotation.Items) + { + if (schemaObject is XmlSchemaAppInfo appInfo && appInfo.Markup != null) + { + foreach (XmlNode? xmlNode in appInfo.Markup) + { + XmlElement? typeElement = xmlNode as XmlElement; + if (typeElement != null && typeElement.NamespaceURI == Globals.SerializationNamespace) + { + if (typeElement.LocalName == Globals.GenericTypeLocalName) + dataContract.GenericInfo = ImportGenericInfo(typeElement, type); + } + } + } + } + } + + private GenericInfo ImportGenericInfo(XmlElement typeElement, XmlSchemaType type) + { + string? name = typeElement.Attributes.GetNamedItem(Globals.GenericNameAttribute)?.Value; + if (name == null) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericAnnotationAttributeNotFound, type.Name, Globals.GenericNameAttribute))); + string? ns = typeElement.Attributes.GetNamedItem(Globals.GenericNamespaceAttribute)?.Value; + if (ns == null) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericAnnotationAttributeNotFound, type.Name, Globals.GenericNamespaceAttribute))); + if (typeElement.ChildNodes.Count > 0) //Generic Type + name = DataContract.EncodeLocalName(name); + + int currentLevel = 0; + GenericInfo genInfo = new GenericInfo(new XmlQualifiedName(name, ns), type.Name); + foreach (XmlNode childNode in typeElement.ChildNodes) + { + if (childNode is XmlElement argumentElement) + { + if (argumentElement.LocalName != Globals.GenericParameterLocalName || + argumentElement.NamespaceURI != Globals.SerializationNamespace) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericAnnotationHasInvalidElement, argumentElement.LocalName, argumentElement.NamespaceURI, type.Name))); + XmlNode? nestedLevelAttribute = argumentElement.Attributes.GetNamedItem(Globals.GenericParameterNestedLevelAttribute); + int argumentLevel = 0; + if (nestedLevelAttribute != null) + { + if (!int.TryParse(nestedLevelAttribute.Value, out argumentLevel)) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericAnnotationHasInvalidAttributeValue, argumentElement.LocalName, argumentElement.NamespaceURI, type.Name, nestedLevelAttribute.Value, nestedLevelAttribute.LocalName, Globals.TypeOfInt.Name))); + } + if (argumentLevel < currentLevel) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericAnnotationForNestedLevelMustBeIncreasing, argumentElement.LocalName, argumentElement.NamespaceURI, type.Name))); + genInfo.Add(ImportGenericInfo(argumentElement, type)); + genInfo.AddToLevel(argumentLevel, 1); + currentLevel = argumentLevel; + } + } + + XmlNode? typeNestedLevelsAttribute = typeElement.Attributes.GetNamedItem(Globals.GenericParameterNestedLevelAttribute); + if (typeNestedLevelsAttribute != null) + { + int nestedLevels; + if (!int.TryParse(typeNestedLevelsAttribute.Value, out nestedLevels)) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericAnnotationHasInvalidAttributeValue, typeElement.LocalName, typeElement.NamespaceURI, type.Name, typeNestedLevelsAttribute.Value, typeNestedLevelsAttribute.LocalName, Globals.TypeOfInt.Name))); + if ((nestedLevels - 1) > currentLevel) + genInfo.AddToLevel(nestedLevels - 1, 0); + } + return genInfo; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private object? ImportSurrogateData(XmlElement? typeElement, string name, string ns) + { + if (_dataContractSet.SerializationExtendedSurrogateProvider != null && typeElement != null) + { + Collection knownTypes = new Collection(); + DataContractSurrogateCaller.GetKnownCustomDataTypes(_dataContractSet.SerializationExtendedSurrogateProvider, knownTypes); + DataContractSerializer serializer = new DataContractSerializer(Globals.TypeOfObject, name, ns, knownTypes, + int.MaxValue, false /*ignoreExtensionDataObject*/, true /*preserveObjectReferences*/); + return serializer.ReadObject(new XmlNodeReader(typeElement)); + } + return null; + } + + private static void CheckComplexType(XmlQualifiedName typeName, XmlSchemaComplexType type) + { + if (type.IsAbstract) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.AbstractTypeNotSupported)); + if (type.IsMixed) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.MixedContentNotSupported)); + } + + private static void CheckIfElementUsesUnsupportedConstructs(XmlQualifiedName typeName, XmlSchemaElement element) + { + if (element.IsAbstract) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.AbstractElementNotSupported, element.Name)); + if (element.DefaultValue != null) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.DefaultOnElementNotSupported, element.Name)); + if (element.FixedValue != null) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.FixedOnElementNotSupported, element.Name)); + if (!element.SubstitutionGroup.IsEmpty) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.SubstitutionGroupOnElementNotSupported, element.Name)); + } + + private static void ImportAttributes(XmlQualifiedName typeName, XmlSchemaObjectCollection attributes, XmlSchemaAnyAttribute? anyAttribute, out bool isReference) + { + if (anyAttribute != null) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.AnyAttributeNotSupported)); + + isReference = false; + if (attributes != null) + { + bool foundId = false, foundRef = false; + for (int i = 0; i < attributes.Count; i++) + { + XmlSchemaObject o = attributes[i]; + if (o is XmlSchemaAttribute attribute) + { + if (attribute.Use == XmlSchemaUse.Prohibited) + continue; + if (TryCheckIfAttribute(typeName, attribute, Globals.IdQualifiedName, ref foundId)) + continue; + if (TryCheckIfAttribute(typeName, attribute, Globals.RefQualifiedName, ref foundRef)) + continue; + if (attribute.RefName.IsEmpty || attribute.RefName.Namespace != Globals.SerializationNamespace || attribute.Use == XmlSchemaUse.Required) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.TypeShouldNotContainAttributes, Globals.SerializationNamespace)); + } + } + isReference = (foundId && foundRef); + } + } + + private static bool TryCheckIfAttribute(XmlQualifiedName typeName, XmlSchemaAttribute attribute, XmlQualifiedName refName, ref bool foundAttribute) + { + if (attribute.RefName != refName) + return false; + if (foundAttribute) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.CannotHaveDuplicateAttributeNames, refName.Name)); + foundAttribute = true; + return true; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private void AddDataContract(DataContract dataContract) + { + _dataContractSet.Add(dataContract.StableName, dataContract); + } + + private static string? GetInnerText(XmlQualifiedName typeName, XmlElement? xmlElement) + { + if (xmlElement != null) + { + XmlNode? child = xmlElement.FirstChild; + while (child != null) + { + if (child.NodeType == XmlNodeType.Element) + ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.InvalidAnnotationExpectingText, xmlElement.LocalName, xmlElement.NamespaceURI, child.LocalName, child.NamespaceURI)); + child = child.NextSibling; + } + return xmlElement.InnerText; + } + return null; + } + + private static XmlElement? ImportAnnotation(XmlSchemaAnnotation? annotation, XmlQualifiedName annotationQualifiedName) + { + if (annotation != null && annotation.Items != null && annotation.Items.Count > 0 && annotation.Items[0] is XmlSchemaAppInfo) + { + XmlSchemaAppInfo appInfo = (XmlSchemaAppInfo)annotation.Items[0]; + XmlNode?[]? markup = appInfo.Markup; + if (markup != null) + { + for (int i = 0; i < markup.Length; i++) + { + XmlElement? annotationElement = markup[i] as XmlElement; + if (annotationElement != null && annotationElement.LocalName == annotationQualifiedName.Name && annotationElement.NamespaceURI == annotationQualifiedName.Namespace) + return annotationElement; + } + } + } + return null; + } + + [DoesNotReturn] + private static void ThrowTypeCannotBeImportedException(string name, string ns, string message) + { + ThrowTypeCannotBeImportedException(SR.Format(SR.TypeCannotBeImported, name, ns, message)); + } + + [DoesNotReturn] + private static void ThrowArrayTypeCannotBeImportedException(string name, string ns, string message) + { + ThrowTypeCannotBeImportedException(SR.Format(SR.ArrayTypeCannotBeImported, name, ns, message)); + } + + [DoesNotReturn] + private static void ThrowEnumTypeCannotBeImportedException(string name, string ns, string message) + { + ThrowTypeCannotBeImportedException(SR.Format(SR.EnumTypeCannotBeImported, name, ns, message)); + } + + [DoesNotReturn] + private static void ThrowISerializableTypeCannotBeImportedException(string name, string ns, string message) + { + ThrowTypeCannotBeImportedException(SR.Format(SR.ISerializableTypeCannotBeImported, name, ns, message)); + } + + [DoesNotReturn] + private static void ThrowTypeCannotBeImportedException(string message) + { + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.TypeCannotBeImportedHowToFix, message))); + } + } + +} diff --git a/src/libraries/System.Runtime.Serialization.Primitives/ref/System.Runtime.Serialization.Primitives.cs b/src/libraries/System.Runtime.Serialization.Primitives/ref/System.Runtime.Serialization.Primitives.cs index 92749bc455abe..043023f6bdcfa 100644 --- a/src/libraries/System.Runtime.Serialization.Primitives/ref/System.Runtime.Serialization.Primitives.cs +++ b/src/libraries/System.Runtime.Serialization.Primitives/ref/System.Runtime.Serialization.Primitives.cs @@ -3,6 +3,8 @@ // ------------------------------------------------------------------------------ // Changes to this file must follow the https://aka.ms/api-review process. // ------------------------------------------------------------------------------ +using System.Collections.ObjectModel; +using System.Reflection; namespace System.Runtime.Serialization { @@ -76,6 +78,13 @@ public partial interface ISerializationSurrogateProvider object GetObjectToSerialize(object obj, System.Type targetType); System.Type GetSurrogateType(System.Type type); } + public interface ISerializationExtendedSurrogateProvider : ISerializationSurrogateProvider + { + object? GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType); + object? GetCustomDataToExport(Type clrType, Type dataContractType); + void GetKnownCustomDataTypes(Collection customDataTypes); + Type? GetReferencedTypeOnImport(string typeName, string typeNamespace, object? customData); + } [System.AttributeUsageAttribute(System.AttributeTargets.Class | System.AttributeTargets.Struct, Inherited=true, AllowMultiple=true)] public sealed partial class KnownTypeAttribute : System.Attribute { diff --git a/src/libraries/System.Runtime.Serialization.Primitives/src/System.Runtime.Serialization.Primitives.csproj b/src/libraries/System.Runtime.Serialization.Primitives/src/System.Runtime.Serialization.Primitives.csproj index 13aff766d38dd..cdadada2f3fea 100644 --- a/src/libraries/System.Runtime.Serialization.Primitives/src/System.Runtime.Serialization.Primitives.csproj +++ b/src/libraries/System.Runtime.Serialization.Primitives/src/System.Runtime.Serialization.Primitives.csproj @@ -11,6 +11,7 @@ + diff --git a/src/libraries/System.Runtime.Serialization.Primitives/src/System/Runtime/Serialization/ISerializationExtendedSurrogateProvider.cs b/src/libraries/System.Runtime.Serialization.Primitives/src/System/Runtime/Serialization/ISerializationExtendedSurrogateProvider.cs new file mode 100644 index 0000000000000..857544cd2c88e --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Primitives/src/System/Runtime/Serialization/ISerializationExtendedSurrogateProvider.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.ObjectModel; +using System.Reflection; + +namespace System.Runtime.Serialization +{ + public interface ISerializationExtendedSurrogateProvider : ISerializationSurrogateProvider + { + object? GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType); + object? GetCustomDataToExport(Type clrType, Type dataContractType); + void GetKnownCustomDataTypes(Collection customDataTypes); + Type? GetReferencedTypeOnImport(string typeName, string typeNamespace, object? customData); + } +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/Directory.Build.props b/src/libraries/System.Runtime.Serialization.Schema/Directory.Build.props new file mode 100644 index 0000000000000..72712f3351c12 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/Directory.Build.props @@ -0,0 +1,7 @@ + + + + true + browser;ios;tvos;maccatalyst + + \ No newline at end of file diff --git a/src/libraries/System.Runtime.Serialization.Schema/System.Runtime.Serialization.Schema.sln b/src/libraries/System.Runtime.Serialization.Schema/System.Runtime.Serialization.Schema.sln new file mode 100644 index 0000000000000..b273f4e5bf616 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/System.Runtime.Serialization.Schema.sln @@ -0,0 +1,51 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{A83DE19F-4E19-4FEE-A3D7-FBA9E065B186}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.Serialization.Schema", "ref\System.Runtime.Serialization.Schema.csproj", "{74AE27CF-E940-4EEB-9A19-0968689B627E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.Serialization.Schema", "src\System.Runtime.Serialization.Schema.csproj", "{14D5A803-D5BF-44E5-B2B5-0B0BC297748E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Runtime.Serialization.Schema.Tests", "tests\System.Runtime.Serialization.Schema.Tests.csproj", "{627FFEFC-A317-4AD1-809F-B26CA7F475BD}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{2D7D470B-B092-45BC-900A-CDB20CA94BE7}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{54321C0F-1323-4962-A01C-AC07028C3FA8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{6591788E-0894-4655-AE2F-602407C4F766}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A83DE19F-4E19-4FEE-A3D7-FBA9E065B186}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A83DE19F-4E19-4FEE-A3D7-FBA9E065B186}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A83DE19F-4E19-4FEE-A3D7-FBA9E065B186}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A83DE19F-4E19-4FEE-A3D7-FBA9E065B186}.Release|Any CPU.Build.0 = Release|Any CPU + {74AE27CF-E940-4EEB-9A19-0968689B627E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {74AE27CF-E940-4EEB-9A19-0968689B627E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {74AE27CF-E940-4EEB-9A19-0968689B627E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {74AE27CF-E940-4EEB-9A19-0968689B627E}.Release|Any CPU.Build.0 = Release|Any CPU + {14D5A803-D5BF-44E5-B2B5-0B0BC297748E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {14D5A803-D5BF-44E5-B2B5-0B0BC297748E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {14D5A803-D5BF-44E5-B2B5-0B0BC297748E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {14D5A803-D5BF-44E5-B2B5-0B0BC297748E}.Release|Any CPU.Build.0 = Release|Any CPU + {627FFEFC-A317-4AD1-809F-B26CA7F475BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {627FFEFC-A317-4AD1-809F-B26CA7F475BD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {627FFEFC-A317-4AD1-809F-B26CA7F475BD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {627FFEFC-A317-4AD1-809F-B26CA7F475BD}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {A83DE19F-4E19-4FEE-A3D7-FBA9E065B186} = {2D7D470B-B092-45BC-900A-CDB20CA94BE7} + {627FFEFC-A317-4AD1-809F-B26CA7F475BD} = {2D7D470B-B092-45BC-900A-CDB20CA94BE7} + {74AE27CF-E940-4EEB-9A19-0968689B627E} = {54321C0F-1323-4962-A01C-AC07028C3FA8} + {14D5A803-D5BF-44E5-B2B5-0B0BC297748E} = {6591788E-0894-4655-AE2F-602407C4F766} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {70EC5780-3C80-4D52-93B0-7FBF64E29572} + EndGlobalSection +EndGlobal diff --git a/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.cs b/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.cs new file mode 100644 index 0000000000000..bd1d054ff3fb7 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.cs @@ -0,0 +1,9 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// ------------------------------------------------------------------------------ +// Changes to this file must follow the https://aka.ms/api-review process. +// ------------------------------------------------------------------------------ + +namespace System.Runtime.Serialization.Schema +{ +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.csproj b/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.csproj new file mode 100644 index 0000000000000..8c84ddc8702b2 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.csproj @@ -0,0 +1,9 @@ + + + $(NetCoreAppCurrent) + + + + + + \ No newline at end of file diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/Resources/Strings.resx b/src/libraries/System.Runtime.Serialization.Schema/src/Resources/Strings.resx new file mode 100644 index 0000000000000..e1037028d6fb5 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/src/Resources/Strings.resx @@ -0,0 +1,1534 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Invalid '{0}' annotation in type '{1}' from namespace '{2}'. Attribute '{3}' not present. + + + Cannot export null assembly provided via '{0}' parameter. + + + Cannot export null type provided via KnownTypesCollection. + + + Cannot export null type provided via '{0}' parameter. + + + Existing type '{0}' specified via the referenced types collection has been referenced in the generated code. Members cannot be added for this type since it cannot be modified. + + + Existing type '{0}' specified via the referenced types collection has been referenced in the generated code. Cannot set namespace for this type since it cannot be modified. + + + Type '{0}' cannot be exported as a schema type because it is an open generic type. You can only export a generic type if all its generic parameter types are actual types. + + + Type '{0}' from namespace '{1}' has not been imported from schema. Consider first importing this type by calling one of the Import methods on XsdDataContractImporter. + + + + A unique name cannot be computed for '{0}' because there are already Int32.MaxValue types of with the same name. + + + Type with data contract name '{0}' in namespace '{1}' cannot be imported. Cannot derive from sealed referenced type '{2}'. + + + Collection type cannot be generated for type '{0}' from namespace '{1}'. Cannot use a generic list type as a base type because the language does not support generic type references. + + + It contains a circular reference for type '{0}' from namespace '{1}'. + + + CLR namespace '{2}' has already been mapped to data contract namespace '{0}'. It cannot be mapped to another data contract namespace '{1}'. + + + DataContract name '{0}' from namespace '{1}' does not match the generic name '{2}' from namespace '{3}'. + + + ISerializable type with data contract name '{0}' in namespace '{1}' cannot be imported. The data contract name cannot be customized for ISerializable type and the generated name '{2}' does not match the expected name '{0}'. Check if the required name has been mapped to a different type or if it is an invalid CLR name which cannot be generated or if the type requires an outer type which is not present. + + + ISerializable type with data contract name '{0}' in namespace '{1}' cannot be imported. The data contract namespace cannot be customized for ISerializable types and the generated namespace '{3}' does not match the required CLR namespace '{2}'. Check if the required namespace has been mapped to a different data contract namespace and consider mapping it explicitly using the namespaces collection. + + + Collection type cannot be generated for type '{0}' from namespace '{1}'. Rename the type to '{2}' in namespace '{3}' or reference an existing collection type that implements '{4}' or '{5}' which can be used as a base type for the generated collection. + + + Referenced type '{0}' with data contract name '{1}' in namespace '{2}' cannot be used since it does not match imported DataContract. Need to exclude this type from referenced types. + + + Type '{0}' in namespace '{1}' cannot be imported. {2} + + + Schema type '{2}' in namespace '{3}' must be imported as an XML type. Type '{0}' cannot be mapped to this schema type because it does not implement '{1}'. Consider not adding type '{0}' to the list of referenced types or changing it to implement '{1}'. + + + An internal error has occurred. Unexpected contract type '{0}' for type '{1}' encountered. + + + + + + + diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj b/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj new file mode 100644 index 0000000000000..44030932998b5 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj @@ -0,0 +1,52 @@ + + + $(NetCoreAppCurrent) + true + $(DefineConstants) + $(NoWarn);1634;1691;649 + Microsoft + + + false + + false + + + false + Provides support for importing and exporting xsd schemas for DataContractSerializer. + +Commonly Used Types: +System.Runtime.Serialization.Schema.XsdDataContractExporter +System.Runtime.Serialization.Schema.XsdDataContractImporter + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs new file mode 100644 index 0000000000000..fffcafed85a0f --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs @@ -0,0 +1,2044 @@ +// 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.CodeDom; +using System.CodeDom.Compiler; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Reflection; +using System.Runtime.Serialization; +using System.Security; +using System.Text; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; + +using DataContractDictionary = System.Collections.Generic.Dictionary; +using ExceptionUtil = System.Runtime.Serialization.Schema.DiagnosticUtility.ExceptionUtility; + +namespace System.Runtime.Serialization.Schema +{ + internal sealed class CodeExporter + { + private const string WildcardNamespaceMapping = "*"; + private const string TypeNameFieldName = "typeName"; + private const int MaxIdentifierLength = 511; + + private static readonly object s_codeUserDataActualTypeKey = new object(); + private static readonly object s_surrogateDataKey = typeof(ISerializationExtendedSurrogateProvider); + + private DataContractSet _dataContractSet; + private CodeCompileUnit _codeCompileUnit; + private ImportOptions? _options; + private Dictionary _namespaces; + private Dictionary _clrNamespaces; + + internal CodeExporter(DataContractSet dataContractSet, ImportOptions? options, CodeCompileUnit codeCompileUnit) + { + _dataContractSet = dataContractSet; + _codeCompileUnit = codeCompileUnit; + AddReferencedAssembly(Assembly.GetExecutingAssembly()); + _options = options; + _namespaces = new Dictionary(); + _clrNamespaces = new Dictionary(StringComparer.OrdinalIgnoreCase); + + // Update namespace tables for DataContract(s) that are already processed + foreach (KeyValuePair pair in dataContractSet) + { + DataContract dataContract = pair.Value; + if (!(dataContract.IsBuiltInDataContract || dataContract is CollectionDataContract)) + { + ContractCodeDomInfo contractCodeDomInfo = GetContractCodeDomInfo(dataContract); + if (contractCodeDomInfo.IsProcessed && !contractCodeDomInfo.UsesWildcardNamespace) + { + string? clrNamespace = contractCodeDomInfo.ClrNamespace; + if (clrNamespace != null && !_clrNamespaces.ContainsKey(clrNamespace)) + { + _clrNamespaces.Add(clrNamespace, dataContract.StableName.Namespace); + _namespaces.Add(dataContract.StableName.Namespace, clrNamespace); + } + } + } + } + + // Copy options.Namespaces to namespace tables + if (_options != null) + { + foreach (KeyValuePair pair in _options.Namespaces) + { + string dataContractNamespace = pair.Key; + string clrNamespace = pair.Value; + if (clrNamespace == null) + clrNamespace = string.Empty; + + string? currentDataContractNamespace; + if (_clrNamespaces.TryGetValue(clrNamespace, out currentDataContractNamespace)) + { + if (dataContractNamespace != currentDataContractNamespace) + throw ExceptionUtil.ThrowHelperError(new InvalidOperationException(SR.Format(SR.CLRNamespaceMappedMultipleTimes, currentDataContractNamespace, dataContractNamespace, clrNamespace))); + } + else + _clrNamespaces.Add(clrNamespace, dataContractNamespace); + + string? currentClrNamespace; + if (_namespaces.TryGetValue(dataContractNamespace, out currentClrNamespace)) + { + if (clrNamespace != currentClrNamespace) + { + _namespaces.Remove(dataContractNamespace); + _namespaces.Add(dataContractNamespace, clrNamespace); + } + } + else + _namespaces.Add(dataContractNamespace, clrNamespace); + } + } + + // Update namespace tables for pre-existing namespaces in CodeCompileUnit + foreach (CodeNamespace codeNS in codeCompileUnit.Namespaces) + { + string ns = codeNS.Name ?? string.Empty; + if (!_clrNamespaces.ContainsKey(ns)) + { + _clrNamespaces.Add(ns, null); + } + if (ns.Length == 0) + { + foreach (CodeTypeDeclaration codeTypeDecl in codeNS.Types) + { + AddGlobalTypeName(codeTypeDecl.Name); + } + } + } + + } + + private void AddReferencedAssembly(Assembly assembly) + { + bool alreadyExisting = false; +#pragma warning disable IL3000 // Avoid accessing Assembly file path when publishing as a single file + string assemblyName = System.IO.Path.GetFileName(assembly.Location); + if (string.IsNullOrWhiteSpace(assemblyName)) + assemblyName = $"[{assembly.FullName}]"; +#pragma warning restore IL3000 // Avoid accessing Assembly file path when publishing as a single file + + foreach (string? existingName in _codeCompileUnit.ReferencedAssemblies) + { + if (string.Equals(existingName, assemblyName, StringComparison.OrdinalIgnoreCase)) + { + alreadyExisting = true; + break; + } + } + if (!alreadyExisting) + _codeCompileUnit.ReferencedAssemblies.Add(assemblyName); + + } + + private bool GenerateSerializableTypes + { + get { return (_options == null) ? false : _options.GenerateSerializable; } + } + + private bool GenerateInternalTypes + { + get { return (_options == null) ? false : _options.GenerateInternal; } + } + + private bool EnableDataBinding + { + get { return (_options == null) ? false : _options.EnableDataBinding; } + } + + private CodeDomProvider? CodeProvider + { + get { return _options?.CodeProvider; } + } + + private bool SupportsDeclareEvents + { + get { return (CodeProvider == null) ? true : CodeProvider.Supports(GeneratorSupport.DeclareEvents); } + } + + private bool SupportsDeclareValueTypes + { + get { return (CodeProvider == null) ? true : CodeProvider.Supports(GeneratorSupport.DeclareValueTypes); } + } + + private bool SupportsGenericTypeReference + { + get { return (CodeProvider == null) ? true : CodeProvider.Supports(GeneratorSupport.GenericTypeReference); } + } + + private bool SupportsAssemblyAttributes + { + get { return (CodeProvider == null) ? true : CodeProvider.Supports(GeneratorSupport.AssemblyAttributes); } + } + + private bool SupportsPartialTypes + { + get { return (CodeProvider == null) ? true : CodeProvider.Supports(GeneratorSupport.PartialTypes); } + } + + private bool SupportsNestedTypes + { + get { return (CodeProvider == null) ? true : CodeProvider.Supports(GeneratorSupport.NestedTypes); } + } + + private string FileExtension + { + get { return (CodeProvider == null) ? string.Empty : CodeProvider.FileExtension; } + } + + private Dictionary Namespaces + { + get { return _namespaces; } + } + + private Dictionary ClrNamespaces + { + get { return _clrNamespaces; } + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + internal void Export() + { + try + { + foreach (KeyValuePair pair in _dataContractSet) + { + DataContract dataContract = pair.Value; + if (dataContract.IsBuiltInDataContract) + continue; + + ContractCodeDomInfo contractCodeDomInfo = GetContractCodeDomInfo(dataContract); + if (!contractCodeDomInfo.IsProcessed) + { + if (dataContract is ClassDataContract classDataContract) + { + if (classDataContract.IsISerializable) + ExportISerializableDataContract(classDataContract, contractCodeDomInfo); + else + ExportClassDataContractHierarchy(classDataContract.StableName, classDataContract, contractCodeDomInfo, new Dictionary()); + } + else if (dataContract is CollectionDataContract) + ExportCollectionDataContract((CollectionDataContract)dataContract, contractCodeDomInfo); + else if (dataContract is EnumDataContract) + ExportEnumDataContract((EnumDataContract)dataContract, contractCodeDomInfo); + else if (dataContract is XmlDataContract) + ExportXmlDataContract((XmlDataContract)dataContract, contractCodeDomInfo); + else + throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.UnexpectedContractType, GetClrTypeFullName(dataContract.GetType()), GetClrTypeFullName(dataContract.UnderlyingType)))); + contractCodeDomInfo.IsProcessed = true; + } + } + + if (_options?.ProcessImportedType != null) + { + CodeNamespace[] namespaces = new CodeNamespace[_codeCompileUnit.Namespaces.Count]; + _codeCompileUnit.Namespaces.CopyTo(namespaces, 0); + foreach (CodeNamespace codeNamespace in namespaces) + InvokeProcessImportedType(codeNamespace.Types); + } + } + finally + { + CodeGenerator.ValidateIdentifiers(_codeCompileUnit); + } + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private void ExportClassDataContractHierarchy(XmlQualifiedName typeName, ClassDataContract classContract, ContractCodeDomInfo contractCodeDomInfo, Dictionary contractNamesInHierarchy) + { + if (contractNamesInHierarchy.ContainsKey(classContract.StableName)) + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.TypeCannotBeImported, typeName.Name, typeName.Namespace, SR.Format(SR.CircularTypeReference, classContract.StableName.Name, classContract.StableName.Namespace)))); + contractNamesInHierarchy.Add(classContract.StableName, null); + + ClassDataContract? baseContract = classContract.BaseContract; + if (baseContract != null) + { + ContractCodeDomInfo baseContractCodeDomInfo = GetContractCodeDomInfo(baseContract); + if (!baseContractCodeDomInfo.IsProcessed) + { + ExportClassDataContractHierarchy(typeName, baseContract, baseContractCodeDomInfo, contractNamesInHierarchy); + baseContractCodeDomInfo.IsProcessed = true; + } + } + ExportClassDataContract(classContract, contractCodeDomInfo); + } + + private void InvokeProcessImportedType(CollectionBase collection) + { + object[] objects = new object[collection.Count]; + ((ICollection)collection).CopyTo(objects, 0); + + Debug.Assert(_options?.ProcessImportedType != null); // The only caller into this method already did a null check for this Func + + foreach (object obj in objects) + { + if (obj is CodeTypeDeclaration codeTypeDeclaration) + { + CodeTypeDeclaration? newCodeTypeDeclaration = _options?.ProcessImportedType.Invoke(codeTypeDeclaration, _codeCompileUnit); + + if (newCodeTypeDeclaration != codeTypeDeclaration) + { + ((IList)collection).Remove(codeTypeDeclaration); + if (newCodeTypeDeclaration != null) + ((IList)collection).Add(newCodeTypeDeclaration); + } + if (newCodeTypeDeclaration != null) + InvokeProcessImportedType(newCodeTypeDeclaration.Members); + } + } + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + internal CodeTypeReference GetCodeTypeReference(DataContract dataContract) + { + if (dataContract.IsBuiltInDataContract) + return GetCodeTypeReference(dataContract.UnderlyingType); + + ContractCodeDomInfo contractCodeDomInfo = GetContractCodeDomInfo(dataContract); + GenerateType(dataContract, contractCodeDomInfo); + + // This is supposed to be set by GenerateType. If it wasn't, there is a problem. + Debug.Assert(contractCodeDomInfo.TypeReference != null); + return contractCodeDomInfo.TypeReference!; + } + + private CodeTypeReference GetCodeTypeReference(Type type) + { + AddReferencedAssembly(type.Assembly); + return new CodeTypeReference(type); + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + internal CodeTypeReference GetElementTypeReference(DataContract dataContract, bool isElementTypeNullable) + { + CodeTypeReference elementTypeReference = GetCodeTypeReference(dataContract); + if (dataContract.IsValueType && isElementTypeNullable) + elementTypeReference = WrapNullable(elementTypeReference); + return elementTypeReference; + } + + [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Part of a logical set of properties, some of which are not static. May not remain static with future implementation updates.")] + private XmlQualifiedName GenericListName + { + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + get { return DataContract.GetStableName(typeof(List<>)); } + } + + private CollectionDataContract GenericListContract + { + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + get { return (_dataContractSet.GetDataContract(typeof(List<>)) as CollectionDataContract)!; } + } + + [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Part of a logical set of properties, some of which are not static. May not remain static with future implementation updates.")] + private XmlQualifiedName GenericDictionaryName + { + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + get { return DataContract.GetStableName(typeof(Dictionary<,>)); } + } + + private CollectionDataContract GenericDictionaryContract + { + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + get { return (_dataContractSet.GetDataContract(typeof(Dictionary<,>)) as CollectionDataContract)!; } + } + + private ContractCodeDomInfo GetContractCodeDomInfo(DataContract dataContract) + { + ContractCodeDomInfo? contractCodeDomInfo = null; + if (_dataContractSet.ProcessedContracts.TryGetValue(dataContract, out object? info)) + contractCodeDomInfo = info as ContractCodeDomInfo; + if (contractCodeDomInfo == null) + { + contractCodeDomInfo = new ContractCodeDomInfo(); + _dataContractSet.ProcessedContracts.Add(dataContract, contractCodeDomInfo); + } + return contractCodeDomInfo; + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private void GenerateType(DataContract dataContract, ContractCodeDomInfo contractCodeDomInfo) + { + if (!contractCodeDomInfo.IsProcessed) + { + CodeTypeReference? referencedType = GetReferencedType(dataContract); + if (referencedType != null) + { + contractCodeDomInfo.TypeReference = referencedType; + contractCodeDomInfo.ReferencedTypeExists = true; + } + else + { + CodeTypeDeclaration? type = contractCodeDomInfo.TypeDeclaration; + if (type == null) + { + string clrNamespace = GetClrNamespace(dataContract, contractCodeDomInfo); + CodeNamespace ns = GetCodeNamespace(clrNamespace, dataContract.StableName.Namespace, contractCodeDomInfo); + type = GetNestedType(dataContract, contractCodeDomInfo); + if (type == null) + { + string typeName = XmlConvert.DecodeName(dataContract.StableName.Name); + typeName = GetClrIdentifier(typeName, Globals.DefaultTypeName); + if (NamespaceContainsType(ns, typeName) || GlobalTypeNameConflicts(clrNamespace, typeName)) + { + for (int i = 1;; i++) + { + string uniqueName = AppendToValidClrIdentifier(typeName, i.ToString(NumberFormatInfo.InvariantInfo)); + if (!NamespaceContainsType(ns, uniqueName) && !GlobalTypeNameConflicts(clrNamespace, uniqueName)) + { + typeName = uniqueName; + break; + } + if (i == int.MaxValue) + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.CannotComputeUniqueName, typeName))); + } + } + + type = CreateTypeDeclaration(typeName, dataContract); + ns.Types.Add(type); + if (string.IsNullOrEmpty(clrNamespace)) + { + AddGlobalTypeName(typeName); + } + contractCodeDomInfo.TypeReference = new CodeTypeReference((clrNamespace == null || clrNamespace.Length == 0) ? typeName : clrNamespace + "." + typeName); + + if (GenerateInternalTypes) + type.TypeAttributes = TypeAttributes.NotPublic; + else + type.TypeAttributes = TypeAttributes.Public; + } + + if (_dataContractSet.TryGetSurrogateData(dataContract, out object? surrogateData)) + type.UserData.Add(s_surrogateDataKey, surrogateData); + + contractCodeDomInfo.TypeDeclaration = type; + } + } + } + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private CodeTypeDeclaration? GetNestedType(DataContract dataContract, ContractCodeDomInfo contractCodeDomInfo) + { + if (!SupportsNestedTypes) + return null; + string originalName = dataContract.StableName.Name; + int nestedTypeIndex = originalName.LastIndexOf('.'); + if (nestedTypeIndex <= 0) + return null; + string containingTypeName = originalName.Substring(0, nestedTypeIndex); + DataContract? containingDataContract = _dataContractSet.GetDataContract(new XmlQualifiedName(containingTypeName, dataContract.StableName.Namespace)); + if (containingDataContract == null) + return null; + string nestedTypeName = XmlConvert.DecodeName(originalName.Substring(nestedTypeIndex + 1)); + nestedTypeName = GetClrIdentifier(nestedTypeName, Globals.DefaultTypeName); + + ContractCodeDomInfo containingContractCodeDomInfo = GetContractCodeDomInfo(containingDataContract); + GenerateType(containingDataContract, containingContractCodeDomInfo); + if (containingContractCodeDomInfo.ReferencedTypeExists) + return null; + + CodeTypeDeclaration containingType = containingContractCodeDomInfo.TypeDeclaration!; // Nested types by definition have containing types. + if (TypeContainsNestedType(containingType, nestedTypeName)) + { + for (int i = 1;; i++) + { + string uniqueName = AppendToValidClrIdentifier(nestedTypeName, i.ToString(NumberFormatInfo.InvariantInfo)); + if (!TypeContainsNestedType(containingType, uniqueName)) + { + nestedTypeName = uniqueName; + break; + } + } + } + + CodeTypeDeclaration type = CreateTypeDeclaration(nestedTypeName, dataContract); + containingType.Members.Add(type); + contractCodeDomInfo.TypeReference = new CodeTypeReference(containingContractCodeDomInfo.TypeReference!.BaseType + "+" + nestedTypeName); // Again, nested types by definition have containing types. + + if (GenerateInternalTypes) + type.TypeAttributes = TypeAttributes.NestedAssembly; + else + type.TypeAttributes = TypeAttributes.NestedPublic; + return type; + } + + private static CodeTypeDeclaration CreateTypeDeclaration(string typeName, DataContract dataContract) + { + CodeTypeDeclaration typeDecl = new CodeTypeDeclaration(typeName); + CodeAttributeDeclaration debuggerStepThroughAttribute = new CodeAttributeDeclaration(typeof(System.Diagnostics.DebuggerStepThroughAttribute).FullName!); + CodeAttributeDeclaration generatedCodeAttribute = new CodeAttributeDeclaration(typeof(GeneratedCodeAttribute).FullName!); + + AssemblyName assemblyName = Assembly.GetExecutingAssembly().GetName(); + generatedCodeAttribute.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(assemblyName.Name))); + generatedCodeAttribute.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(assemblyName.Version?.ToString()))); + + // System.Diagnostics.DebuggerStepThroughAttribute not allowed on enums + // ensure that the attribute is only generated on types that are not enums + EnumDataContract? enumDataContract = dataContract as EnumDataContract; + if (enumDataContract == null) + { + typeDecl.CustomAttributes.Add(debuggerStepThroughAttribute); + } + typeDecl.CustomAttributes.Add(generatedCodeAttribute); + return typeDecl; + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private CodeTypeReference? GetReferencedType(DataContract dataContract) + { + CodeTypeReference? typeReference = GetSurrogatedTypeReference(dataContract); + if (typeReference != null) + return typeReference; + + if (_dataContractSet.TryGetReferencedType(dataContract.StableName, dataContract, out Type? type) + && !type.IsGenericTypeDefinition && !type.ContainsGenericParameters) + { + if (dataContract is XmlDataContract) + { + if (typeof(IXmlSerializable).IsAssignableFrom(type)) + { + XmlDataContract xmlContract = (XmlDataContract)dataContract; + if (xmlContract.IsTypeDefinedOnImport) + { + if (!xmlContract.Equals(_dataContractSet.GetDataContract(type))) + throw ExceptionUtil.ThrowHelperError(new InvalidOperationException(SR.Format(SR.ReferencedTypeDoesNotMatch, type.AssemblyQualifiedName, dataContract.StableName.Name, dataContract.StableName.Namespace))); + } + else + { + xmlContract.IsValueType = type.IsValueType; + xmlContract.IsTypeDefinedOnImport = true; + } + return GetCodeTypeReference(type); + } + throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.TypeMustBeIXmlSerializable, GetClrTypeFullName(type), GetClrTypeFullName(typeof(IXmlSerializable)), dataContract.StableName.Name, dataContract.StableName.Namespace))); + } + DataContract referencedContract = _dataContractSet.GetDataContract(type); + if (referencedContract.Equals(dataContract)) + { + typeReference = GetCodeTypeReference(type); + typeReference.UserData.Add(s_codeUserDataActualTypeKey, type); + return typeReference; + } + throw ExceptionUtil.ThrowHelperError(new InvalidOperationException(SR.Format(SR.ReferencedTypeDoesNotMatch, type.AssemblyQualifiedName, dataContract.StableName.Name, dataContract.StableName.Namespace))); + } + else if (dataContract.GenericInfo != null) + { + DataContract? referencedContract; + XmlQualifiedName genericStableName = dataContract.GenericInfo.GetExpandedStableName(); + if (genericStableName != dataContract.StableName) + throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericTypeNameMismatch, dataContract.StableName.Name, dataContract.StableName.Namespace, genericStableName.Name, genericStableName.Namespace))); + + typeReference = GetReferencedGenericType(dataContract.GenericInfo, out referencedContract); + if (referencedContract != null && !referencedContract.Equals(dataContract)) + { + // NOTE TODO smolloy - Is this right? Looking at 'GetReferenceGenericType()' it is possible to get a non-null referencedContract, but a null typeReference. Is that supposed to happen? + // Are we supposed to only check the dataContract if we did not fail to get a typeReference? Should GetReferenceGenericType() be consistent with the two return parameters? + // For now... assert to get out of the way of compilation. But come revisit this. + Debug.Assert(typeReference != null); + type = (Type?)typeReference.UserData[s_codeUserDataActualTypeKey]; + throw ExceptionUtil.ThrowHelperError(new InvalidOperationException(SR.Format(SR.ReferencedTypeDoesNotMatch, + type?.AssemblyQualifiedName, + referencedContract.StableName.Name, + referencedContract.StableName.Namespace))); + } + return typeReference; + } + + return GetReferencedCollectionType(dataContract as CollectionDataContract); + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private CodeTypeReference? GetReferencedCollectionType(CollectionDataContract? collectionContract) + { + if (collectionContract == null) + return null; + + if (HasDefaultCollectionNames(collectionContract)) + { + CodeTypeReference? typeReference; + if (!TryGetReferencedDictionaryType(collectionContract, out typeReference)) + { + DataContract itemContract = collectionContract.ItemContract; + if (collectionContract.IsDictionary) + { + GenerateKeyValueType(itemContract as ClassDataContract); + } + bool isItemTypeNullable = collectionContract.IsItemTypeNullable; + if (!TryGetReferencedListType(itemContract, isItemTypeNullable, out typeReference)) + { + CodeTypeReference? elementTypeReference = GetElementTypeReference(itemContract, isItemTypeNullable); + if (elementTypeReference != null) + typeReference = new CodeTypeReference(elementTypeReference, 1); + } + } + return typeReference; + } + return null; + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private static bool HasDefaultCollectionNames(CollectionDataContract collectionContract) + { + DataContract itemContract = collectionContract.ItemContract; + if (collectionContract.ItemName != itemContract.StableName.Name) + return false; + + if (collectionContract.IsDictionary && + (collectionContract.KeyName != Globals.KeyLocalName || collectionContract.ValueName != Globals.ValueLocalName)) + return false; + + XmlQualifiedName expectedType = itemContract.GetArrayTypeName(collectionContract.IsItemTypeNullable); + return (collectionContract.StableName.Name == expectedType.Name && collectionContract.StableName.Namespace == expectedType.Namespace); + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private bool TryGetReferencedDictionaryType(CollectionDataContract collectionContract, [NotNullWhen(true)] out CodeTypeReference? typeReference) + { + // Check if it is a dictionary and use referenced dictionary type if present + if (collectionContract.IsDictionary + && SupportsGenericTypeReference) + { + Type? type; + if (!_dataContractSet.TryGetReferencedType(GenericDictionaryName, GenericDictionaryContract, out type)) + type = typeof(Dictionary<,>); + + ClassDataContract? itemContract = collectionContract.ItemContract as ClassDataContract; + + // A dictionary should have a Key/Value item contract that has at least two members: key and value. + Debug.Assert(itemContract != null); + Debug.Assert(itemContract.Members != null && itemContract.Members.Count > 1); + + DataMember keyMember = itemContract.Members[0]; + DataMember valueMember = itemContract.Members[1]; + CodeTypeReference? keyTypeReference = GetElementTypeReference(keyMember.MemberTypeContract, keyMember.IsNullable); + CodeTypeReference? valueTypeReference = GetElementTypeReference(valueMember.MemberTypeContract, valueMember.IsNullable); + if (keyTypeReference != null && valueTypeReference != null) + { + typeReference = GetCodeTypeReference(type); + typeReference.TypeArguments.Add(keyTypeReference); + typeReference.TypeArguments.Add(valueTypeReference); + return true; + } + } + typeReference = null; + return false; + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private bool TryGetReferencedListType(DataContract itemContract, bool isItemTypeNullable, out CodeTypeReference? typeReference) + { + Type? type; + if (SupportsGenericTypeReference && _dataContractSet.TryGetReferencedType(GenericListName, GenericListContract, out type)) + { + typeReference = GetCodeTypeReference(type); + typeReference.TypeArguments.Add(GetElementTypeReference(itemContract, isItemTypeNullable)!); // Lists have an item type + return true; + } + typeReference = null; + return false; + } + + [RequiresUnreferencedCode("TODO smolloy - better string here")] + private CodeTypeReference? GetSurrogatedTypeReference(DataContract dataContract) + { + Type? type = _dataContractSet.GetReferencedTypeOnImport(dataContract); + if (type != null) + { + CodeTypeReference typeReference = GetCodeTypeReference(type); + typeReference.UserData.Add(s_codeUserDataActualTypeKey, type); + return typeReference; + } + return null; + + // TODO smolloy - the stuff above replaces the stuff below completely. The stuff below + // is left here as a reference for when DCSet gets fleshed out with this logic. + + //ISerializationExtendedSurrogateProvider? dataContractSurrogate = _dataContractSet.SerializationExtendedSurrogateProvider; + //if (dataContractSurrogate != null) + //{ + // Type? type = DataContractSurrogateCaller.GetReferencedTypeOnImport( + // dataContractSurrogate, + // dataContract.StableName.Name, + // dataContract.StableName.Namespace, + // _dataContractSet.GetSurrogateData(dataContract)); + // if (type != null) + // { + // CodeTypeReference typeReference = GetCodeTypeReference(type); + // typeReference.UserData.Add(s_codeUserDataActualTypeKey, type); + // return typeReference; + // } + //} + //return null; + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private CodeTypeReference? GetReferencedGenericType(GenericInfo genInfo, out DataContract? dataContract) + { + dataContract = null; + + if (!SupportsGenericTypeReference) + return null; + + Type? type; + if (!_dataContractSet.TryGetReferencedType(genInfo.StableName, null, out type)) + { + if (genInfo.Parameters != null) + return null; + dataContract = _dataContractSet.GetDataContract(genInfo.StableName); + if (dataContract == null) + return null; + if (dataContract.GenericInfo != null) + return null; + return GetCodeTypeReference(dataContract); + } + + bool enableStructureCheck = (type != typeof(Nullable<>)); + CodeTypeReference typeReference = GetCodeTypeReference(type); + typeReference.UserData.Add(s_codeUserDataActualTypeKey, type); + if (genInfo.Parameters != null) + { + DataContract[] paramContracts = new DataContract[genInfo.Parameters.Count]; + for (int i = 0; i < genInfo.Parameters.Count; i++) + { + GenericInfo paramInfo = genInfo.Parameters[i]; + XmlQualifiedName stableName = paramInfo.GetExpandedStableName(); + DataContract? paramContract = _dataContractSet.GetDataContract(stableName); + + CodeTypeReference? paramTypeReference; + bool isParamValueType; + if (paramContract != null) + { + paramTypeReference = GetCodeTypeReference(paramContract); + isParamValueType = paramContract.IsValueType; + } + else + { + paramTypeReference = GetReferencedGenericType(paramInfo, out paramContract); + isParamValueType = (paramTypeReference != null && paramTypeReference.ArrayRank == 0); // only value type information we can get from CodeTypeReference + } + paramContracts[i] = paramContract!; // Potentially tricky here. We could assign a null item here, and that's ok. We subsequently disable the structure check in that case. See note below. + if (paramContract == null) + enableStructureCheck = false; + if (paramTypeReference == null) + return null; + if (type == typeof(Nullable<>) && !isParamValueType) + return paramTypeReference; + else + typeReference.TypeArguments.Add(paramTypeReference); + } + // paramContracts could contain null values, but if it does, this structure check is disabled. So we know paramContracts has no null values if we go through with this call. + if (enableStructureCheck) + dataContract = DataContract.GetDataContract(type).BindGenericParameters(paramContracts, new Dictionary()); + } + return typeReference; + } + + private static bool NamespaceContainsType(CodeNamespace ns, string typeName) + { + foreach (CodeTypeDeclaration type in ns.Types) + { + if (string.Equals(typeName, type.Name, StringComparison.OrdinalIgnoreCase)) + return true; + } + return false; + } + + private bool GlobalTypeNameConflicts(string clrNamespace, string typeName) + { + return (string.IsNullOrEmpty(clrNamespace) && _clrNamespaces.ContainsKey(typeName)); + } + + private void AddGlobalTypeName(string typeName) + { + if (!_clrNamespaces.ContainsKey(typeName)) + { + _clrNamespaces.Add(typeName, null); + } + } + + private static bool TypeContainsNestedType(CodeTypeDeclaration containingType, string typeName) + { + foreach (CodeTypeMember member in containingType.Members) + { + if (member is CodeTypeDeclaration declaration) + { + if (string.Equals(typeName, declaration.Name, StringComparison.OrdinalIgnoreCase)) + return true; + } + } + return false; + } + + private static string GetNameForAttribute(string name) + { + string decodedName = XmlConvert.DecodeName(name); + if (string.CompareOrdinal(name, decodedName) == 0) + return name; + string reencodedName = DataContract.EncodeLocalName(decodedName); + return (string.CompareOrdinal(name, reencodedName) == 0) ? decodedName : name; + } + + private void AddSerializableAttribute(bool generateSerializable, CodeTypeDeclaration type, ContractCodeDomInfo contractCodeDomInfo) + { + if (generateSerializable) + { + type.CustomAttributes.Add(SerializableAttribute); + AddImportStatement(typeof(SerializableAttribute).Namespace, contractCodeDomInfo.CodeNamespace); + } + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private void ExportClassDataContract(ClassDataContract classDataContract, ContractCodeDomInfo contractCodeDomInfo) + { + GenerateType(classDataContract, contractCodeDomInfo); + if (contractCodeDomInfo.ReferencedTypeExists) + return; + + // This is supposed to be set by GenerateType. If it wasn't, there is a problem. + Debug.Assert(contractCodeDomInfo.TypeDeclaration != null); + + CodeTypeDeclaration type = contractCodeDomInfo.TypeDeclaration; + if (SupportsPartialTypes) + type.IsPartial = true; + if (classDataContract.IsValueType && SupportsDeclareValueTypes) + type.IsStruct = true; + else + type.IsClass = true; + + string dataContractName = GetNameForAttribute(classDataContract.StableName.Name); + CodeAttributeDeclaration dataContractAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(DataContractAttribute))); + dataContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.NameProperty, new CodePrimitiveExpression(dataContractName))); + dataContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.NamespaceProperty, new CodePrimitiveExpression(classDataContract.StableName.Namespace))); + if (classDataContract.IsReference != Globals.DefaultIsReference) + dataContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.IsReferenceProperty, new CodePrimitiveExpression(classDataContract.IsReference))); + type.CustomAttributes.Add(dataContractAttribute); + AddImportStatement(typeof(DataContractAttribute).Namespace, contractCodeDomInfo.CodeNamespace); + + AddSerializableAttribute(GenerateSerializableTypes, type, contractCodeDomInfo); + + AddKnownTypes(classDataContract, contractCodeDomInfo); + + bool raisePropertyChanged = EnableDataBinding && SupportsDeclareEvents; + if (classDataContract.BaseContract == null) + { + if (!type.IsStruct) + type.BaseTypes.Add(typeof(object)); + AddExtensionData(contractCodeDomInfo); + AddPropertyChangedNotifier(contractCodeDomInfo, type.IsStruct); + } + else + { + ContractCodeDomInfo baseContractCodeDomInfo = GetContractCodeDomInfo(classDataContract.BaseContract); + Debug.Assert(baseContractCodeDomInfo.IsProcessed, "Cannot generate code for type if code for base type has not been generated"); + type.BaseTypes.Add(baseContractCodeDomInfo.TypeReference); + AddBaseMemberNames(baseContractCodeDomInfo, contractCodeDomInfo); + if (baseContractCodeDomInfo.ReferencedTypeExists) + { + Type? actualType = (Type?)baseContractCodeDomInfo.TypeReference?.UserData[s_codeUserDataActualTypeKey]; + Debug.Assert(actualType != null); // If we're in this if condition, then we should be able to get a Type + ThrowIfReferencedBaseTypeSealed(actualType, classDataContract); + if (!typeof(IExtensibleDataObject).IsAssignableFrom(actualType)) + AddExtensionData(contractCodeDomInfo); + if (!typeof(INotifyPropertyChanged).IsAssignableFrom(actualType)) + { + AddPropertyChangedNotifier(contractCodeDomInfo, type.IsStruct); + } + else + { + raisePropertyChanged = false; + } + } + } + + if (classDataContract.Members != null) + { + for (int i = 0; i < classDataContract.Members.Count; i++) + { + DataMember dataMember = classDataContract.Members[i]; + + CodeTypeReference memberType = GetElementTypeReference(dataMember.MemberTypeContract, + (dataMember.IsNullable && dataMember.MemberTypeContract.IsValueType)); + + string dataMemberName = GetNameForAttribute(dataMember.Name); + string propertyName = GetMemberName(dataMemberName, contractCodeDomInfo); + string fieldName = GetMemberName(AppendToValidClrIdentifier(propertyName, Globals.DefaultFieldSuffix), contractCodeDomInfo); + + CodeMemberField field = new CodeMemberField(); + field.Type = memberType; + field.Name = fieldName; + field.Attributes = MemberAttributes.Private; + + CodeMemberProperty property = CreateProperty(memberType, propertyName, fieldName, dataMember.MemberTypeContract.IsValueType && SupportsDeclareValueTypes, raisePropertyChanged); + if (_dataContractSet.TryGetSurrogateData(dataMember, out object? surrogateData)) + property.UserData.Add(s_surrogateDataKey, surrogateData); + + CodeAttributeDeclaration dataMemberAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(DataMemberAttribute))); + if (dataMemberName != property.Name) + dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(Globals.NameProperty, new CodePrimitiveExpression(dataMemberName))); + if (dataMember.IsRequired != Globals.DefaultIsRequired) + dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(Globals.IsRequiredProperty, new CodePrimitiveExpression(dataMember.IsRequired))); + if (dataMember.EmitDefaultValue != Globals.DefaultEmitDefaultValue) + dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(Globals.EmitDefaultValueProperty, new CodePrimitiveExpression(dataMember.EmitDefaultValue))); + if (dataMember.Order != Globals.DefaultOrder) + dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(Globals.OrderProperty, new CodePrimitiveExpression(dataMember.Order))); + property.CustomAttributes.Add(dataMemberAttribute); + + if (GenerateSerializableTypes && !dataMember.IsRequired) + { + CodeAttributeDeclaration optionalFieldAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(OptionalFieldAttribute))); + field.CustomAttributes.Add(optionalFieldAttribute); + } + + type.Members.Add(field); + type.Members.Add(property); + } + } + } + + private bool CanDeclareAssemblyAttribute(ContractCodeDomInfo contractCodeDomInfo) + { + return SupportsAssemblyAttributes && !contractCodeDomInfo.UsesWildcardNamespace; + } + + private static bool NeedsExplicitNamespace(string dataContractNamespace, string clrNamespace) + { + return (SchemaHelper.GetDefaultStableNamespace(clrNamespace) != dataContractNamespace); + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + internal ICollection? GetKnownTypeReferences(DataContract dataContract) + { + DataContractDictionary? knownTypeDictionary = GetKnownTypeContracts(dataContract); + if (knownTypeDictionary == null) + return null; + + ICollection? knownTypeContracts = knownTypeDictionary.Values; + if (knownTypeContracts == null || knownTypeContracts.Count == 0) + return null; + + List knownTypeReferences = new List(); + foreach (DataContract knownTypeContract in knownTypeContracts) + { + knownTypeReferences.Add(GetCodeTypeReference(knownTypeContract)); + } + return knownTypeReferences; + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private DataContractDictionary? GetKnownTypeContracts(DataContract dataContract) + { + if (_dataContractSet.KnownTypesForObject != null && IsObjectContract(dataContract)) + { + return _dataContractSet.KnownTypesForObject; + } + else if (dataContract is ClassDataContract) + { + ContractCodeDomInfo contractCodeDomInfo = GetContractCodeDomInfo(dataContract); + if (!contractCodeDomInfo.IsProcessed) + GenerateType(dataContract, contractCodeDomInfo); + if (contractCodeDomInfo.ReferencedTypeExists) + return GetKnownTypeContracts((ClassDataContract)dataContract, new Dictionary()); + } + return null; + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private DataContractDictionary? GetKnownTypeContracts(ClassDataContract dataContract, Dictionary handledContracts) + { + if (handledContracts.ContainsKey(dataContract)) + return dataContract.KnownDataContracts; + + handledContracts.Add(dataContract, null); + if (dataContract.Members != null) + { + bool objectMemberHandled = false; + foreach (DataMember dataMember in dataContract.Members) + { + DataContract memberContract = dataMember.MemberTypeContract; + if (!objectMemberHandled && _dataContractSet.KnownTypesForObject != null && IsObjectContract(memberContract)) + { + AddKnownTypeContracts(dataContract, _dataContractSet.KnownTypesForObject); + objectMemberHandled = true; + } + else if (memberContract is ClassDataContract) + { + ContractCodeDomInfo memberCodeDomInfo = GetContractCodeDomInfo(memberContract); + if (!memberCodeDomInfo.IsProcessed) + GenerateType(memberContract, memberCodeDomInfo); + if (memberCodeDomInfo.ReferencedTypeExists) + { + AddKnownTypeContracts(dataContract, GetKnownTypeContracts((ClassDataContract)memberContract, handledContracts)); + } + } + } + } + + return dataContract.KnownDataContracts; + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private static void AddKnownTypeContracts(ClassDataContract dataContract, DataContractDictionary? knownContracts) + { + if (knownContracts == null || knownContracts.Count == 0) + return; + + if (dataContract.KnownDataContracts == null) + dataContract.KnownDataContracts = new DataContractDictionary(); + + foreach (KeyValuePair pair in knownContracts) + { + if (dataContract.StableName != pair.Key && !dataContract.KnownDataContracts.ContainsKey(pair.Key) && !pair.Value.IsBuiltInDataContract) + dataContract.KnownDataContracts.Add(pair.Key, pair.Value); + } + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private void AddKnownTypes(ClassDataContract dataContract, ContractCodeDomInfo contractCodeDomInfo) + { + DataContractDictionary? knownContractDictionary = GetKnownTypeContracts(dataContract, new Dictionary()); + if (knownContractDictionary == null || knownContractDictionary.Count == 0) + return; + + ICollection knownTypeContracts = knownContractDictionary.Values; + foreach (DataContract knownTypeContract in knownTypeContracts) + { + // This is only called from methods that first call GenerateType to fill in this info. + Debug.Assert(contractCodeDomInfo.TypeDeclaration != null); + + CodeAttributeDeclaration knownTypeAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(KnownTypeAttribute))); + knownTypeAttribute.Arguments.Add(new CodeAttributeArgument(new CodeTypeOfExpression(GetCodeTypeReference(knownTypeContract)))); + contractCodeDomInfo.TypeDeclaration.CustomAttributes.Add(knownTypeAttribute); + } + AddImportStatement(typeof(KnownTypeAttribute).Namespace, contractCodeDomInfo.CodeNamespace); + } + + private CodeTypeReference WrapNullable(CodeTypeReference memberType) + { + if (!SupportsGenericTypeReference) + return memberType; + + CodeTypeReference nullableOfMemberType = GetCodeTypeReference(typeof(Nullable<>)); + nullableOfMemberType.TypeArguments.Add(memberType); + return nullableOfMemberType; + } + + private void AddExtensionData(ContractCodeDomInfo contractCodeDomInfo) + { + if (contractCodeDomInfo.TypeDeclaration != null) + { + CodeTypeDeclaration type = contractCodeDomInfo.TypeDeclaration; + type.BaseTypes.Add(GetClrTypeFullName(typeof(IExtensibleDataObject))); + CodeMemberField extensionDataObjectField = ExtensionDataObjectField; + if (GenerateSerializableTypes) + { + CodeAttributeDeclaration nonSerializedAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(NonSerializedAttribute))); + extensionDataObjectField.CustomAttributes.Add(nonSerializedAttribute); + } + type.Members.Add(extensionDataObjectField); + contractCodeDomInfo.GetMemberNames().Add(extensionDataObjectField.Name); + CodeMemberProperty extensionDataObjectProperty = ExtensionDataObjectProperty; + type.Members.Add(extensionDataObjectProperty); + contractCodeDomInfo.GetMemberNames().Add(extensionDataObjectProperty.Name); + } + } + + private void AddPropertyChangedNotifier(ContractCodeDomInfo contractCodeDomInfo, bool isValueType) + { + if (EnableDataBinding && SupportsDeclareEvents && contractCodeDomInfo.TypeDeclaration != null) + { + CodeTypeDeclaration codeTypeDeclaration = contractCodeDomInfo.TypeDeclaration; + codeTypeDeclaration.BaseTypes.Add(CodeTypeIPropertyChange); + CodeMemberEvent memberEvent = PropertyChangedEvent; + codeTypeDeclaration.Members.Add(memberEvent); + CodeMemberMethod raisePropertyChangedEventMethod = RaisePropertyChangedEventMethod; + if (!isValueType) + raisePropertyChangedEventMethod.Attributes |= MemberAttributes.Family; + codeTypeDeclaration.Members.Add(raisePropertyChangedEventMethod); + contractCodeDomInfo.GetMemberNames().Add(memberEvent.Name); + contractCodeDomInfo.GetMemberNames().Add(raisePropertyChangedEventMethod.Name); + } + } + + private static void ThrowIfReferencedBaseTypeSealed(Type baseType, DataContract dataContract) + { + if (baseType.IsSealed) + throw ExceptionUtil.ThrowHelperError(new InvalidOperationException(SR.Format(SR.CannotDeriveFromSealedReferenceType, dataContract.StableName.Name, dataContract.StableName.Namespace, GetClrTypeFullName(baseType)))); + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private void ExportEnumDataContract(EnumDataContract enumDataContract, ContractCodeDomInfo contractCodeDomInfo) + { + GenerateType(enumDataContract, contractCodeDomInfo); + if (contractCodeDomInfo.ReferencedTypeExists) + return; + + // This is supposed to be set by GenerateType. If it wasn't, there is a problem. + Debug.Assert(contractCodeDomInfo.TypeDeclaration != null); + + CodeTypeDeclaration type = contractCodeDomInfo.TypeDeclaration; + type.IsEnum = true; + type.BaseTypes.Add(EnumDataContract.GetBaseType(enumDataContract.BaseContractName)); + if (enumDataContract.IsFlags) + { + type.CustomAttributes.Add(new CodeAttributeDeclaration(GetClrTypeFullName(typeof(FlagsAttribute)))); + AddImportStatement(typeof(FlagsAttribute).Namespace, contractCodeDomInfo.CodeNamespace); + } + + string dataContractName = GetNameForAttribute(enumDataContract.StableName.Name); + CodeAttributeDeclaration dataContractAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(DataContractAttribute))); + dataContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.NameProperty, new CodePrimitiveExpression(dataContractName))); + dataContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.NamespaceProperty, new CodePrimitiveExpression(enumDataContract.StableName.Namespace))); + type.CustomAttributes.Add(dataContractAttribute); + AddImportStatement(typeof(DataContractAttribute).Namespace, contractCodeDomInfo.CodeNamespace); + + if (enumDataContract.Members != null) + { + for (int i = 0; i < enumDataContract.Members.Count; i++) + { + string stringValue = enumDataContract.Members[i].Name; + long longValue = enumDataContract.Values![i]; // Members[] and Values[] go hand in hand. + + CodeMemberField enumMember = new CodeMemberField(); + if (enumDataContract.IsULong) + enumMember.InitExpression = new CodeSnippetExpression(enumDataContract.GetStringFromEnumValue(longValue)); + else + enumMember.InitExpression = new CodePrimitiveExpression(longValue); + enumMember.Name = GetMemberName(stringValue, contractCodeDomInfo); + CodeAttributeDeclaration enumMemberAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(EnumMemberAttribute))); + if (enumMember.Name != stringValue) + enumMemberAttribute.Arguments.Add(new CodeAttributeArgument(Globals.ValueProperty, new CodePrimitiveExpression(stringValue))); + enumMember.CustomAttributes.Add(enumMemberAttribute); + type.Members.Add(enumMember); + } + } + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private void ExportISerializableDataContract(ClassDataContract dataContract, ContractCodeDomInfo contractCodeDomInfo) + { + GenerateType(dataContract, contractCodeDomInfo); + if (contractCodeDomInfo.ReferencedTypeExists) + return; + + if (SchemaHelper.GetDefaultStableNamespace(contractCodeDomInfo.ClrNamespace) != dataContract.StableName.Namespace) + throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidClrNamespaceGeneratedForISerializable, dataContract.StableName.Name, dataContract.StableName.Namespace, SchemaHelper.GetDataContractNamespaceFromUri(dataContract.StableName.Namespace), contractCodeDomInfo.ClrNamespace))); + + string dataContractName = GetNameForAttribute(dataContract.StableName.Name); + int nestedTypeIndex = dataContractName.LastIndexOf('.'); + string expectedName = (nestedTypeIndex <= 0 || nestedTypeIndex == dataContractName.Length - 1) ? dataContractName : dataContractName.Substring(nestedTypeIndex + 1); + + // This is supposed to be set by GenerateType. If it wasn't, there is a problem. + Debug.Assert(contractCodeDomInfo.TypeDeclaration != null); + + if (contractCodeDomInfo.TypeDeclaration.Name != expectedName) + throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidClrNameGeneratedForISerializable, dataContract.StableName.Name, dataContract.StableName.Namespace, contractCodeDomInfo.TypeDeclaration.Name))); + + CodeTypeDeclaration type = contractCodeDomInfo.TypeDeclaration; + if (SupportsPartialTypes) + type.IsPartial = true; + if (dataContract.IsValueType && SupportsDeclareValueTypes) + type.IsStruct = true; + else + type.IsClass = true; + + AddSerializableAttribute(true /*generateSerializable*/, type, contractCodeDomInfo); + + AddKnownTypes(dataContract, contractCodeDomInfo); + + if (dataContract.BaseContract == null) + { + if (!type.IsStruct) + type.BaseTypes.Add(typeof(object)); + type.BaseTypes.Add(GetClrTypeFullName(typeof(ISerializable))); + type.Members.Add(ISerializableBaseConstructor); + type.Members.Add(SerializationInfoField); + type.Members.Add(SerializationInfoProperty); + type.Members.Add(GetObjectDataMethod); + AddPropertyChangedNotifier(contractCodeDomInfo, type.IsStruct); + } + else + { + ContractCodeDomInfo baseContractCodeDomInfo = GetContractCodeDomInfo(dataContract.BaseContract); + GenerateType(dataContract.BaseContract, baseContractCodeDomInfo); + type.BaseTypes.Add(baseContractCodeDomInfo.TypeReference); + if (baseContractCodeDomInfo.ReferencedTypeExists) + { + Type? actualType = (Type?)baseContractCodeDomInfo.TypeReference?.UserData[s_codeUserDataActualTypeKey]; + Debug.Assert(actualType != null); // If we're in this if condition, then we should be able to get a Type + ThrowIfReferencedBaseTypeSealed(actualType, dataContract); + } + type.Members.Add(ISerializableDerivedConstructor); + } + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private void GenerateKeyValueType(ClassDataContract? keyValueContract) + { + // Add code for KeyValue item type in the case where its usage is limited to dictionary + // and dictionary is not found in referenced types + if (keyValueContract != null && _dataContractSet.GetDataContract(keyValueContract.StableName) == null) + { + ContractCodeDomInfo? contractCodeDomInfo = null; + if (_dataContractSet.ProcessedContracts.TryGetValue(keyValueContract, out object? info)) + contractCodeDomInfo = info as ContractCodeDomInfo; + if (contractCodeDomInfo == null) + { + contractCodeDomInfo = new ContractCodeDomInfo(); + _dataContractSet.ProcessedContracts.Add(keyValueContract, contractCodeDomInfo); + ExportClassDataContract(keyValueContract, contractCodeDomInfo); + contractCodeDomInfo.IsProcessed = true; + } + } + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private void ExportCollectionDataContract(CollectionDataContract collectionContract, ContractCodeDomInfo contractCodeDomInfo) + { + GenerateType(collectionContract, contractCodeDomInfo); + if (contractCodeDomInfo.ReferencedTypeExists) + return; + + string dataContractName = GetNameForAttribute(collectionContract.StableName.Name); + + // If type name is not expected, generate collection type that derives from referenced list type and uses [CollectionDataContract] + if (!SupportsGenericTypeReference) + throw ExceptionUtil.ThrowHelperError(new InvalidOperationException( + SR.Format(SR.CannotUseGenericTypeAsBase, dataContractName, + collectionContract.StableName.Namespace))); + + DataContract itemContract = collectionContract.ItemContract; + bool isItemTypeNullable = collectionContract.IsItemTypeNullable; + + CodeTypeReference? baseTypeReference; + bool foundDictionaryBase = TryGetReferencedDictionaryType(collectionContract, out baseTypeReference); + if (!foundDictionaryBase) + { + if (collectionContract.IsDictionary) + { + GenerateKeyValueType(collectionContract.ItemContract as ClassDataContract); + } + if (!TryGetReferencedListType(itemContract, isItemTypeNullable, out baseTypeReference)) + { + if (SupportsGenericTypeReference) + { + baseTypeReference = GetCodeTypeReference(typeof(List<>)); + baseTypeReference.TypeArguments.Add(GetElementTypeReference(itemContract, isItemTypeNullable)); + } + else + { + string expectedTypeName = Globals.ArrayPrefix + itemContract.StableName.Name; + string expectedTypeNs = SchemaHelper.GetCollectionNamespace(itemContract.StableName.Namespace); + throw ExceptionUtil.ThrowHelperError(new InvalidOperationException(SR.Format(SR.ReferencedBaseTypeDoesNotExist, + dataContractName, collectionContract.StableName.Namespace, + expectedTypeName, expectedTypeNs, GetClrTypeFullName(typeof(IList<>)), GetClrTypeFullName(typeof(ICollection<>))))); + } + } + } + + // This is supposed to be set by GenerateType. If it wasn't, there is a problem. + Debug.Assert(contractCodeDomInfo.TypeDeclaration != null); + + CodeTypeDeclaration generatedType = contractCodeDomInfo.TypeDeclaration; + generatedType.BaseTypes.Add(baseTypeReference); + CodeAttributeDeclaration collectionContractAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(CollectionDataContractAttribute))); + collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.NameProperty, new CodePrimitiveExpression(dataContractName))); + collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.NamespaceProperty, new CodePrimitiveExpression(collectionContract.StableName.Namespace))); + if (collectionContract.IsReference != Globals.DefaultIsReference) + collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.IsReferenceProperty, new CodePrimitiveExpression(collectionContract.IsReference))); + collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.ItemNameProperty, new CodePrimitiveExpression(GetNameForAttribute(collectionContract.ItemName)))); + if (foundDictionaryBase) + { + // These are not null if we are working with a dictionary. See CollectionDataContract.IsDictionary + Debug.Assert(collectionContract.KeyName != null); + Debug.Assert(collectionContract.ValueName != null); + collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.KeyNameProperty, new CodePrimitiveExpression(GetNameForAttribute(collectionContract.KeyName)))); + collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.ValueNameProperty, new CodePrimitiveExpression(GetNameForAttribute(collectionContract.ValueName)))); + } + generatedType.CustomAttributes.Add(collectionContractAttribute); + AddImportStatement(typeof(CollectionDataContractAttribute).Namespace, contractCodeDomInfo.CodeNamespace); + AddSerializableAttribute(GenerateSerializableTypes, generatedType, contractCodeDomInfo); + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private void ExportXmlDataContract(XmlDataContract xmlDataContract, ContractCodeDomInfo contractCodeDomInfo) + { + GenerateType(xmlDataContract, contractCodeDomInfo); + if (contractCodeDomInfo.ReferencedTypeExists) + return; + + // This is supposed to be set by GenerateType. If it wasn't, there is a problem. + Debug.Assert(contractCodeDomInfo.TypeDeclaration != null); + + CodeTypeDeclaration type = contractCodeDomInfo.TypeDeclaration; + if (SupportsPartialTypes) + type.IsPartial = true; + if (xmlDataContract.IsValueType) + type.IsStruct = true; + else + { + type.IsClass = true; + type.BaseTypes.Add(typeof(object)); + } + AddSerializableAttribute(GenerateSerializableTypes, type, contractCodeDomInfo); + + type.BaseTypes.Add(GetClrTypeFullName(typeof(IXmlSerializable))); + + type.Members.Add(NodeArrayField); + type.Members.Add(NodeArrayProperty); + type.Members.Add(ReadXmlMethod); + type.Members.Add(WriteXmlMethod); + type.Members.Add(GetSchemaMethod); + if (xmlDataContract.IsAnonymous && !xmlDataContract.HasRoot) + { + type.CustomAttributes.Add(new CodeAttributeDeclaration( + GetClrTypeFullName(Globals.TypeOfXmlSchemaProviderAttribute), + new CodeAttributeArgument(NullReference), + new CodeAttributeArgument(Globals.IsAnyProperty, new CodePrimitiveExpression(true))) + ); + } + else + { + type.CustomAttributes.Add(new CodeAttributeDeclaration( + GetClrTypeFullName(Globals.TypeOfXmlSchemaProviderAttribute), + new CodeAttributeArgument(new CodePrimitiveExpression(Globals.ExportSchemaMethod))) + ); + + CodeMemberField typeNameField = new CodeMemberField(Globals.TypeOfXmlQualifiedName, TypeNameFieldName); + typeNameField.Attributes |= MemberAttributes.Static | MemberAttributes.Private; + XmlQualifiedName typeName = xmlDataContract.IsAnonymous + ? XsdDataContractImporter.ImportActualType(xmlDataContract.XsdType?.Annotation, xmlDataContract.StableName, xmlDataContract.StableName) + : xmlDataContract.StableName; + typeNameField.InitExpression = new CodeObjectCreateExpression(Globals.TypeOfXmlQualifiedName, new CodePrimitiveExpression(typeName.Name), new CodePrimitiveExpression(typeName.Namespace)); + type.Members.Add(typeNameField); + + type.Members.Add(GetSchemaStaticMethod); + + bool isElementNameDifferent = + (xmlDataContract.TopLevelElementName != null && xmlDataContract.TopLevelElementName.Value != xmlDataContract.StableName.Name) || + (xmlDataContract.TopLevelElementNamespace != null && xmlDataContract.TopLevelElementNamespace.Value != xmlDataContract.StableName.Namespace); + if (isElementNameDifferent || xmlDataContract.IsTopLevelElementNullable == false) + { + CodeAttributeDeclaration xmlRootAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(XmlRootAttribute))); + if (isElementNameDifferent) + { + if (xmlDataContract.TopLevelElementName != null) + { + xmlRootAttribute.Arguments.Add(new CodeAttributeArgument("ElementName", new CodePrimitiveExpression(xmlDataContract.TopLevelElementName.Value))); + } + if (xmlDataContract.TopLevelElementNamespace != null) + { + xmlRootAttribute.Arguments.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(xmlDataContract.TopLevelElementNamespace.Value))); + } + } + if (xmlDataContract.IsTopLevelElementNullable == false) + xmlRootAttribute.Arguments.Add(new CodeAttributeArgument("IsNullable", new CodePrimitiveExpression(false))); + type.CustomAttributes.Add(xmlRootAttribute); + } + } + AddPropertyChangedNotifier(contractCodeDomInfo, type.IsStruct); + } + + private CodeNamespace GetCodeNamespace(string clrNamespace, string dataContractNamespace, ContractCodeDomInfo contractCodeDomInfo) + { + if (contractCodeDomInfo.CodeNamespace != null) + return contractCodeDomInfo.CodeNamespace; + + CodeNamespaceCollection codeNamespaceCollection = _codeCompileUnit.Namespaces; + foreach (CodeNamespace ns in codeNamespaceCollection) + { + if (ns.Name == clrNamespace) + { + contractCodeDomInfo.CodeNamespace = ns; + return ns; + } + } + + CodeNamespace codeNamespace = new CodeNamespace(clrNamespace); + codeNamespaceCollection.Add(codeNamespace); + + if (CanDeclareAssemblyAttribute(contractCodeDomInfo) + && NeedsExplicitNamespace(dataContractNamespace, clrNamespace)) + { + CodeAttributeDeclaration namespaceAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(ContractNamespaceAttribute))); + namespaceAttribute.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(dataContractNamespace))); + namespaceAttribute.Arguments.Add(new CodeAttributeArgument(Globals.ClrNamespaceProperty, new CodePrimitiveExpression(clrNamespace))); + _codeCompileUnit.AssemblyCustomAttributes.Add(namespaceAttribute); + } + contractCodeDomInfo.CodeNamespace = codeNamespace; + return codeNamespace; + } + + private static string GetMemberName(string memberName, ContractCodeDomInfo contractCodeDomInfo) + { + memberName = GetClrIdentifier(memberName, Globals.DefaultGeneratedMember); + + // This is only called from Export* methods which have already called GenerateType to fill in this info. + Debug.Assert(contractCodeDomInfo.TypeDeclaration != null); + + if (memberName == contractCodeDomInfo.TypeDeclaration.Name) + memberName = AppendToValidClrIdentifier(memberName, Globals.DefaultMemberSuffix); + + if (contractCodeDomInfo.GetMemberNames().Contains(memberName)) + { + string uniqueMemberName; + for (int i = 1;; i++) + { + uniqueMemberName = AppendToValidClrIdentifier(memberName, i.ToString(NumberFormatInfo.InvariantInfo)); + if (!contractCodeDomInfo.GetMemberNames().Contains(uniqueMemberName)) + { + memberName = uniqueMemberName; + break; + } + } + } + + contractCodeDomInfo.GetMemberNames().Add(memberName); + return memberName; + } + + private static void AddBaseMemberNames(ContractCodeDomInfo baseContractCodeDomInfo, ContractCodeDomInfo contractCodeDomInfo) + { + if (!baseContractCodeDomInfo.ReferencedTypeExists) + { + HashSet baseMemberNames = baseContractCodeDomInfo.GetMemberNames(); + HashSet memberNames = contractCodeDomInfo.GetMemberNames(); + foreach (string name in baseMemberNames) + { + memberNames.Add(name); + } + } + } + + private static string GetClrIdentifier(string identifier, string defaultIdentifier) + { + if (identifier.Length <= MaxIdentifierLength && CodeGenerator.IsValidLanguageIndependentIdentifier(identifier)) + return identifier; + + bool isStart = true; + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < identifier.Length && builder.Length < MaxIdentifierLength; i++) + { + char c = identifier[i]; + if (IsValid(c)) + { + if (isStart && !IsValidStart(c)) + builder.Append('_'); + builder.Append(c); + isStart = false; + } + } + if (builder.Length == 0) + return defaultIdentifier; + + return builder.ToString(); + } + + internal static string GetClrTypeFullName(Type type) + { + return !type.IsGenericTypeDefinition && type.ContainsGenericParameters ? type.Namespace + "." + type.Name : type.FullName!; + } + + private static string AppendToValidClrIdentifier(string identifier, string appendString) + { + int availableLength = MaxIdentifierLength - identifier.Length; + int requiredLength = appendString.Length; + if (availableLength < requiredLength) + identifier = identifier.Substring(0, MaxIdentifierLength - requiredLength); + identifier += appendString; + return identifier; + } + + private string GetClrNamespace(DataContract dataContract, ContractCodeDomInfo contractCodeDomInfo) + { + string? clrNamespace = contractCodeDomInfo.ClrNamespace; + bool usesWildcardNamespace = false; + if (clrNamespace == null) + { + if (!Namespaces.TryGetValue(dataContract.StableName.Namespace, out clrNamespace)) + { + if (Namespaces.TryGetValue(WildcardNamespaceMapping, out clrNamespace)) + { + usesWildcardNamespace = true; + } + else + { + clrNamespace = GetClrNamespace(dataContract.StableName.Namespace); + if (ClrNamespaces.ContainsKey(clrNamespace)) + { + string uniqueNamespace; + for (int i = 1;; i++) + { + uniqueNamespace = ((clrNamespace.Length == 0) ? Globals.DefaultClrNamespace : clrNamespace) + i.ToString(NumberFormatInfo.InvariantInfo); + if (!ClrNamespaces.ContainsKey(uniqueNamespace)) + { + clrNamespace = uniqueNamespace; + break; + } + } + } + AddNamespacePair(dataContract.StableName.Namespace, clrNamespace); + } + } + contractCodeDomInfo.ClrNamespace = clrNamespace; + contractCodeDomInfo.UsesWildcardNamespace = usesWildcardNamespace; + } + return clrNamespace; + } + + private void AddNamespacePair(string dataContractNamespace, string clrNamespace) + { + Namespaces.Add(dataContractNamespace, clrNamespace); + ClrNamespaces.Add(clrNamespace, dataContractNamespace); + } + + private static void AddImportStatement(string? clrNamespace, CodeNamespace? codeNamespace) + { + // We don't expect these to be null when passed in, but they are usually properties on larger classes which declare their types as nullable and we can't control, so we allow nullable parameters. + Debug.Assert(clrNamespace != null); + Debug.Assert(codeNamespace != null); + + if (clrNamespace == codeNamespace.Name) + return; + + CodeNamespaceImportCollection importCollection = codeNamespace.Imports; + foreach (CodeNamespaceImport import in importCollection) + { + if (import.Namespace == clrNamespace) + return; + } + + importCollection.Add(new CodeNamespaceImport(clrNamespace)); + } + + private static string GetClrNamespace(string? dataContractNamespace) + { + if (dataContractNamespace == null || dataContractNamespace.Length == 0) + return string.Empty; + + StringBuilder builder = new StringBuilder(); + if (Uri.TryCreate(dataContractNamespace, UriKind.RelativeOrAbsolute, out Uri? uri)) + { + Dictionary fragments = new Dictionary(StringComparer.OrdinalIgnoreCase); + if (!uri.IsAbsoluteUri) + AddToNamespace(builder, uri.OriginalString, fragments); + else + { + string uriString = uri.AbsoluteUri; + if (uriString.StartsWith(Globals.DataContractXsdBaseNamespace, StringComparison.Ordinal)) + AddToNamespace(builder, uriString.Substring(Globals.DataContractXsdBaseNamespace.Length), fragments); + else + { + string host = uri.Host; + if (host != null) + AddToNamespace(builder, host, fragments); + string path = uri.PathAndQuery; + if (path != null) + AddToNamespace(builder, path, fragments); + } + } + } + + if (builder.Length == 0) + return string.Empty; + + int length = builder.Length; + if (builder[builder.Length - 1] == '.') + length--; + length = Math.Min(MaxIdentifierLength, length); + + return builder.ToString(0, length); + } + + private static void AddToNamespace(StringBuilder builder, string? fragment, Dictionary fragments) + { + if (fragment == null) + return; + bool isStart = true; + int fragmentOffset = builder.Length; + int fragmentLength = 0; + + for (int i = 0; i < fragment.Length && builder.Length < MaxIdentifierLength; i++) + { + char c = fragment[i]; + + if (IsValid(c)) + { + if (isStart && !IsValidStart(c)) + builder.Append('_'); + builder.Append(c); + fragmentLength++; + isStart = false; + } + else if ((c == '.' || c == '/' || c == ':') && (builder.Length == 1 + || (builder.Length > 1 && builder[builder.Length - 1] != '.'))) + { + AddNamespaceFragment(builder, fragmentOffset, fragmentLength, fragments); + builder.Append('.'); + fragmentOffset = builder.Length; + fragmentLength = 0; + isStart = true; + } + } + AddNamespaceFragment(builder, fragmentOffset, fragmentLength, fragments); + } + + private static void AddNamespaceFragment(StringBuilder builder, int fragmentOffset, + int fragmentLength, Dictionary fragments) + { + if (fragmentLength == 0) + return; + + string nsFragment = builder.ToString(fragmentOffset, fragmentLength); + if (fragments.ContainsKey(nsFragment)) + { + for (int i = 1;; i++) + { + string uniquifier = i.ToString(NumberFormatInfo.InvariantInfo); + string uniqueNsFragment = AppendToValidClrIdentifier(nsFragment, uniquifier); + if (!fragments.ContainsKey(uniqueNsFragment)) + { + builder.Append(uniquifier); + nsFragment = uniqueNsFragment; + break; + } + if (i == int.MaxValue) + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.CannotComputeUniqueName, nsFragment))); + } + } + fragments.Add(nsFragment, null); + } + + [RequiresUnreferencedCode("TODO smolloy - Placeholder")] + internal static bool IsObjectContract(DataContract dataContract) + { + Dictionary previousCollectionTypes = new Dictionary(); + while (dataContract is CollectionDataContract) + { + if (dataContract.OriginalUnderlyingType == null) + { + dataContract = ((CollectionDataContract)dataContract).ItemContract; + continue; + } + + if (!previousCollectionTypes.ContainsKey(dataContract.OriginalUnderlyingType)) + { + previousCollectionTypes.Add(dataContract.OriginalUnderlyingType, dataContract.OriginalUnderlyingType); + dataContract = ((CollectionDataContract)dataContract).ItemContract; + } + else + { + break; + } + } + + return dataContract is PrimitiveDataContract && ((PrimitiveDataContract)dataContract).UnderlyingType == typeof(object); + } + + private static bool IsValidStart(char c) + { + return (char.GetUnicodeCategory(c) != UnicodeCategory.DecimalDigitNumber); + } + + private static bool IsValid(char c) + { + UnicodeCategory uc = char.GetUnicodeCategory(c); + + // each char must be Lu, Ll, Lt, Lm, Lo, Nd, Mn, Mc, Pc + + switch (uc) + { + case UnicodeCategory.UppercaseLetter: // Lu + case UnicodeCategory.LowercaseLetter: // Ll + case UnicodeCategory.TitlecaseLetter: // Lt + case UnicodeCategory.ModifierLetter: // Lm + case UnicodeCategory.OtherLetter: // Lo + case UnicodeCategory.DecimalDigitNumber: // Nd + case UnicodeCategory.NonSpacingMark: // Mn + case UnicodeCategory.SpacingCombiningMark: // Mc + case UnicodeCategory.ConnectorPunctuation: // Pc + return true; + default: + return false; + } + } + + private CodeTypeReference CodeTypeIPropertyChange + { + get { return GetCodeTypeReference(typeof(System.ComponentModel.INotifyPropertyChanged)); } + } + + private static CodeThisReferenceExpression ThisReference + { + get { return new CodeThisReferenceExpression(); } + } + + private static CodePrimitiveExpression NullReference + { + get { return new CodePrimitiveExpression(null); } + } + + private CodeParameterDeclarationExpression SerializationInfoParameter + { + get { return new CodeParameterDeclarationExpression(GetCodeTypeReference(typeof(SerializationInfo)), Globals.SerializationInfoFieldName); } + } + + private CodeParameterDeclarationExpression StreamingContextParameter + { + get { return new CodeParameterDeclarationExpression(GetCodeTypeReference(typeof(StreamingContext)), Globals.ContextFieldName); } + } + + private CodeAttributeDeclaration SerializableAttribute + { + get { return new CodeAttributeDeclaration(GetCodeTypeReference(typeof(SerializableAttribute))); } + } + + private CodeMemberProperty NodeArrayProperty + { + get + { + return CreateProperty(GetCodeTypeReference(Globals.TypeOfXmlNodeArray), Globals.NodeArrayPropertyName, Globals.NodeArrayFieldName, false/*isValueType*/); + } + } + + private CodeMemberField NodeArrayField + { + get + { + CodeMemberField nodeArrayField = new CodeMemberField(); + nodeArrayField.Type = GetCodeTypeReference(Globals.TypeOfXmlNodeArray); + nodeArrayField.Name = Globals.NodeArrayFieldName; + nodeArrayField.Attributes = MemberAttributes.Private; + return nodeArrayField; + } + } + + private CodeMemberMethod ReadXmlMethod + { + get + { + CodeMemberMethod readXmlMethod = new CodeMemberMethod(); + readXmlMethod.Name = "ReadXml"; + CodeParameterDeclarationExpression readerArg = new CodeParameterDeclarationExpression(typeof(XmlReader), "reader"); + readXmlMethod.Parameters.Add(readerArg); + readXmlMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final; + readXmlMethod.ImplementationTypes.Add(typeof(IXmlSerializable)); + CodeAssignStatement setNode = new CodeAssignStatement(); + setNode.Left = new CodeFieldReferenceExpression(ThisReference, Globals.NodeArrayFieldName); + setNode.Right = new CodeMethodInvokeExpression( + new CodeTypeReferenceExpression(GetCodeTypeReference(typeof(XmlSerializableServices))), + nameof(XmlSerializableServices.ReadNodes), + new CodeArgumentReferenceExpression(readerArg.Name) + ); + readXmlMethod.Statements.Add(setNode); + return readXmlMethod; + } + } + + private CodeMemberMethod WriteXmlMethod + { + get + { + CodeMemberMethod writeXmlMethod = new CodeMemberMethod(); + writeXmlMethod.Name = "WriteXml"; + CodeParameterDeclarationExpression writerArg = new CodeParameterDeclarationExpression(typeof(XmlWriter), "writer"); + writeXmlMethod.Parameters.Add(writerArg); + writeXmlMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final; + writeXmlMethod.ImplementationTypes.Add(typeof(IXmlSerializable)); + writeXmlMethod.Statements.Add( + new CodeMethodInvokeExpression( + new CodeTypeReferenceExpression(GetCodeTypeReference(typeof(XmlSerializableServices))), + nameof(XmlSerializableServices.WriteNodes), + new CodeArgumentReferenceExpression(writerArg.Name), + new CodePropertyReferenceExpression(ThisReference, Globals.NodeArrayPropertyName) + ) + ); + return writeXmlMethod; + } + } + + private CodeMemberMethod GetSchemaMethod + { + get + { + CodeMemberMethod getSchemaMethod = new CodeMemberMethod(); + getSchemaMethod.Name = "GetSchema"; + getSchemaMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final; + getSchemaMethod.ImplementationTypes.Add(typeof(IXmlSerializable)); + getSchemaMethod.ReturnType = GetCodeTypeReference(typeof(XmlSchema)); + getSchemaMethod.Statements.Add(new CodeMethodReturnStatement(NullReference)); + return getSchemaMethod; + } + } + + private CodeMemberMethod GetSchemaStaticMethod + { + get + { + CodeMemberMethod getSchemaStaticMethod = new CodeMemberMethod(); + getSchemaStaticMethod.Name = Globals.ExportSchemaMethod; + getSchemaStaticMethod.ReturnType = GetCodeTypeReference(Globals.TypeOfXmlQualifiedName); + CodeParameterDeclarationExpression paramDeclaration = new CodeParameterDeclarationExpression(typeof(XmlSchemaSet), "schemas"); + getSchemaStaticMethod.Parameters.Add(paramDeclaration); + getSchemaStaticMethod.Attributes = MemberAttributes.Static | MemberAttributes.Public; + getSchemaStaticMethod.Statements.Add( + new CodeMethodInvokeExpression( + new CodeTypeReferenceExpression(GetCodeTypeReference(typeof(XmlSerializableServices))), + nameof(XmlSerializableServices.AddDefaultSchema), + new CodeArgumentReferenceExpression(paramDeclaration.Name), + new CodeFieldReferenceExpression(null, TypeNameFieldName) + ) + ); + getSchemaStaticMethod.Statements.Add( + new CodeMethodReturnStatement( + new CodeFieldReferenceExpression(null, TypeNameFieldName) + ) + ); + return getSchemaStaticMethod; + } + } + + private CodeConstructor ISerializableBaseConstructor + { + get + { + CodeConstructor baseConstructor = new CodeConstructor(); + baseConstructor.Attributes = MemberAttributes.Public; + baseConstructor.Parameters.Add(SerializationInfoParameter); + baseConstructor.Parameters.Add(StreamingContextParameter); + CodeAssignStatement setObjectData = new CodeAssignStatement(); + setObjectData.Left = new CodePropertyReferenceExpression(ThisReference, Globals.SerializationInfoFieldName); + setObjectData.Right = new CodeArgumentReferenceExpression(Globals.SerializationInfoFieldName); + baseConstructor.Statements.Add(setObjectData); + // Special-cased check for vb here since CodeGeneratorOptions does not provide information indicating that VB cannot initialize event member + if (EnableDataBinding && SupportsDeclareEvents && string.CompareOrdinal(FileExtension, "vb") != 0) + { + baseConstructor.Statements.Add(new CodeAssignStatement(new CodePropertyReferenceExpression(ThisReference, PropertyChangedEvent.Name), NullReference)); + } + return baseConstructor; + } + } + + private CodeConstructor ISerializableDerivedConstructor + { + get + { + CodeConstructor derivedConstructor = new CodeConstructor(); + derivedConstructor.Attributes = MemberAttributes.Public; + derivedConstructor.Parameters.Add(SerializationInfoParameter); + derivedConstructor.Parameters.Add(StreamingContextParameter); + derivedConstructor.BaseConstructorArgs.Add(new CodeVariableReferenceExpression(Globals.SerializationInfoFieldName)); + derivedConstructor.BaseConstructorArgs.Add(new CodeVariableReferenceExpression(Globals.ContextFieldName)); + return derivedConstructor; + } + } + + private CodeMemberField SerializationInfoField + { + get + { + CodeMemberField serializationInfoField = new CodeMemberField(); + serializationInfoField.Type = GetCodeTypeReference(typeof(SerializationInfo)); + serializationInfoField.Name = Globals.SerializationInfoFieldName; + serializationInfoField.Attributes = MemberAttributes.Private; + return serializationInfoField; + } + } + + private CodeMemberProperty SerializationInfoProperty + { + get + { + return CreateProperty(GetCodeTypeReference(typeof(SerializationInfo)), Globals.SerializationInfoPropertyName, Globals.SerializationInfoFieldName, false/*isValueType*/); + } + } + + private CodeMemberMethod GetObjectDataMethod + { + get + { + CodeMemberMethod getObjectDataMethod = new CodeMemberMethod(); + getObjectDataMethod.Name = Globals.GetObjectDataMethodName; + getObjectDataMethod.Parameters.Add(SerializationInfoParameter); + getObjectDataMethod.Parameters.Add(StreamingContextParameter); + getObjectDataMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final; + getObjectDataMethod.ImplementationTypes.Add(typeof(ISerializable)); + + // Generates: if (this.SerializationInfo == null) return; + CodeConditionStatement returnIfNull = new CodeConditionStatement(); + returnIfNull.Condition = new CodeBinaryOperatorExpression( + new CodePropertyReferenceExpression(ThisReference, Globals.SerializationInfoPropertyName), + CodeBinaryOperatorType.IdentityEquality, + NullReference); + returnIfNull.TrueStatements.Add(new CodeMethodReturnStatement()); + + // Generates: SerializationInfoEnumerator enumerator = this.SerializationInfo.GetEnumerator(); + CodeVariableDeclarationStatement getEnumerator = new CodeVariableDeclarationStatement(); + getEnumerator.Type = GetCodeTypeReference(typeof(SerializationInfoEnumerator)); + getEnumerator.Name = Globals.EnumeratorFieldName; + getEnumerator.InitExpression = new CodeMethodInvokeExpression( + new CodePropertyReferenceExpression(ThisReference, Globals.SerializationInfoPropertyName), + Globals.GetEnumeratorMethodName); + + //Generates: SerializationEntry entry = enumerator.Current; + CodeVariableDeclarationStatement getCurrent = new CodeVariableDeclarationStatement(); + getCurrent.Type = GetCodeTypeReference(typeof(SerializationEntry)); + getCurrent.Name = Globals.SerializationEntryFieldName; + getCurrent.InitExpression = new CodePropertyReferenceExpression( + new CodeVariableReferenceExpression(Globals.EnumeratorFieldName), + Globals.CurrentPropertyName); + + //Generates: info.AddValue(entry.Name, entry.Value); + CodeExpressionStatement addValue = new CodeExpressionStatement(); + CodePropertyReferenceExpression getCurrentName = new CodePropertyReferenceExpression( + new CodeVariableReferenceExpression(Globals.SerializationEntryFieldName), + Globals.NameProperty); + CodePropertyReferenceExpression getCurrentValue = new CodePropertyReferenceExpression( + new CodeVariableReferenceExpression(Globals.SerializationEntryFieldName), + Globals.ValueProperty); + addValue.Expression = new CodeMethodInvokeExpression( + new CodeArgumentReferenceExpression(Globals.SerializationInfoFieldName), + Globals.AddValueMethodName, + new CodeExpression[] { getCurrentName, getCurrentValue }); + + //Generates: for (; enumerator.MoveNext(); ) + CodeIterationStatement loop = new CodeIterationStatement(); + loop.TestExpression = new CodeMethodInvokeExpression( + new CodeVariableReferenceExpression(Globals.EnumeratorFieldName), + Globals.MoveNextMethodName); + loop.InitStatement = loop.IncrementStatement = new CodeSnippetStatement(string.Empty); + loop.Statements.Add(getCurrent); + loop.Statements.Add(addValue); + + getObjectDataMethod.Statements.Add(returnIfNull); + getObjectDataMethod.Statements.Add(getEnumerator); + getObjectDataMethod.Statements.Add(loop); + + return getObjectDataMethod; + } + } + + private CodeMemberField ExtensionDataObjectField + { + get + { + CodeMemberField extensionDataObjectField = new CodeMemberField(); + extensionDataObjectField.Type = GetCodeTypeReference(typeof(ExtensionDataObject)); + extensionDataObjectField.Name = Globals.ExtensionDataObjectFieldName; + extensionDataObjectField.Attributes = MemberAttributes.Private; + return extensionDataObjectField; + } + } + + private CodeMemberProperty ExtensionDataObjectProperty + { + get + { + CodeMemberProperty extensionDataObjectProperty = new CodeMemberProperty(); + extensionDataObjectProperty.Type = GetCodeTypeReference(typeof(ExtensionDataObject)); + extensionDataObjectProperty.Name = Globals.ExtensionDataObjectPropertyName; + extensionDataObjectProperty.Attributes = MemberAttributes.Public | MemberAttributes.Final; + extensionDataObjectProperty.ImplementationTypes.Add(typeof(IExtensibleDataObject)); + + CodeMethodReturnStatement propertyGet = new CodeMethodReturnStatement(); + propertyGet.Expression = new CodeFieldReferenceExpression(ThisReference, Globals.ExtensionDataObjectFieldName); + extensionDataObjectProperty.GetStatements.Add(propertyGet); + + CodeAssignStatement propertySet = new CodeAssignStatement(); + propertySet.Left = new CodeFieldReferenceExpression(ThisReference, Globals.ExtensionDataObjectFieldName); + propertySet.Right = new CodePropertySetValueReferenceExpression(); + extensionDataObjectProperty.SetStatements.Add(propertySet); + + return extensionDataObjectProperty; + } + } + + private CodeMemberMethod RaisePropertyChangedEventMethod + { + get + { + CodeMemberMethod raisePropertyChangedEventMethod = new CodeMemberMethod(); + raisePropertyChangedEventMethod.Name = "RaisePropertyChanged"; + raisePropertyChangedEventMethod.Attributes = MemberAttributes.Final; + CodeArgumentReferenceExpression propertyName = new CodeArgumentReferenceExpression("propertyName"); + raisePropertyChangedEventMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(string), propertyName.ParameterName)); + CodeVariableReferenceExpression propertyChanged = new CodeVariableReferenceExpression("propertyChanged"); + raisePropertyChangedEventMethod.Statements.Add(new CodeVariableDeclarationStatement(typeof(PropertyChangedEventHandler), propertyChanged.VariableName, new CodeEventReferenceExpression(ThisReference, PropertyChangedEvent.Name))); + CodeConditionStatement ifStatement = new CodeConditionStatement(new CodeBinaryOperatorExpression(propertyChanged, CodeBinaryOperatorType.IdentityInequality, NullReference)); + raisePropertyChangedEventMethod.Statements.Add(ifStatement); + ifStatement.TrueStatements.Add(new CodeDelegateInvokeExpression(propertyChanged, ThisReference, new CodeObjectCreateExpression(typeof(PropertyChangedEventArgs), propertyName))); + return raisePropertyChangedEventMethod; + } + } + + private CodeMemberEvent PropertyChangedEvent + { + get + { + CodeMemberEvent propertyChangedEvent = new CodeMemberEvent(); + propertyChangedEvent.Attributes = MemberAttributes.Public; + propertyChangedEvent.Name = "PropertyChanged"; + propertyChangedEvent.Type = GetCodeTypeReference(typeof(PropertyChangedEventHandler)); + propertyChangedEvent.ImplementationTypes.Add(typeof(INotifyPropertyChanged)); + return propertyChangedEvent; + } + } + + private CodeMemberProperty CreateProperty(CodeTypeReference type, string propertyName, string fieldName, bool isValueType) + { + return CreateProperty(type, propertyName, fieldName, isValueType, EnableDataBinding && SupportsDeclareEvents); + } + + private CodeMemberProperty CreateProperty(CodeTypeReference type, string propertyName, string fieldName, bool isValueType, bool raisePropertyChanged) + { + CodeMemberProperty property = new CodeMemberProperty(); + property.Type = type; + property.Name = propertyName; + property.Attributes = MemberAttributes.Final; + if (GenerateInternalTypes) + property.Attributes |= MemberAttributes.Assembly; + else + property.Attributes |= MemberAttributes.Public; + + CodeMethodReturnStatement propertyGet = new CodeMethodReturnStatement(); + propertyGet.Expression = new CodeFieldReferenceExpression(ThisReference, fieldName); + property.GetStatements.Add(propertyGet); + + CodeAssignStatement propertySet = new CodeAssignStatement(); + propertySet.Left = new CodeFieldReferenceExpression(ThisReference, fieldName); + propertySet.Right = new CodePropertySetValueReferenceExpression(); + if (raisePropertyChanged) + { + CodeConditionStatement ifStatement = new CodeConditionStatement(); + CodeExpression left = new CodeFieldReferenceExpression(ThisReference, fieldName); + CodeExpression right = new CodePropertySetValueReferenceExpression(); + if (!isValueType) + { + left = new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(typeof(object)), + "ReferenceEquals", new CodeExpression[] { left, right }); + } + else + { + left = new CodeMethodInvokeExpression(left, "Equals", new CodeExpression[] { right }); + } + right = new CodePrimitiveExpression(true); + ifStatement.Condition = new CodeBinaryOperatorExpression(left, CodeBinaryOperatorType.IdentityInequality, right); + ifStatement.TrueStatements.Add(propertySet); + ifStatement.TrueStatements.Add(new CodeMethodInvokeExpression(ThisReference, RaisePropertyChangedEventMethod.Name, new CodePrimitiveExpression(propertyName))); + property.SetStatements.Add(ifStatement); + } + else + property.SetStatements.Add(propertySet); + return property; + } + } +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs new file mode 100644 index 0000000000000..943376b1e3153 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs @@ -0,0 +1,54 @@ +// 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.CodeDom; +using System.Collections.Generic; +using System.Xml; +using System.Xml.Schema; + +using ExceptionUtil = System.Runtime.Serialization.Schema.DiagnosticUtility.ExceptionUtility; + +namespace System.Runtime.Serialization.Schema +{ + internal sealed class ContractCodeDomInfo + { + private string? _clrNamespace; + // TODO smolloy - This was a Dictionary previously, so adding a duplicate entry would throw an exception. + // HashSet does not allow duplicates either, but it just returns false instead of throwing. I think it's safe to not + // throw in that case here, so long as we don't add duplicates. It's just a string list. + private HashSet? _memberNames; + + internal string? ClrNamespace + { + get { return ReferencedTypeExists ? null : _clrNamespace; } + set + { + if (ReferencedTypeExists) + throw ExceptionUtil.ThrowHelperError(new InvalidOperationException(SR.Format(SR.CannotSetNamespaceForReferencedType, TypeReference?.BaseType))); + else + _clrNamespace = value; + } + } + + internal CodeNamespace? CodeNamespace { get; set; } + + internal bool IsProcessed { get; set; } + + internal bool ReferencedTypeExists { get; set; } + + internal CodeTypeDeclaration? TypeDeclaration { get; set; } + + internal CodeTypeReference? TypeReference { get; set; } + + internal bool UsesWildcardNamespace { get; set; } + + internal HashSet GetMemberNames() + { + if (ReferencedTypeExists) + throw ExceptionUtil.ThrowHelperError(new InvalidOperationException(SR.Format(SR.CannotSetMembersForReferencedType, TypeReference?.BaseType))); + else + return _memberNames ??= new HashSet(StringComparer.OrdinalIgnoreCase); + } + } +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/DiagnosticUtility.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/DiagnosticUtility.cs new file mode 100644 index 0000000000000..1a89968bfa62d --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/DiagnosticUtility.cs @@ -0,0 +1,115 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; + +namespace System.Runtime.Serialization.Schema +{ + internal static class DiagnosticUtility + { + [Conditional("DEBUG")] + [DoesNotReturn] + public static void DebugAssert(string message) + { + DebugAssert(false, message); + } + + [Conditional("DEBUG")] + public static void DebugAssert([DoesNotReturnIf(false)] bool condition, string message) + { + Debug.Assert(condition, message); + } + + internal static class ExceptionUtility + { + public static Exception ThrowHelperArgumentNull(string message) + { + return new ArgumentNullException(message); + } + + public static Exception ThrowHelperError(Exception e) + { + return e; + } + + public static Exception ThrowHelperArgument(string message) + { + return new ArgumentException(message); + } + + internal static Exception ThrowHelperFatal(string message, Exception innerException) + { + return ThrowHelperError(new Exception(message, innerException)); + } + internal static Exception ThrowHelperCallback(Exception e) + { + return ThrowHelperError(e); + } + } + } + + + // TODO smolloy - same deal as other places. Code below is original from DCS. Copy what we need up above. + // remove this code when done. +#if unused + internal static class Fx + { + [Conditional("DEBUG")] + public static void Assert([DoesNotReturnIf(false)] bool condition, string message) + { + System.Diagnostics.Debug.Assert(condition, message); + } + + [Conditional("DEBUG")] + [DoesNotReturn] + public static void Assert(string message) + { + Assert(false, message); + } + } + + internal static class DiagnosticUtility + { + [Conditional("DEBUG")] + [DoesNotReturn] + public static void DebugAssert(string message) + { + DebugAssert(false, message); + } + + [Conditional("DEBUG")] + public static void DebugAssert([DoesNotReturnIf(false)] bool condition, string message) + { + Debug.Assert(condition, message); + } + + internal static class ExceptionUtility + { + public static Exception ThrowHelperArgumentNull(string message) + { + return new ArgumentNullException(message); + } + + public static Exception ThrowHelperError(Exception e) + { + return e; + } + + public static Exception ThrowHelperArgument(string message) + { + return new ArgumentException(message); + } + + internal static Exception ThrowHelperFatal(string message, Exception innerException) + { + return ThrowHelperError(new Exception(message, innerException)); + } + internal static Exception ThrowHelperCallback(Exception e) + { + return ThrowHelperError(e); + } + } + } +#endif +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ExportOptions.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ExportOptions.cs new file mode 100644 index 0000000000000..c6e41b4b87677 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ExportOptions.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.ObjectModel; + +namespace System.Runtime.Serialization.Schema +{ + // TODO smolloy - should we rename this to avoid confusion with Sys.RT.Ser.ExportOptions? Rename ImportOptions to match. + // Do we even need this class? It is not a different signature than the in-box one. Should we just use that? + // Actually, that's not quite right. This _would be_ the same signature if export supported surrogates in box. + // But it doesn't, so the surrogate provider is not there. We could add it. Or just use this class. Depends on which + // is the more likely "pit of success" I guess. + public class ExportOptions + { + // TODO smolloy - this is named differently than the in-box version of the options. + public ISerializationSurrogateProvider? SurrogateProvider { get; set; } + + // TODO smolloy - This was used in core already. Since the idea is to shift this export functionality out here, this + // existing piece should come along with us. Which is to say, we probably still need this. + private Collection? _knownTypes; + public Collection KnownTypes => _knownTypes ??= new Collection(); + } +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/Globals.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/Globals.cs new file mode 100644 index 0000000000000..22ad633b47dd7 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/Globals.cs @@ -0,0 +1,614 @@ +// 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.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Reflection; +using System.Text.RegularExpressions; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; + +namespace System.Runtime.Serialization.Schema +{ + internal static class Globals + { + internal const string SerializerTrimmerWarning = "Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the " + + "required types are preserved."; + + public const string ActualTypeLocalName = "ActualType"; + public const string ActualTypeNameAttribute = "Name"; + public const string ActualTypeNamespaceAttribute = "Namespace"; + public const string AddValueMethodName = "AddValue"; + public const string AnyTypeLocalName = "anyType"; + public const string ArrayPrefix = "ArrayOf"; + public const string ClrNamespaceProperty = "ClrNamespace"; + public const string ContextFieldName = "context"; + public const string CurrentPropertyName = "Current"; + public const string DataContractXsdBaseNamespace = "http://schemas.datacontract.org/2004/07/"; + public const string DefaultClrNamespace = "GeneratedNamespace"; + public const bool DefaultEmitDefaultValue = true; + public const string DefaultGeneratedMember = "GeneratedMember"; + public const string DefaultFieldSuffix = "Field"; + public const bool DefaultIsReference = false; + public const bool DefaultIsRequired = false; + public const string DefaultMemberSuffix = "Member"; + public const int DefaultOrder = 0; + public const string DefaultTypeName = "GeneratedType"; + public const string DefaultValueLocalName = "DefaultValue"; + public const string EmitDefaultValueAttribute = "EmitDefaultValue"; + public const string EmitDefaultValueProperty = "EmitDefaultValue"; + public const string EnumerationValueLocalName = "EnumerationValue"; + public const string EnumeratorFieldName = "enumerator"; + public const string ExportSchemaMethod = "ExportSchema"; + public const string ExtensionDataObjectFieldName = "extensionDataField"; + public const string ExtensionDataObjectPropertyName = "ExtensionData"; + public const string False = "false"; + public const string GenericNameAttribute = "Name"; + public const string GenericNamespaceAttribute = "Namespace"; + public const string GenericParameterLocalName = "GenericParameter"; + public const string GenericParameterNestedLevelAttribute = "NestedLevel"; + public const string GenericTypeLocalName = "GenericType"; + public const string GetEnumeratorMethodName = "GetEnumerator"; + public const string GetObjectDataMethodName = "GetObjectData"; + public const string IdLocalName = "Id"; + public const string IntLocalName = "int"; + public const string IsAnyProperty = "IsAny"; + public const string IsDictionaryLocalName = "IsDictionary"; + public const string ISerializableFactoryTypeLocalName = "FactoryType"; + public const string IsReferenceProperty = "IsReference"; + public const string IsRequiredProperty = "IsRequired"; + public const string IsValueTypeLocalName = "IsValueType"; + public const string ItemNameProperty = "ItemName"; + public const string KeyLocalName = "Key"; + public const string KeyNameProperty = "KeyName"; + public const string MoveNextMethodName = "MoveNext"; + public const string NameProperty = "Name"; + public const string NamespaceProperty = "Namespace"; + public const string NodeArrayFieldName = "nodesField"; + public const string NodeArrayPropertyName = "Nodes"; + public const string OccursUnbounded = "unbounded"; + public const string OrderProperty = "Order"; + public const string RefLocalName = "Ref"; + public const string SchemaInstanceNamespace = "http://www.w3.org/2001/XMLSchema-instance"; + public const string SchemaLocalName = "schema"; + public const string SchemaNamespace = "http://www.w3.org/2001/XMLSchema"; + public const string SerializationEntryFieldName = "entry"; + public const string SerializationInfoFieldName = "info"; + public const string SerializationInfoPropertyName = "SerializationInfo"; + public const string SerializationNamespace = "http://schemas.microsoft.com/2003/10/Serialization/"; + public const string SerPrefixForSchema = "ser"; + public const string StringLocalName = "string"; + public const string SurrogateDataLocalName = "Surrogate"; + public const string TnsPrefix = "tns"; + public const string True = "true"; + public const string ValueLocalName = "Value"; + public const string ValueNameProperty = "ValueName"; + public const string ValueProperty = "Value"; + + private static Uri? s_dataContractXsdBaseNamespaceUri; + internal static Uri DataContractXsdBaseNamespaceUri => s_dataContractXsdBaseNamespaceUri ??= new Uri(DataContractXsdBaseNamespace); + + private static XmlQualifiedName? s_idQualifiedName; + internal static XmlQualifiedName IdQualifiedName => s_idQualifiedName ??= new XmlQualifiedName(Globals.IdLocalName, Globals.SerializationNamespace); + + private static XmlQualifiedName? s_refQualifiedName; + internal static XmlQualifiedName RefQualifiedName => s_refQualifiedName ??= new XmlQualifiedName(Globals.RefLocalName, Globals.SerializationNamespace); + + private static Type? s_typeOfXmlElement; + internal static Type TypeOfXmlElement => s_typeOfXmlElement ??= typeof(XmlElement); + + private static Type? s_typeOfXmlNodeArray; + internal static Type TypeOfXmlNodeArray => s_typeOfXmlNodeArray ??= typeof(XmlNode[]); + + private static Type? s_typeOfXmlQualifiedName; + internal static Type TypeOfXmlQualifiedName => s_typeOfXmlQualifiedName ??= typeof(XmlQualifiedName); + + private static Type? s_typeOfXmlSchemaProviderAttribute; + internal static Type TypeOfXmlSchemaProviderAttribute => s_typeOfXmlSchemaProviderAttribute ??= typeof(XmlSchemaProviderAttribute); + + private static Type? s_typeOfXmlSchemaType; + internal static Type TypeOfXmlSchemaType => s_typeOfXmlSchemaType ??= typeof(XmlSchemaType); + + + public const string SerializationSchema = @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"; + + // TODO smolloy - All of this came from Sys.Priv.DCS... here for easy copy/paste of the things we need. Delete when done. +#if unused + /// + /// Review - changes to const could affect code generation logic; any changes should be reviewed. + /// + internal const BindingFlags ScanAllMembers = BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public; + + private static XmlQualifiedName? s_idQualifiedName; + internal static XmlQualifiedName IdQualifiedName => + s_idQualifiedName ??= new XmlQualifiedName(Globals.IdLocalName, Globals.SerializationNamespace); + + private static XmlQualifiedName? s_refQualifiedName; + internal static XmlQualifiedName RefQualifiedName => + s_refQualifiedName ??= new XmlQualifiedName(Globals.RefLocalName, Globals.SerializationNamespace); + + private static Type? s_typeOfObject; + internal static Type TypeOfObject => + s_typeOfObject ??= typeof(object); + + private static Type? s_typeOfValueType; + internal static Type TypeOfValueType => + s_typeOfValueType ??= typeof(ValueType); + + private static Type? s_typeOfArray; + internal static Type TypeOfArray => + s_typeOfArray ??= typeof(Array); + + private static Type? s_typeOfString; + internal static Type TypeOfString => + s_typeOfString ??= typeof(string); + + private static Type? s_typeOfInt; + internal static Type TypeOfInt => + s_typeOfInt ??= typeof(int); + + private static Type? s_typeOfULong; + internal static Type TypeOfULong => + s_typeOfULong ??= typeof(ulong); + + private static Type? s_typeOfVoid; + internal static Type TypeOfVoid => + s_typeOfVoid ??= typeof(void); + + private static Type? s_typeOfByteArray; + internal static Type TypeOfByteArray => + s_typeOfByteArray ??= typeof(byte[]); + + private static Type? s_typeOfTimeSpan; + internal static Type TypeOfTimeSpan => + s_typeOfTimeSpan ??= typeof(TimeSpan); + + private static Type? s_typeOfGuid; + internal static Type TypeOfGuid => + s_typeOfGuid ??= typeof(Guid); + + private static Type? s_typeOfDateTimeOffset; + internal static Type TypeOfDateTimeOffset => + s_typeOfDateTimeOffset ??= typeof(DateTimeOffset); + + private static Type? s_typeOfDateTimeOffsetAdapter; + internal static Type TypeOfDateTimeOffsetAdapter => + s_typeOfDateTimeOffsetAdapter ??= typeof(DateTimeOffsetAdapter); + + private static Type? s_typeOfMemoryStream; + internal static Type TypeOfMemoryStream => + s_typeOfMemoryStream ??= typeof(MemoryStream); + + private static Type? s_typeOfMemoryStreamAdapter; + internal static Type TypeOfMemoryStreamAdapter => + s_typeOfMemoryStreamAdapter ??= typeof(MemoryStreamAdapter); + + private static Type? s_typeOfUri; + internal static Type TypeOfUri => + s_typeOfUri ??= typeof(Uri); + + private static Type? s_typeOfTypeEnumerable; + internal static Type TypeOfTypeEnumerable => + s_typeOfTypeEnumerable ??= typeof(IEnumerable); + + private static Type? s_typeOfStreamingContext; + internal static Type TypeOfStreamingContext => + s_typeOfStreamingContext ??= typeof(StreamingContext); + + private static Type? s_typeOfISerializable; + internal static Type TypeOfISerializable => + s_typeOfISerializable ??= typeof(ISerializable); + + private static Type? s_typeOfIDeserializationCallback; + internal static Type TypeOfIDeserializationCallback => + s_typeOfIDeserializationCallback ??= typeof(IDeserializationCallback); + + private static Type? s_typeOfIObjectReference; + internal static Type TypeOfIObjectReference => + s_typeOfIObjectReference ??= typeof(IObjectReference); + + private static Type? s_typeOfXmlFormatClassWriterDelegate; + internal static Type TypeOfXmlFormatClassWriterDelegate => + s_typeOfXmlFormatClassWriterDelegate ??= typeof(XmlFormatClassWriterDelegate); + + private static Type? s_typeOfXmlFormatCollectionWriterDelegate; + internal static Type TypeOfXmlFormatCollectionWriterDelegate => + s_typeOfXmlFormatCollectionWriterDelegate ??= typeof(XmlFormatCollectionWriterDelegate); + + private static Type? s_typeOfXmlFormatClassReaderDelegate; + internal static Type TypeOfXmlFormatClassReaderDelegate => + s_typeOfXmlFormatClassReaderDelegate ??= typeof(XmlFormatClassReaderDelegate); + + private static Type? s_typeOfXmlFormatCollectionReaderDelegate; + internal static Type TypeOfXmlFormatCollectionReaderDelegate => + s_typeOfXmlFormatCollectionReaderDelegate ??= typeof(XmlFormatCollectionReaderDelegate); + + private static Type? s_typeOfXmlFormatGetOnlyCollectionReaderDelegate; + internal static Type TypeOfXmlFormatGetOnlyCollectionReaderDelegate => + s_typeOfXmlFormatGetOnlyCollectionReaderDelegate ??= typeof(XmlFormatGetOnlyCollectionReaderDelegate); + + private static Type? s_typeOfKnownTypeAttribute; + internal static Type TypeOfKnownTypeAttribute => + s_typeOfKnownTypeAttribute ??= typeof(KnownTypeAttribute); + + private static Type? s_typeOfDataContractAttribute; + internal static Type TypeOfDataContractAttribute => + s_typeOfDataContractAttribute ??= typeof(DataContractAttribute); + + private static Type? s_typeOfDataMemberAttribute; + internal static Type TypeOfDataMemberAttribute => + s_typeOfDataMemberAttribute ??= typeof(DataMemberAttribute); + + private static Type? s_typeOfEnumMemberAttribute; + internal static Type TypeOfEnumMemberAttribute => + s_typeOfEnumMemberAttribute ??= typeof(EnumMemberAttribute); + + private static Type? s_typeOfCollectionDataContractAttribute; + internal static Type TypeOfCollectionDataContractAttribute => + s_typeOfCollectionDataContractAttribute ??= typeof(CollectionDataContractAttribute); + + private static Type? s_typeOfOptionalFieldAttribute; + internal static Type TypeOfOptionalFieldAttribute => + s_typeOfOptionalFieldAttribute ??= typeof(OptionalFieldAttribute); + + private static Type? s_typeOfObjectArray; + internal static Type TypeOfObjectArray => + s_typeOfObjectArray ??= typeof(object[]); + + private static Type? s_typeOfOnSerializingAttribute; + internal static Type TypeOfOnSerializingAttribute => + s_typeOfOnSerializingAttribute ??= typeof(OnSerializingAttribute); + + private static Type? s_typeOfOnSerializedAttribute; + internal static Type TypeOfOnSerializedAttribute => + s_typeOfOnSerializedAttribute ??= typeof(OnSerializedAttribute); + + private static Type? s_typeOfOnDeserializingAttribute; + internal static Type TypeOfOnDeserializingAttribute => + s_typeOfOnDeserializingAttribute ??= typeof(OnDeserializingAttribute); + + private static Type? s_typeOfOnDeserializedAttribute; + internal static Type TypeOfOnDeserializedAttribute => + s_typeOfOnDeserializedAttribute ??= typeof(OnDeserializedAttribute); + + private static Type? s_typeOfFlagsAttribute; + internal static Type TypeOfFlagsAttribute => + s_typeOfFlagsAttribute ??= typeof(FlagsAttribute); + + private static Type? s_typeOfIXmlSerializable; + internal static Type TypeOfIXmlSerializable => + s_typeOfIXmlSerializable ??= typeof(IXmlSerializable); + + private static Type? s_typeOfXmlSchemaProviderAttribute; + internal static Type TypeOfXmlSchemaProviderAttribute => + s_typeOfXmlSchemaProviderAttribute ??= typeof(XmlSchemaProviderAttribute); + + private static Type? s_typeOfXmlRootAttribute; + internal static Type TypeOfXmlRootAttribute => + s_typeOfXmlRootAttribute ??= typeof(XmlRootAttribute); + + private static Type? s_typeOfXmlQualifiedName; + internal static Type TypeOfXmlQualifiedName => + s_typeOfXmlQualifiedName ??= typeof(XmlQualifiedName); + + private static Type? s_typeOfXmlSchemaType; + internal static Type TypeOfXmlSchemaType => + s_typeOfXmlSchemaType ??= typeof(XmlSchemaType); + + private static Type? s_typeOfIExtensibleDataObject; + internal static Type TypeOfIExtensibleDataObject => + s_typeOfIExtensibleDataObject ??= typeof(IExtensibleDataObject); + + private static Type? s_typeOfExtensionDataObject; + internal static Type TypeOfExtensionDataObject => + s_typeOfExtensionDataObject ??= typeof(ExtensionDataObject); + + private static Type? s_typeOfISerializableDataNode; + internal static Type TypeOfISerializableDataNode => + s_typeOfISerializableDataNode ??= typeof(ISerializableDataNode); + + private static Type? s_typeOfClassDataNode; + internal static Type TypeOfClassDataNode => + s_typeOfClassDataNode ??= typeof(ClassDataNode); + + private static Type? s_typeOfCollectionDataNode; + internal static Type TypeOfCollectionDataNode => + s_typeOfCollectionDataNode ??= typeof(CollectionDataNode); + + private static Type? s_typeOfXmlDataNode; + internal static Type TypeOfXmlDataNode => + s_typeOfXmlDataNode ??= typeof(XmlDataNode); + + private static Type? s_typeOfNullable; + internal static Type TypeOfNullable => + s_typeOfNullable ??= typeof(Nullable<>); + + private static Type? s_typeOfReflectionPointer; + internal static Type TypeOfReflectionPointer => + s_typeOfReflectionPointer ??= typeof(System.Reflection.Pointer); + + private static Type? s_typeOfIDictionaryGeneric; + internal static Type TypeOfIDictionaryGeneric => + s_typeOfIDictionaryGeneric ??= typeof(IDictionary<,>); + + private static Type? s_typeOfIDictionary; + internal static Type TypeOfIDictionary => + s_typeOfIDictionary ??= typeof(IDictionary); + + private static Type? s_typeOfIListGeneric; + internal static Type TypeOfIListGeneric => + s_typeOfIListGeneric ??= typeof(IList<>); + + private static Type? s_typeOfIList; + internal static Type TypeOfIList => + s_typeOfIList ??= typeof(IList); + + private static Type? s_typeOfICollectionGeneric; + internal static Type TypeOfICollectionGeneric => + s_typeOfICollectionGeneric ??= typeof(ICollection<>); + + private static Type? s_typeOfICollection; + internal static Type TypeOfICollection => + s_typeOfICollection ??= typeof(ICollection); + + private static Type? s_typeOfIEnumerableGeneric; + internal static Type TypeOfIEnumerableGeneric => + s_typeOfIEnumerableGeneric ??= typeof(IEnumerable<>); + + private static Type? s_typeOfIEnumerable; + internal static Type TypeOfIEnumerable => + s_typeOfIEnumerable ??= typeof(IEnumerable); + + private static Type? s_typeOfIEnumeratorGeneric; + internal static Type TypeOfIEnumeratorGeneric => + s_typeOfIEnumeratorGeneric ??= typeof(IEnumerator<>); + + private static Type? s_typeOfIEnumerator; + internal static Type TypeOfIEnumerator => + s_typeOfIEnumerator ??= typeof(IEnumerator); + + private static Type? s_typeOfKeyValuePair; + internal static Type TypeOfKeyValuePair => + s_typeOfKeyValuePair ??= typeof(KeyValuePair<,>); + + private static Type? s_typeOfKeyValue; + internal static Type TypeOfKeyValue => + s_typeOfKeyValue ??= typeof(KeyValue<,>); + + private static Type? s_typeOfIDictionaryEnumerator; + internal static Type TypeOfIDictionaryEnumerator => + s_typeOfIDictionaryEnumerator ??= typeof(IDictionaryEnumerator); + + private static Type? s_typeOfDictionaryEnumerator; + internal static Type TypeOfDictionaryEnumerator => + s_typeOfDictionaryEnumerator ??= typeof(CollectionDataContract.DictionaryEnumerator); + + private static Type? s_typeOfGenericDictionaryEnumerator; + internal static Type TypeOfGenericDictionaryEnumerator => + s_typeOfGenericDictionaryEnumerator ??= typeof(CollectionDataContract.GenericDictionaryEnumerator<,>); + + private static Type? s_typeOfDictionaryGeneric; + internal static Type TypeOfDictionaryGeneric => + s_typeOfDictionaryGeneric ??= typeof(Dictionary<,>); + + private static Type? s_typeOfHashtable; + internal static Type TypeOfHashtable + { + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + get => s_typeOfHashtable ??= TypeOfDictionaryGeneric.MakeGenericType(TypeOfObject, TypeOfObject); + } + + private static Type? s_typeOfXmlElement; + internal static Type TypeOfXmlElement => + s_typeOfXmlElement ??= typeof(XmlElement); + + private static Type? s_typeOfXmlNodeArray; + internal static Type TypeOfXmlNodeArray => + s_typeOfXmlNodeArray ??= typeof(XmlNode[]); + + private static Type? s_typeOfDBNull; + internal static Type TypeOfDBNull => + s_typeOfDBNull ??= typeof(DBNull); + + private static Uri? s_dataContractXsdBaseNamespaceUri; + internal static Uri DataContractXsdBaseNamespaceUri => + s_dataContractXsdBaseNamespaceUri ??= new Uri(DataContractXsdBaseNamespace); + + public const bool DefaultIsRequired = false; + public const bool DefaultEmitDefaultValue = true; + public const int DefaultOrder = 0; + public const bool DefaultIsReference = false; + // The value string.Empty aids comparisons (can do simple length checks + // instead of string comparison method calls in IL.) + public static readonly string NewObjectId = string.Empty; + public const string NullObjectId = null; + public const string FullSRSInternalsVisiblePattern = @"^[\s]*System\.Runtime\.Serialization[\s]*,[\s]*PublicKey[\s]*=[\s]*(?i:00240000048000009400000006020000002400005253413100040000010001008d56c76f9e8649383049f383c44be0ec204181822a6c31cf5eb7ef486944d032188ea1d3920763712ccb12d75fb77e9811149e6148e5d32fbaab37611c1878ddc19e20ef135d0cb2cff2bfec3d115810c3d9069638fe4be215dbf795861920e5ab6f7db2e2ceef136ac23d5dd2bf031700aec232f6c6b1c785b4305c123b37ab)[\s]*$"; + [RegexGenerator(FullSRSInternalsVisiblePattern)] + public static partial Regex FullSRSInternalsVisibleRegex(); + public const char SpaceChar = ' '; + public const char OpenBracketChar = '['; + public const char CloseBracketChar = ']'; + public const char CommaChar = ','; + public const string Space = " "; + public const string XsiPrefix = "i"; + public const string XsdPrefix = "x"; + public const string SerPrefix = "z"; + public const string SerPrefixForSchema = "ser"; + public const string ElementPrefix = "q"; + public const string DataContractXsdBaseNamespace = "http://schemas.datacontract.org/2004/07/"; + public const string DataContractXmlNamespace = DataContractXsdBaseNamespace + "System.Xml"; + public const string SchemaInstanceNamespace = "http://www.w3.org/2001/XMLSchema-instance"; + public const string SchemaNamespace = "http://www.w3.org/2001/XMLSchema"; + public const string XsiNilLocalName = "nil"; + public const string XsiTypeLocalName = "type"; + public const string TnsPrefix = "tns"; + public const string OccursUnbounded = "unbounded"; + public const string AnyTypeLocalName = "anyType"; + public const string StringLocalName = "string"; + public const string IntLocalName = "int"; + public const string True = "true"; + public const string False = "false"; + public const string ArrayPrefix = "ArrayOf"; + public const string XmlnsNamespace = "http://www.w3.org/2000/xmlns/"; + public const string XmlnsPrefix = "xmlns"; + public const string SchemaLocalName = "schema"; + public const string CollectionsNamespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays"; + public const string DefaultClrNamespace = "GeneratedNamespace"; + public const string DefaultTypeName = "GeneratedType"; + public const string DefaultGeneratedMember = "GeneratedMember"; + public const string DefaultFieldSuffix = "Field"; + public const string DefaultPropertySuffix = "Property"; + public const string DefaultMemberSuffix = "Member"; + public const string NameProperty = "Name"; + public const string NamespaceProperty = "Namespace"; + public const string OrderProperty = "Order"; + public const string IsReferenceProperty = "IsReference"; + public const string IsRequiredProperty = "IsRequired"; + public const string EmitDefaultValueProperty = "EmitDefaultValue"; + public const string ClrNamespaceProperty = "ClrNamespace"; + public const string ItemNameProperty = "ItemName"; + public const string KeyNameProperty = "KeyName"; + public const string ValueNameProperty = "ValueName"; + public const string SerializationInfoPropertyName = "SerializationInfo"; + public const string SerializationInfoFieldName = "info"; + public const string NodeArrayPropertyName = "Nodes"; + public const string NodeArrayFieldName = "nodesField"; + public const string ExportSchemaMethod = "ExportSchema"; + public const string IsAnyProperty = "IsAny"; + public const string ContextFieldName = "context"; + public const string GetObjectDataMethodName = "GetObjectData"; + public const string GetEnumeratorMethodName = "GetEnumerator"; + public const string MoveNextMethodName = "MoveNext"; + public const string AddValueMethodName = "AddValue"; + public const string CurrentPropertyName = "Current"; + public const string ValueProperty = "Value"; + public const string EnumeratorFieldName = "enumerator"; + public const string SerializationEntryFieldName = "entry"; + public const string ExtensionDataSetMethod = "set_ExtensionData"; + public const string ExtensionDataSetExplicitMethod = "System.Runtime.Serialization.IExtensibleDataObject.set_ExtensionData"; + public const string ExtensionDataObjectPropertyName = "ExtensionData"; + public const string ExtensionDataObjectFieldName = "extensionDataField"; + public const string AddMethodName = "Add"; + public const string GetCurrentMethodName = "get_Current"; + // NOTE: These values are used in schema below. If you modify any value, please make the same change in the schema. + public const string SerializationNamespace = "http://schemas.microsoft.com/2003/10/Serialization/"; + public const string ClrTypeLocalName = "Type"; + public const string ClrAssemblyLocalName = "Assembly"; + public const string IsValueTypeLocalName = "IsValueType"; + public const string EnumerationValueLocalName = "EnumerationValue"; + public const string SurrogateDataLocalName = "Surrogate"; + public const string GenericTypeLocalName = "GenericType"; + public const string GenericParameterLocalName = "GenericParameter"; + public const string GenericNameAttribute = "Name"; + public const string GenericNamespaceAttribute = "Namespace"; + public const string GenericParameterNestedLevelAttribute = "NestedLevel"; + public const string IsDictionaryLocalName = "IsDictionary"; + public const string ActualTypeLocalName = "ActualType"; + public const string ActualTypeNameAttribute = "Name"; + public const string ActualTypeNamespaceAttribute = "Namespace"; + public const string DefaultValueLocalName = "DefaultValue"; + public const string EmitDefaultValueAttribute = "EmitDefaultValue"; + public const string IdLocalName = "Id"; + public const string RefLocalName = "Ref"; + public const string ArraySizeLocalName = "Size"; + public const string KeyLocalName = "Key"; + public const string ValueLocalName = "Value"; + public const string MscorlibAssemblyName = "0"; + public const string ParseMethodName = "Parse"; + public const string SafeSerializationManagerName = "SafeSerializationManager"; + public const string SafeSerializationManagerNamespace = "http://schemas.datacontract.org/2004/07/System.Runtime.Serialization"; + public const string ISerializableFactoryTypeLocalName = "FactoryType"; + public const string SerializationSchema = @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +"; + +#endif + } +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ImportOptions.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ImportOptions.cs new file mode 100644 index 0000000000000..706c9fd3efeaa --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ImportOptions.cs @@ -0,0 +1,38 @@ +// 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.CodeDom; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace System.Runtime.Serialization.Schema +{ + public class ImportOptions + { + private ICollection? _referencedTypes; + private ICollection? _referencedCollectionTypes; + private IDictionary? _namespaces; + + public CodeDomProvider? CodeProvider { get; set; } + + public bool EnableDataBinding { get; set; } + + public ISerializationExtendedSurrogateProvider? ExtendedSurrogateProvider { get; set; } + + public bool GenerateInternal { get; set; } + + public bool GenerateSerializable { get; set; } + + public bool ImportXmlType { get; set; } + + public IDictionary Namespaces => _namespaces ??= new Dictionary(); + + public ICollection ReferencedCollectionTypes => _referencedCollectionTypes ??= new List(); + + public ICollection ReferencedTypes => _referencedTypes ??= new List(); + + public Func? ProcessImportedType; + } +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaHelper.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaHelper.cs new file mode 100644 index 0000000000000..b5ad415321b2b --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaHelper.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Runtime.Serialization.Schema +{ + internal static class SchemaHelper + { + internal static string GetCollectionNamespace(string elementNs) + { + return IsBuiltInNamespace(elementNs) ? Globals.CollectionsNamespace : elementNs; + } + + internal static string GetDataContractNamespaceFromUri(string uriString) + { + return uriString.StartsWith(Globals.DataContractXsdBaseNamespace, StringComparison.Ordinal) ? uriString.Substring(Globals.DataContractXsdBaseNamespace.Length) : uriString; + } + + internal static string GetDefaultStableNamespace(Type type) + { + if (type.IsGenericParameter) + return "{ns}"; + return GetDefaultStableNamespace(type.Namespace); + } + + internal static string GetDefaultStableNamespace(string? clrNs) + { + if (clrNs == null) clrNs = string.Empty; + return new Uri(Globals.DataContractXsdBaseNamespaceUri, clrNs).AbsoluteUri; + } + + internal static bool IsBuiltInNamespace(string ns) + { + return (ns == Globals.SchemaNamespace || ns == Globals.SerializationNamespace); + } + } +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs new file mode 100644 index 0000000000000..fb07d8bc98286 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs @@ -0,0 +1,342 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Xml; +using System.Xml.Schema; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Reflection; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; + +using ExceptionUtil = System.Runtime.Serialization.Schema.DiagnosticUtility.ExceptionUtility; + +namespace System.Runtime.Serialization.Schema +{ + public class XsdDataContractExporter + { + private ExportOptions? _options; + private XmlSchemaSet? _schemas; + private DataContractSet? _dataContractSet; + + public XsdDataContractExporter() + { + } + + public XsdDataContractExporter(XmlSchemaSet? schemas) + { + this._schemas = schemas; + } + + public ExportOptions? Options + { + get { return _options; } + set { _options = value; } + } + + public XmlSchemaSet Schemas + { + get + { + XmlSchemaSet schemaSet = GetSchemaSet(); + // TODO smolloy - what to do. Looks like this particular method can live easily anywhere we want. But... + // the home of SchemaImporter is yet to be determined. If it lives externally here, then use it like this. + // If it lives internally... which is probably preferred if possible... then we will need to duplicate this + // method out here, or find a way to call into it over there. + DataContractSet.CompileSchemaSet(schemaSet); + return schemaSet; + } + } + + private XmlSchemaSet GetSchemaSet() + { + if (_schemas == null) + { + _schemas = new XmlSchemaSet(); + _schemas.XmlResolver = null; + } + return _schemas; + } + + private DataContractSet DataContractSet + { + get + { + if (_dataContractSet == null) + { + // TODO smolloy - This used to pass the surrogate to DCSet in 4.8. We can't do that here. We need to pair + // the two somehow. For now, just pass nulls and see where down the line we need to resurface the surrogate provider + // so we can best figure how to pair these. + // _dataContractSet = new DataContractSet(Options?.GetSurrogate(), null, null); + _dataContractSet = new DataContractSet(null, null, null); + } + return _dataContractSet; + } + } + + private static void EnsureTypeNotGeneric(Type type) + { + if (type.ContainsGenericParameters) + throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericTypeNotExportable, type))); + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + public void Export(ICollection assemblies) + { + ArgumentNullException.ThrowIfNull(assemblies); + + DataContractSet? oldValue = (_dataContractSet == null) ? null : new DataContractSet(_dataContractSet); + try + { + foreach (Assembly assembly in assemblies) + { + if (assembly == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentException(SR.Format(SR.CannotExportNullAssembly, nameof(assemblies)))); + + Type[] types = assembly.GetTypes(); + for (int j = 0; j < types.Length; j++) + CheckAndAddType(types[j]); + } + + Export(); + } + catch + { + _dataContractSet = oldValue; + throw; + } + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + public void Export(ICollection types) + { + ArgumentNullException.ThrowIfNull(types); + + DataContractSet? oldValue = (_dataContractSet == null) ? null : new DataContractSet(_dataContractSet); + try + { + foreach (Type type in types) + { + if (type == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentException(SR.Format(SR.CannotExportNullType, nameof(types)))); + AddType(type); + } + + Export(); + } + catch + { + _dataContractSet = oldValue; + throw; + } + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + public void Export(Type type) + { + ArgumentNullException.ThrowIfNull(type); + + DataContractSet? oldValue = (_dataContractSet == null) ? null : new DataContractSet(_dataContractSet); + try + { + AddType(type); + Export(); + } + catch + { + _dataContractSet = oldValue; + throw; + } + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + public XmlQualifiedName GetSchemaTypeName(Type type) + { + ArgumentNullException.ThrowIfNull(type); + + type = GetSurrogatedType(type); + DataContract dataContract = DataContract.GetDataContract(type); + EnsureTypeNotGeneric(dataContract.UnderlyingType); + XmlDataContract? xmlDataContract = dataContract as XmlDataContract; + if (xmlDataContract != null && xmlDataContract.IsAnonymous) + return XmlQualifiedName.Empty; + return dataContract.StableName; + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + public XmlSchemaType? GetSchemaType(Type type) + { + ArgumentNullException.ThrowIfNull(type); + + type = GetSurrogatedType(type); + DataContract dataContract = DataContract.GetDataContract(type); + EnsureTypeNotGeneric(dataContract.UnderlyingType); + XmlDataContract? xmlDataContract = dataContract as XmlDataContract; + if (xmlDataContract != null && xmlDataContract.IsAnonymous) + return dataContract.XsdType; + return null; + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + public XmlQualifiedName? GetRootElementName(Type type) + { + ArgumentNullException.ThrowIfNull(type); + + type = GetSurrogatedType(type); + DataContract dataContract = DataContract.GetDataContract(type); + EnsureTypeNotGeneric(dataContract.UnderlyingType); + //if (dataContract.HasRoot) + //{ + // return new XmlQualifiedName(dataContract.TopLevelElementName!.Value, dataContract.TopLevelElementNamespace!.Value); + //} + // TODO smolloy - the above is now done with the new API below. + if (dataContract.GetRootElementName(out XmlQualifiedName? root)) + { + return root; + } + else + { + return null; + } + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private Type GetSurrogatedType(Type type) + { + // TODO smolloy - This is the DCS surrogate, not the extended one. Hmmmmm... guess inheritence is still the way to go. + ISerializationSurrogateProvider? surrogate = Options?.SurrogateProvider; + if (surrogate != null) + type = DataContract.GetSurrogateType(surrogate, type); + return type; + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private void CheckAndAddType(Type type) + { + type = GetSurrogatedType(type); + if (!type.ContainsGenericParameters && DataContract.IsTypeSerializable(type)) + AddType(type); + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private void AddType(Type type) + { + DataContractSet.Add(type); + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private void Export() + { + AddKnownTypes(); + DataContractSet.ExportSchemaSet(GetSchemaSet()); + // TODO smolloy - done with the new API above. Keeps SchemaExporter internal. + //SchemaExporter schemaExporter = new SchemaExporter(GetSchemaSet(), DataContractSet); + //schemaExporter.Export(); + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + private void AddKnownTypes() + { + if (Options != null) + { + Collection knownTypes = Options.KnownTypes; + + if (knownTypes != null) + { + for (int i = 0; i < knownTypes.Count; i++) + { + Type type = knownTypes[i]; + if (type == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentException(SR.CannotExportNullKnownType)); + AddType(type); + } + } + } + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + public bool CanExport(ICollection assemblies) + { + ArgumentNullException.ThrowIfNull(assemblies); + + DataContractSet? oldValue = (_dataContractSet == null) ? null : new DataContractSet(_dataContractSet); + try + { + foreach (Assembly assembly in assemblies) + { + if (assembly == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentException(SR.Format(SR.CannotExportNullAssembly, nameof(assemblies)))); + + Type[] types = assembly.GetTypes(); + for (int j = 0; j < types.Length; j++) + CheckAndAddType(types[j]); + } + AddKnownTypes(); + return true; + } + catch (InvalidDataContractException) + { + _dataContractSet = oldValue; + return false; + } + catch + { + _dataContractSet = oldValue; + throw; + } + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + public bool CanExport(ICollection types) + { + ArgumentNullException.ThrowIfNull(types); + + DataContractSet? oldValue = (_dataContractSet == null) ? null : new DataContractSet(_dataContractSet); + try + { + foreach (Type type in types) + { + if (type == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentException(SR.Format(SR.CannotExportNullType, nameof(types)))); + AddType(type); + } + AddKnownTypes(); + return true; + } + catch (InvalidDataContractException) + { + _dataContractSet = oldValue; + return false; + } + catch + { + _dataContractSet = oldValue; + throw; + } + } + + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + public bool CanExport(Type type) + { + ArgumentNullException.ThrowIfNull(type); + + DataContractSet? oldValue = (_dataContractSet == null) ? null : new DataContractSet(_dataContractSet); + try + { + AddType(type); + AddKnownTypes(); + return true; + } + catch (InvalidDataContractException) + { + _dataContractSet = oldValue; + return false; + } + catch + { + _dataContractSet = oldValue; + throw; + } + } + } +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs new file mode 100644 index 0000000000000..c9dea9112dc5c --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs @@ -0,0 +1,309 @@ +// 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.CodeDom; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Xml; +using System.Xml.Schema; + +using ExceptionUtil = System.Runtime.Serialization.Schema.DiagnosticUtility.ExceptionUtility; + +namespace System.Runtime.Serialization.Schema +{ + public class XsdDataContractImporter + { + private CodeCompileUnit _codeCompileUnit = null!; // Not directly referenced. Always lazy initialized by property getter. + private DataContractSet? _dataContractSet; + + private static readonly XmlQualifiedName[] s_emptyTypeNameArray = Array.Empty(); + private static readonly XmlSchemaElement[] s_emptyElementArray = Array.Empty(); + private XmlQualifiedName[] _singleTypeNameArray = null!; // Not directly referenced. Always lazy initialized by property getter. + private XmlSchemaElement[] _singleElementArray = null!; // Not directly referenced. Always lazy initialized by property getter. + + public XsdDataContractImporter() + { + } + + public XsdDataContractImporter(CodeCompileUnit codeCompileUnit) + { + _codeCompileUnit = codeCompileUnit; + } + + public ImportOptions? Options { get; set; } + + public CodeCompileUnit CodeCompileUnit => _codeCompileUnit ??= new CodeCompileUnit(); + + private DataContractSet DataContractSet + { + get + { + if (_dataContractSet == null) + { + _dataContractSet = Options == null ? new DataContractSet(null, null, null) : + new DataContractSet(Options.ExtendedSurrogateProvider, Options.ReferencedTypes, Options.ReferencedCollectionTypes); + } + return _dataContractSet; + } + } + + [RequiresUnreferencedCode("Placeholder Warning")] + public void Import(XmlSchemaSet schemas) + { + if (schemas == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(schemas))); + + InternalImport(schemas, null, s_emptyElementArray, s_emptyTypeNameArray); + } + + [RequiresUnreferencedCode("Placeholder Warning")] + public void Import(XmlSchemaSet schemas, ICollection typeNames) + { + if (schemas == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(schemas))); + + if (typeNames == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(typeNames))); + + InternalImport(schemas, typeNames, s_emptyElementArray, s_emptyTypeNameArray); + } + + [RequiresUnreferencedCode("Placeholder Warning")] + public void Import(XmlSchemaSet schemas, XmlQualifiedName typeName) + { + if (schemas == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(schemas))); + + if (typeName == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(typeName))); + + SingleTypeNameArray[0] = typeName; + InternalImport(schemas, SingleTypeNameArray, s_emptyElementArray, s_emptyTypeNameArray); + } + + [RequiresUnreferencedCode("Placeholder Warning")] + public XmlQualifiedName? Import(XmlSchemaSet schemas, XmlSchemaElement element) + { + if (schemas == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(schemas))); + + if (element == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(element))); + + SingleElementArray[0] = element; + InternalImport(schemas, s_emptyTypeNameArray, SingleElementArray, SingleTypeNameArray /*filled on return*/); + return SingleTypeNameArray[0]; + } + + [RequiresUnreferencedCode("Placeholder Warning")] + public bool CanImport(XmlSchemaSet schemas) + { + if (schemas == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(schemas))); + + return InternalCanImport(schemas, null, s_emptyElementArray, s_emptyTypeNameArray); + } + + [RequiresUnreferencedCode("Placeholder Warning")] + public bool CanImport(XmlSchemaSet schemas, ICollection typeNames) + { + if (schemas == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(schemas))); + + if (typeNames == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(typeNames))); + + return InternalCanImport(schemas, typeNames, s_emptyElementArray, s_emptyTypeNameArray); + } + + [RequiresUnreferencedCode("Placeholder Warning")] + public bool CanImport(XmlSchemaSet schemas, XmlQualifiedName typeName) + { + if (schemas == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(schemas))); + + if (typeName == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(typeName))); + + return InternalCanImport(schemas, new XmlQualifiedName[] { typeName }, s_emptyElementArray, s_emptyTypeNameArray); + } + + [RequiresUnreferencedCode("Placeholder Warning")] + public bool CanImport(XmlSchemaSet schemas, XmlSchemaElement element) + { + if (schemas == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(schemas))); + + if (element == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(element))); + + SingleElementArray[0] = element; + return InternalCanImport(schemas, s_emptyTypeNameArray, SingleElementArray, SingleTypeNameArray); + } + + [RequiresUnreferencedCode("Placeholder Warning")] + public CodeTypeReference GetCodeTypeReference(XmlQualifiedName typeName) + { + DataContract dataContract = FindDataContract(typeName); + CodeExporter codeExporter = new CodeExporter(DataContractSet, Options, CodeCompileUnit); + return codeExporter.GetCodeTypeReference(dataContract); + } + + [RequiresUnreferencedCode("Placeholder Warning")] + public CodeTypeReference GetCodeTypeReference(XmlQualifiedName typeName, XmlSchemaElement element) + { + if (element == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(element))); + if (typeName == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(typeName))); + DataContract dataContract = FindDataContract(typeName); + CodeExporter codeExporter = new CodeExporter(DataContractSet, Options, CodeCompileUnit); + return codeExporter.GetElementTypeReference(dataContract, element.IsNillable); + } + + [RequiresUnreferencedCode("Placeholder Warning")] + internal DataContract FindDataContract(XmlQualifiedName typeName) + { + if (typeName == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(typeName))); + + DataContract? dataContract = DataContract.GetBuiltInDataContract(typeName.Name, typeName.Namespace); + if (dataContract == null) + { + dataContract = DataContractSet.GetDataContract(typeName); + if (dataContract == null) + throw ExceptionUtil.ThrowHelperError(new InvalidOperationException(SR.Format(SR.TypeHasNotBeenImported, typeName.Name, typeName.Namespace))); + } + return dataContract; + } + + [RequiresUnreferencedCode("Placeholder Warning")] + public ICollection? GetKnownTypeReferences(XmlQualifiedName typeName) + { + if (typeName == null) + throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(typeName))); + + DataContract? dataContract = DataContract.GetBuiltInDataContract(typeName.Name, typeName.Namespace); + if (dataContract == null) + { + dataContract = DataContractSet.GetDataContract(typeName); + if (dataContract == null) + throw ExceptionUtil.ThrowHelperError(new InvalidOperationException(SR.Format(SR.TypeHasNotBeenImported, typeName.Name, typeName.Namespace))); + } + + CodeExporter codeExporter = new CodeExporter(DataContractSet, Options, CodeCompileUnit); + return codeExporter.GetKnownTypeReferences(dataContract); + } + + private XmlQualifiedName[] SingleTypeNameArray + { + get + { + if (_singleTypeNameArray == null) + _singleTypeNameArray = new XmlQualifiedName[1]; + return _singleTypeNameArray; + } + } + + private XmlSchemaElement[] SingleElementArray + { + get + { + if (_singleElementArray == null) + _singleElementArray = new XmlSchemaElement[1]; + return _singleElementArray; + } + } + + [RequiresUnreferencedCode("Placeholder Warning")] + private void InternalImport(XmlSchemaSet schemas, ICollection? typeNames, ICollection elements, XmlQualifiedName[] elementTypeNames/*filled on return*/) + { + DataContractSet? oldValue = (_dataContractSet == null) ? null : new DataContractSet(_dataContractSet); + try + { + DataContractSet.ImportSchemaSet(schemas, typeNames, elements, elementTypeNames/*filled on return*/, ImportXmlDataType); + // TODO smolloy - The above used to be done as below... but to keep SchemaImporter internal it is now done as above. + //SchemaImporter schemaImporter = new SchemaImporter(schemas, typeNames, elements, elementTypeNames/*filled on return*/, DataContractSet, ImportXmlDataType); + //schemaImporter.Import(); + + CodeExporter codeExporter = new CodeExporter(DataContractSet, Options, CodeCompileUnit); + codeExporter.Export(); + } + catch + { + _dataContractSet = oldValue; + throw; + } + } + + private bool ImportXmlDataType + { + get + { + return Options == null ? false : Options.ImportXmlType; + } + } + + [RequiresUnreferencedCode("Placeholder Warning")] + private bool InternalCanImport(XmlSchemaSet schemas, ICollection? typeNames, ICollection elements, XmlQualifiedName[] elementTypeNames) + { + DataContractSet? oldValue = (_dataContractSet == null) ? null : new DataContractSet(_dataContractSet); + try + { + DataContractSet.ImportSchemaSet(schemas, typeNames, elements, elementTypeNames/*filled on return*/, ImportXmlDataType); + // TODO smolloy - The above used to be done as below... but to keep SchemaImporter internal it is now done as above. + //SchemaImporter schemaImporter = new SchemaImporter(schemas, typeNames, elements, elementTypeNames, DataContractSet, ImportXmlDataType); + //schemaImporter.Import(); + return true; + } + catch (ArgumentException) + { + _dataContractSet = oldValue; + return false; + } + catch + { + _dataContractSet = oldValue; + throw; + } + } + + private static XmlQualifiedName? s_actualTypeAnnotationName; + internal static XmlQualifiedName ActualTypeAnnotationName => s_actualTypeAnnotationName ??= new XmlQualifiedName(Globals.ActualTypeLocalName, Globals.SerializationNamespace); + + internal static XmlQualifiedName ImportActualType(XmlSchemaAnnotation? annotation, XmlQualifiedName defaultTypeName, XmlQualifiedName typeName) + { + XmlElement? actualTypeElement = ImportAnnotation(annotation, ActualTypeAnnotationName); + if (actualTypeElement == null) + return defaultTypeName; + + XmlNode? nameAttribute = actualTypeElement.Attributes.GetNamedItem(Globals.ActualTypeNameAttribute); + if (nameAttribute?.Value == null) + throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.AnnotationAttributeNotFound, ActualTypeAnnotationName.Name, typeName.Name, typeName.Namespace, Globals.ActualTypeNameAttribute))); + XmlNode? nsAttribute = actualTypeElement.Attributes.GetNamedItem(Globals.ActualTypeNamespaceAttribute); + if (nsAttribute?.Value == null) + throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.AnnotationAttributeNotFound, ActualTypeAnnotationName.Name, typeName.Name, typeName.Namespace, Globals.ActualTypeNamespaceAttribute))); + return new XmlQualifiedName(nameAttribute.Value, nsAttribute.Value); + } + + private static XmlElement? ImportAnnotation(XmlSchemaAnnotation? annotation, XmlQualifiedName annotationQualifiedName) + { + if (annotation != null && annotation.Items != null && annotation.Items.Count > 0 && annotation.Items[0] is XmlSchemaAppInfo) + { + XmlSchemaAppInfo appInfo = (XmlSchemaAppInfo)annotation.Items[0]; + XmlNode?[]? markup = appInfo.Markup; + if (markup != null) + { + for (int i = 0; i < markup.Length; i++) + { + XmlElement? annotationElement = markup[i] as XmlElement; + if (annotationElement != null && annotationElement.LocalName == annotationQualifiedName.Name && annotationElement.NamespaceURI == annotationQualifiedName.Namespace) + return annotationElement; + } + } + } + return null; + } + } +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/_Stubs.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/_Stubs.cs new file mode 100644 index 0000000000000..5d584ce6ee897 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/_Stubs.cs @@ -0,0 +1,167 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// TODO smolloy - stubs. remove once API is determined. + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Xml; +using System.Xml.Schema; + +using DataContractDictionary = System.Collections.Generic.Dictionary; + +namespace System.Runtime.Serialization +{ + public sealed class DataContractSet + { + // ======================================================================================================= + // These existed internal in Core + public DataContractSet(DataContractSet copySet) { } + public void Add(Type type) { } + public DataContract GetDataContract(Type type) { return new DataContract(); } + public IEnumerator> GetEnumerator() { return new Dictionary().GetEnumerator(); } + public Dictionary ProcessedContracts => new Dictionary(); + + + // ======================================================================================================= + // These existed internal in 4.8 and are brought back for schema support + public DataContractSet(object? a, object? b, object? c) { } + public DataContract? GetDataContract(XmlQualifiedName qname) { return null; } // Technically new. This was a this[] indexer in 4.8. + public DataContractDictionary? KnownTypesForObject { get; /*internal still OK for set, SchemaImporter.cs is the only writer.*/ } + + + // ======================================================================================================= + // These are new API's, internal or otherwise. All of them are simple wrappers or a gateway to an existing internal method + // on an internal type, except for the last. [GetReferencedTypeOnImport] + + // Forward to SchemaImporter.cs + public static void CompileSchemaSet(XmlSchemaSet schemaSet) { } + // Forward to SchemaExporter.cs + public void ExportSchemaSet(XmlSchemaSet schemaSet) { } + // Forward to SchemaImporter.cs + public void ImportSchemaSet(XmlSchemaSet schemaSet, ICollection? typeNames, ICollection elements, XmlQualifiedName[] elementTypeNames /*filled on return*/, bool importXmlDataType) { } + // Wrapper around a trio of internal methods of the same name with a dash of logic that was in but does not need to live in CodeExporter. + // Using this wrapper exposes one method instead of 3. + public bool TryGetReferencedType(XmlQualifiedName stableName, DataContract? dataContract, [NotNullWhen(true)] out Type? type) { type = null; return false; } + // Wrapper around GetSurrogateData - which is internal brought back for schema support. The wrapper allows us to keep knowledge/logic of + // surrogate providers internal to DataContractSet. + public bool TryGetSurrogateData(object key, out object? value) { value = null; return false; } + // This is new. Pushing surrogate functionality into DCSet so we don't have to manage surrogates externally. (Since ExtendedSurrogate is internal.) + public Type? GetReferencedTypeOnImport(DataContract dataContract) { return null; } // See the commented code in CodeExporter.cs for what this is supposed to do. + } + + public class DataMember + { + // ======================================================================================================= + // All were existing internal properties. + public bool EmitDefaultValue; + public bool IsNullable; + public bool IsRequired; + public DataContract MemberTypeContract = null!; // ** It isn't used externally, but MemberType kind of goes hand in logical hand here as well, no? + public string Name = string.Empty; + public int Order; + } + + public class GenericInfo + { + // ======================================================================================================= + // This entire class existed in 4.8 and was brought back for schema support. All API's here existed internal in 4.8. + public IList? Parameters => null; + public XmlQualifiedName StableName => XmlQualifiedName.Empty; // Can these stable names return null? + public XmlQualifiedName GetExpandedStableName() { return StableName; } + } + + public class DataContract + { + // ======================================================================================================= + // These existed internal in Core + public static bool IsTypeSerializable(Type type) { return false; } + public XmlQualifiedName StableName => XmlQualifiedName.Empty; + public Type UnderlyingType => typeof(DataContract); + public static DataContract GetDataContract(Type type) { return new DataContract(); } + public static DataContract? GetBuiltInDataContract(string name, string ns) { return null; } + // This API exists and is used internally. It can easily be copied externally if we want to reduce the API surface here. + // But it's also a semi-logical exposure of a DC-intended static utility function. It makes sense to just expose and re-use it. + public static string EncodeLocalName(string localName) { return "string"; } + + + // ======================================================================================================= + // These existed internal in 4.8 and are brought back for schema support + public GenericInfo? GenericInfo => null; + + + // ======================================================================================================= + // These are new API's, internal or otherwise. + + // This one - similar to a couple DCSet API's - allows us to keep surrogate execution logic internal to DC/DCSet. + // Basically and entry to [surrogate_caller.GetDataContractType()] + public static Type GetSurrogateType(ISerializationSurrogateProvider surrogateProvider, Type type) { return type; } + + // This is a new API that hides 'HasRoot', 'TopLevelElementName', and 'TopLevelElementNamespace' which already + // exist internally in Core. There are other places that use these properties though. Check those places to see + // if this new API works for them, or if it needs to be re-worked, or if we just stick with exposing those + // niche properties for niche cases. + // Upon further review, we don't even have to do a boolean/out pattern. We can just return + // something or null and our usage pattern here already flows like that. Maybe simplify this. + public bool GetRootElementName([NotNullWhen(true)] out XmlQualifiedName? rootElementName) { rootElementName = null; return false; } + + + // ======================================================================================================= + // More API's that need exposing + + // DataContract BindGenericParameters(DataContract[], Dictionary) + // XmlQualifiedName GetArrayTypeName(bool) + // XmlQualifiedName static GetStableName(Type t) {} + + // bool IsBuiltInDataContract + // bool IsValueType + // Type OriginalUnderlyingType + } + + + + public class ClassDataContract : DataContract + { + // BaseContract + // IsISerializable + // IsReference + // IsValueType + // KnownDataContracts + // Members + } + public class CollectionDataContract : DataContract + { + // IsCollection + // IsDictionary + // IsItemTypeNullable + // IsReference + // ItemContract + // ItemName + // KeyName + // ValueName + } + public class EnumDataContract : DataContract + { + // BaseContractName + // GetBaseType + // GetStringFromEnumValue + // IsFlags + // IsULong + // Members + // Values + } + public class PrimitiveDataContract : DataContract { } + public class XmlDataContract : DataContract + { + // IsAnonymous + // IsTopLevelElementNullable + // IsTypeDefinedOnImport + // IsValueType + // XsdType + + // These three are actually on DC itself. We worked around with a new API in one case. Can we use that for all cases? + // HasRoot + // TopLevelElementName + // TopLevelElementNamespace + } +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/System.Runtime.Serialization.Schema.Tests.csproj b/src/libraries/System.Runtime.Serialization.Schema/tests/System.Runtime.Serialization.Schema.Tests.csproj new file mode 100644 index 0000000000000..45b5bf3b22ee7 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/tests/System.Runtime.Serialization.Schema.Tests.csproj @@ -0,0 +1,12 @@ + + + true + $(NetCoreAppCurrent) + + + + + + + + diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Importer.cs b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Importer.cs new file mode 100644 index 0000000000000..13e424dce9a19 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Importer.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Xunit; + +namespace System.Runtime.Serialization.Schema.Tests +{ + public class ImporterTests + { + [Fact] + public void Hello() + { + Assert.True(true); + } + } +} diff --git a/src/libraries/oob.proj b/src/libraries/oob.proj index 74a8bfb3b1885..954a8671c0807 100644 --- a/src/libraries/oob.proj +++ b/src/libraries/oob.proj @@ -55,6 +55,7 @@ System.Composition.Runtime; System.Composition.TypedParts; System.Configuration.ConfigurationManager; + System.Runtime.Serialization.Schema; System.Speech; Microsoft.Extensions.DependencyInjection.Specification.Tests" /> diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index 7f747d1634c22..09230d8b3c15b 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -487,6 +487,7 @@ + From 6dfd3c46b52e5da17ad89555bae376a9be3adee1 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Wed, 6 Jul 2022 02:08:45 -0700 Subject: [PATCH 04/33] Added public APIs, but not the DataContract tree yet. --- ...m.Private.DataContractSerialization.csproj | 1 + .../Serialization/ClassDataContract.cs | 302 ++++++------- .../Runtime/Serialization/CodeGenerator.cs | 54 +-- .../Serialization/CollectionDataContract.cs | 270 ++++-------- .../Runtime/Serialization/DataContract.cs | 416 +++++++----------- .../Serialization/DataContractSerializer.cs | 29 +- .../Runtime/Serialization/DataContractSet.cs | 206 +++++---- .../Runtime/Serialization/DataMember.cs | 131 ++---- .../Serialization/DateTimeOffsetAdapter.cs | 2 +- .../Runtime/Serialization/EnumDataContract.cs | 78 ++-- .../Serialization/ExtensionDataReader.cs | 2 - .../GenericParameterDataContract.cs | 21 +- .../System/Runtime/Serialization/Globals.cs | 9 +- .../Json/ReflectionJsonFormatWriter.cs | 3 +- .../KnownTypeDataContractResolver.cs | 1 - .../Serialization/PrimitiveDataContract.cs | 251 +++++------ .../Runtime/Serialization/SchemaExporter.cs | 8 +- .../Runtime/Serialization/SchemaHelper.cs | 11 +- .../Runtime/Serialization/SchemaImporter.cs | 42 +- .../Serialization/SpecialTypeDataContract.cs | 2 +- .../Serialization/SurrogateDataContract.cs | 14 +- .../Runtime/Serialization/XmlDataContract.cs | 91 ++-- .../XmlObjectSerializerContext.cs | 2 +- .../Serialization/XmlReaderDelegator.cs | 18 +- .../Serialization/XmlSerializableReader.cs | 6 +- .../Serialization/XsdDataContractExporter.cs | 6 +- .../src/System/Xml/XmlDictionaryReader.cs | 12 +- .../src/System/Xml/XmlDictionaryWriter.cs | 3 +- .../src/System/Xml/XmlExceptionHelper.cs | 6 +- ...System.Runtime.Serialization.Schema.csproj | 5 - .../Serialization/Schema/CodeExporter.cs | 3 +- .../Runtime/Serialization/Schema/Globals.cs | 1 + .../Schema/XsdDataContractExporter.cs | 14 +- .../Runtime/Serialization/Schema/_Stubs.cs | 64 ++- .../ref/System.Runtime.Serialization.Xml.cs | 82 ++++ 35 files changed, 938 insertions(+), 1228 deletions(-) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj b/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj index 60e229ca44380..6b5246e7fa01c 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj +++ b/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj @@ -54,6 +54,7 @@ + diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs index 23122a250f330..36a0942744ab5 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs @@ -2,18 +2,15 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.IO; using System.Linq; using System.Reflection; -using System.Runtime.CompilerServices; using System.Security; using System.Threading; using System.Xml; + using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization @@ -30,14 +27,6 @@ internal sealed class ClassDataContract : DataContract private ClassDataContractCriticalHelper _helper; - internal const DynamicallyAccessedMemberTypes DataContractPreserveMemberTypes = - DynamicallyAccessedMemberTypes.PublicMethods | - DynamicallyAccessedMemberTypes.NonPublicMethods | - DynamicallyAccessedMemberTypes.PublicConstructors | - DynamicallyAccessedMemberTypes.NonPublicConstructors | - DynamicallyAccessedMemberTypes.PublicFields | - DynamicallyAccessedMemberTypes.PublicProperties; - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal ClassDataContract(Type type) : base(new ClassDataContractCriticalHelper(type)) { @@ -54,21 +43,21 @@ private ClassDataContract(Type type, XmlDictionaryString ns, string[] memberName private void InitClassDataContract() { _helper = (base.Helper as ClassDataContractCriticalHelper)!; - this.ContractNamespaces = _helper.ContractNamespaces; - this.MemberNames = _helper.MemberNames; - this.MemberNamespaces = _helper.MemberNamespaces; + ContractNamespaces = _helper.ContractNamespaces; + MemberNames = _helper.MemberNames; + MemberNamespaces = _helper.MemberNamespaces; } internal ClassDataContract? BaseContract { - get { return _helper.BaseContract; } - set { _helper.BaseContract = value; } + get => _helper.BaseContract; + set => _helper.BaseContract = value; } internal List? Members { - get { return _helper.Members; } - set { _helper.Members = value; } + get => _helper.Members; + set => _helper.Members = value; } public XmlDictionaryString?[]? ChildElementNamespaces @@ -96,61 +85,37 @@ public XmlDictionaryString?[]? ChildElementNamespaces } } - internal MethodInfo? OnSerializing - { - get { return _helper.OnSerializing; } - } + internal MethodInfo? OnSerializing => _helper.OnSerializing; - internal MethodInfo? OnSerialized - { - get { return _helper.OnSerialized; } - } + internal MethodInfo? OnSerialized => _helper.OnSerialized; - internal MethodInfo? OnDeserializing - { - get { return _helper.OnDeserializing; } - } + internal MethodInfo? OnDeserializing => _helper.OnDeserializing; - internal MethodInfo? OnDeserialized - { - get { return _helper.OnDeserialized; } - } + internal MethodInfo? OnDeserialized => _helper.OnDeserialized; - internal MethodInfo? ExtensionDataSetMethod - { - get { return _helper.ExtensionDataSetMethod; } - } + internal MethodInfo? ExtensionDataSetMethod => _helper.ExtensionDataSetMethod; internal override DataContractDictionary? KnownDataContracts { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - get { return _helper.KnownDataContracts; } - set { _helper.KnownDataContracts = value; } + get => _helper.KnownDataContracts; + set => _helper.KnownDataContracts = value; } - internal override bool IsISerializable + public override bool IsISerializable { - get { return _helper.IsISerializable; } - set { _helper.IsISerializable = value; } + get => _helper.IsISerializable; + internal set => _helper.IsISerializable = value; } - internal bool IsNonAttributedType - { - get { return _helper.IsNonAttributedType; } - } + internal bool IsNonAttributedType => _helper.IsNonAttributedType; - internal bool HasExtensionData - { - get { return _helper.HasExtensionData; } - } + internal bool HasExtensionData => _helper.HasExtensionData; - internal string? SerialiazationExceptionMessage { get { return _helper.SerializationExceptionMessage; } } - internal string? DeserializationExceptionMessage { get { return _helper.DeserializationExceptionMessage; } } + internal string? SerialiazationExceptionMessage => _helper.SerializationExceptionMessage; + internal string? DeserializationExceptionMessage => _helper.DeserializationExceptionMessage; - internal bool IsReadOnlyContract - { - get { return DeserializationExceptionMessage != null; } - } + internal bool IsReadOnlyContract => DeserializationExceptionMessage != null; internal ConstructorInfo? GetISerializableConstructor() { @@ -176,7 +141,7 @@ internal bool IsReadOnlyContract internal bool CreateNewInstanceViaDefaultConstructor([NotNullWhen(true)] out object? obj) { ConstructorInfo? ci = GetNonAttributedTypeConstructor(); - if (ci == null || UnderlyingType == Globals.TypeOfSchemaTypePlaceholder) + if (ci == null || UnderlyingType == Globals.TypeOfSchemaDefinedType) { obj = null; return false; @@ -198,7 +163,7 @@ internal bool CreateNewInstanceViaDefaultConstructor([NotNullWhen(true)] out obj [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private XmlFormatClassWriterDelegate CreateXmlFormatWriterDelegate() { - Debug.Assert(UnderlyingType != Globals.TypeOfSchemaTypePlaceholder); + Debug.Assert(UnderlyingType != Globals.TypeOfSchemaDefinedType); return new XmlFormatWriterGenerator().GenerateClassWriter(this); } @@ -226,7 +191,7 @@ internal XmlFormatClassWriterDelegate XmlFormatWriterDelegate [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private XmlFormatClassReaderDelegate CreateXmlFormatReaderDelegate() { - Debug.Assert(UnderlyingType != Globals.TypeOfSchemaTypePlaceholder); + Debug.Assert(UnderlyingType != Globals.TypeOfSchemaDefinedType); return new XmlFormatReaderGenerator().GenerateClassReader(this); } @@ -241,7 +206,7 @@ internal XmlFormatClassReaderDelegate XmlFormatReaderDelegate { if (_helper.XmlFormatReaderDelegate == null) { - if (this.IsReadOnlyContract) + if (IsReadOnlyContract) { ThrowInvalidDataContractException(DeserializationExceptionMessage, null /*type*/); } @@ -263,8 +228,7 @@ internal static ClassDataContract CreateClassDataContractForKeyValue(Type type, internal static void CheckAndAddMember(List members, DataMember memberContract, Dictionary memberNamesTable) { - DataMember? existingMemberContract; - if (memberNamesTable.TryGetValue(memberContract.Name, out existingMemberContract)) + if (memberNamesTable.TryGetValue(memberContract.Name, out DataMember? existingMemberContract)) { Type declaringType = memberContract.MemberInfo.DeclaringType!; DataContract.ThrowInvalidDataContractException( @@ -363,17 +327,17 @@ internal static bool IsNonAttributedTypeValidForSerialization( return null; XmlDictionaryString?[]? baseChildElementNamespaces = null; - if (this.BaseContract != null) - baseChildElementNamespaces = this.BaseContract.ChildElementNamespaces; + if (BaseContract != null) + baseChildElementNamespaces = BaseContract.ChildElementNamespaces; int baseChildElementNamespaceCount = (baseChildElementNamespaces != null) ? baseChildElementNamespaces.Length : 0; XmlDictionaryString?[] childElementNamespaces = new XmlDictionaryString?[Members.Count + baseChildElementNamespaceCount]; if (baseChildElementNamespaceCount > 0) Array.Copy(baseChildElementNamespaces!, childElementNamespaces, baseChildElementNamespaces!.Length); XmlDictionary dictionary = new XmlDictionary(); - for (int i = 0; i < this.Members.Count; i++) + for (int i = 0; i < Members.Count; i++) { - childElementNamespaces[i + baseChildElementNamespaceCount] = GetChildNamespaceToDeclare(this, this.Members[i].MemberType, dictionary); + childElementNamespaces[i + baseChildElementNamespaceCount] = GetChildNamespaceToDeclare(this, Members[i].MemberType, dictionary); } return childElementNamespaces; @@ -385,14 +349,14 @@ private void EnsureMethodsImported() } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext? context) { Debug.Assert(context != null); XmlFormatWriterDelegate(xmlWriter, obj, context, this); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext? context) { xmlReader.Read(); object? o = XmlFormatReaderDelegate(xmlReader, context, MemberNames, MemberNamespaces); @@ -420,7 +384,7 @@ internal bool RequiresMemberAccessForRead(SecurityException? securityException) } return true; } - if (this.BaseContract != null && this.BaseContract.RequiresMemberAccessForRead(securityException)) + if (BaseContract != null && BaseContract.RequiresMemberAccessForRead(securityException)) return true; if (ConstructorRequiresMemberAccess(GetISerializableConstructor())) @@ -449,7 +413,7 @@ internal bool RequiresMemberAccessForRead(SecurityException? securityException) return true; } - if (MethodRequiresMemberAccess(this.OnDeserializing)) + if (MethodRequiresMemberAccess(OnDeserializing)) { if (securityException != null) { @@ -457,13 +421,13 @@ internal bool RequiresMemberAccessForRead(SecurityException? securityException) new SecurityException(SR.Format( SR.PartialTrustDataContractOnDeserializingNotPublic, DataContract.GetClrTypeFullName(UnderlyingType), - this.OnDeserializing!.Name), + OnDeserializing!.Name), securityException)); } return true; } - if (MethodRequiresMemberAccess(this.OnDeserialized)) + if (MethodRequiresMemberAccess(OnDeserialized)) { if (securityException != null) { @@ -471,27 +435,27 @@ internal bool RequiresMemberAccessForRead(SecurityException? securityException) new SecurityException(SR.Format( SR.PartialTrustDataContractOnDeserializedNotPublic, DataContract.GetClrTypeFullName(UnderlyingType), - this.OnDeserialized!.Name), + OnDeserialized!.Name), securityException)); } return true; } - if (this.Members != null) + if (Members != null) { - for (int i = 0; i < this.Members.Count; i++) + for (int i = 0; i < Members.Count; i++) { - if (this.Members[i].RequiresMemberAccessForSet()) + if (Members[i].RequiresMemberAccessForSet()) { if (securityException != null) { - if (this.Members[i].MemberInfo is FieldInfo) + if (Members[i].MemberInfo is FieldInfo) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.Format( SR.PartialTrustDataContractFieldSetNotPublic, DataContract.GetClrTypeFullName(UnderlyingType), - this.Members[i].MemberInfo.Name), + Members[i].MemberInfo.Name), securityException)); } else @@ -500,7 +464,7 @@ internal bool RequiresMemberAccessForRead(SecurityException? securityException) new SecurityException(SR.Format( SR.PartialTrustDataContractPropertySetNotPublic, DataContract.GetClrTypeFullName(UnderlyingType), - this.Members[i].MemberInfo.Name), + Members[i].MemberInfo.Name), securityException)); } } @@ -534,24 +498,24 @@ internal bool RequiresMemberAccessForWrite(SecurityException? securityException) return true; } - if (this.BaseContract != null && this.BaseContract.RequiresMemberAccessForWrite(securityException)) + if (BaseContract != null && BaseContract.RequiresMemberAccessForWrite(securityException)) return true; - if (MethodRequiresMemberAccess(this.OnSerializing)) + if (MethodRequiresMemberAccess(OnSerializing)) { if (securityException != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.Format( SR.PartialTrustDataContractOnSerializingNotPublic, - DataContract.GetClrTypeFullName(this.UnderlyingType), - this.OnSerializing!.Name), + DataContract.GetClrTypeFullName(UnderlyingType), + OnSerializing!.Name), securityException)); } return true; } - if (MethodRequiresMemberAccess(this.OnSerialized)) + if (MethodRequiresMemberAccess(OnSerialized)) { if (securityException != null) { @@ -559,27 +523,27 @@ internal bool RequiresMemberAccessForWrite(SecurityException? securityException) new SecurityException(SR.Format( SR.PartialTrustDataContractOnSerializedNotPublic, DataContract.GetClrTypeFullName(UnderlyingType), - this.OnSerialized!.Name), + OnSerialized!.Name), securityException)); } return true; } - if (this.Members != null) + if (Members != null) { - for (int i = 0; i < this.Members.Count; i++) + for (int i = 0; i < Members.Count; i++) { - if (this.Members[i].RequiresMemberAccessForGet()) + if (Members[i].RequiresMemberAccessForGet()) { if (securityException != null) { - if (this.Members[i].MemberInfo is FieldInfo) + if (Members[i].MemberInfo is FieldInfo) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new SecurityException(SR.Format( SR.PartialTrustDataContractFieldGetNotPublic, DataContract.GetClrTypeFullName(UnderlyingType), - this.Members[i].MemberInfo.Name), + Members[i].MemberInfo.Name), securityException)); } else @@ -588,7 +552,7 @@ internal bool RequiresMemberAccessForWrite(SecurityException? securityException) new SecurityException(SR.Format( SR.PartialTrustDataContractPropertyGetNotPublic, DataContract.GetClrTypeFullName(UnderlyingType), - this.Members[i].MemberInfo.Name), + Members[i].MemberInfo.Name), securityException)); } } @@ -641,12 +605,12 @@ internal ClassDataContractCriticalHelper([DynamicallyAccessedMembers(DataContrac XmlQualifiedName stableName = GetStableNameAndSetHasDataContract(type); if (type == Globals.TypeOfDBNull) { - this.StableName = stableName; + StableName = stableName; _members = new List(); XmlDictionary dictionary = new XmlDictionary(2); - this.Name = dictionary.Add(StableName.Name); - this.Namespace = dictionary.Add(StableName.Namespace); - this.ContractNamespaces = this.MemberNames = this.MemberNamespaces = Array.Empty(); + Name = dictionary.Add(StableName.Name); + Namespace = dictionary.Add(StableName.Namespace); + ContractNamespaces = MemberNames = MemberNamespaces = Array.Empty(); EnsureMethodsImported(); return; } @@ -660,20 +624,20 @@ internal ClassDataContractCriticalHelper([DynamicallyAccessedMembers(DataContrac if (baseType != null && !(baseType.IsSerializable && Globals.TypeOfISerializable.IsAssignableFrom(baseType))) baseType = null; } - this.IsValueType = type.IsValueType; + IsValueType = type.IsValueType; if (baseType != null && baseType != Globals.TypeOfObject && baseType != Globals.TypeOfValueType && baseType != Globals.TypeOfUri) { DataContract baseContract = DataContract.GetDataContract(baseType); - if (baseContract is CollectionDataContract) + if (baseContract is CollectionDataContract collectionDC) { - this.BaseContract = ((CollectionDataContract)baseContract).SharedTypeContract as ClassDataContract; + BaseContract = collectionDC.SharedTypeContract as ClassDataContract; } else { - this.BaseContract = baseContract as ClassDataContract; + BaseContract = baseContract as ClassDataContract; } - if (this.BaseContract != null && this.BaseContract.IsNonAttributedType && !_isNonAttributedType) + if (BaseContract != null && BaseContract.IsNonAttributedType && !_isNonAttributedType) { throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError (new InvalidDataContractException(SR.Format(SR.AttributedTypesCannotInheritFromNonAttributedSerializableTypes, @@ -682,7 +646,7 @@ internal ClassDataContractCriticalHelper([DynamicallyAccessedMembers(DataContrac } else { - this.BaseContract = null; + BaseContract = null; } _hasExtensionData = (Globals.TypeOfIExtensibleDataObject.IsAssignableFrom(type)); @@ -697,7 +661,7 @@ internal ClassDataContractCriticalHelper([DynamicallyAccessedMembers(DataContrac } else { - this.StableName = stableName; + StableName = stableName; ImportDataMembers(); XmlDictionary dictionary = new XmlDictionary(2 + Members.Count); Name = dictionary.Add(StableName.Name); @@ -742,7 +706,7 @@ internal ClassDataContractCriticalHelper( [DynamicallyAccessedMembers(DataContractPreserveMemberTypes)] Type type, XmlDictionaryString ns, string[] memberNames) : base(type) { - this.StableName = new XmlQualifiedName(GetStableNameAndSetHasDataContract(type).Name, ns.Value); + StableName = new XmlQualifiedName(GetStableNameAndSetHasDataContract(type).Name, ns.Value); ImportDataMembers(); XmlDictionary dictionary = new XmlDictionary(1 + Members.Count); Name = dictionary.Add(StableName.Name); @@ -761,15 +725,14 @@ internal ClassDataContractCriticalHelper( private void EnsureIsReferenceImported(Type type) { - DataContractAttribute? dataContractAttribute; bool isReference = false; - bool hasDataContractAttribute = TryGetDCAttribute(type, out dataContractAttribute); + bool hasDataContractAttribute = TryGetDCAttribute(type, out DataContractAttribute? dataContractAttribute); if (BaseContract != null) { if (hasDataContractAttribute && dataContractAttribute!.IsReferenceSetExplicitly) { - bool baseIsReference = this.BaseContract.IsReference; + bool baseIsReference = BaseContract.IsReference; if ((baseIsReference && !dataContractAttribute.IsReference) || (!baseIsReference && dataContractAttribute.IsReference)) { @@ -777,8 +740,8 @@ private void EnsureIsReferenceImported(Type type) SR.Format(SR.InconsistentIsReference, DataContract.GetClrTypeFullName(type), dataContractAttribute.IsReference, - DataContract.GetClrTypeFullName(this.BaseContract.UnderlyingType), - this.BaseContract.IsReference), + DataContract.GetClrTypeFullName(BaseContract.UnderlyingType), + BaseContract.IsReference), type); } else @@ -788,7 +751,7 @@ private void EnsureIsReferenceImported(Type type) } else { - isReference = this.BaseContract.IsReference; + isReference = BaseContract.IsReference; } } else if (hasDataContractAttribute) @@ -808,7 +771,7 @@ private void EnsureIsReferenceImported(Type type) return; } - this.IsReference = isReference; + IsReference = isReference; } [MemberNotNull(nameof(_members))] @@ -816,7 +779,7 @@ private void EnsureIsReferenceImported(Type type) [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private void ImportDataMembers() { - Type type = this.UnderlyingType; + Type type = UnderlyingType; EnsureIsReferenceImported(type); List tempMembers = new List(); Dictionary memberNamesTable = new Dictionary(); @@ -881,7 +844,7 @@ private void ImportDataMembers() memberContract.Name = DataContract.EncodeLocalName(memberContract.Name); memberContract.IsNullable = DataContract.IsTypeNullable(memberContract.MemberType); memberContract.IsRequired = memberAttribute.IsRequired; - if (memberAttribute.IsRequired && this.IsReference) + if (memberAttribute.IsRequired && IsReference) { ThrowInvalidDataContractException( SR.Format(SR.IsRequiredDataMemberOnIsReferenceDataContractType, @@ -949,7 +912,7 @@ private void ImportDataMembers() object[] optionalFields = field!.GetCustomAttributes(Globals.TypeOfOptionalFieldAttribute, false); if (optionalFields == null || optionalFields.Length == 0) { - if (this.IsReference) + if (IsReference) { ThrowInvalidDataContractException( SR.Format(SR.NonOptionalFieldMemberOnIsReferenceSerializableType, @@ -994,7 +957,7 @@ private void SetIfMembersHaveConflict(List members) List membersInHierarchy = new List(); foreach (DataMember member in members) { - membersInHierarchy.Add(new Member(member, this.StableName!.Namespace, baseTypeIndex)); + membersInHierarchy.Add(new Member(member, StableName!.Namespace, baseTypeIndex)); } ClassDataContract? currContract = BaseContract; while (currContract != null) @@ -1017,19 +980,19 @@ private void SetIfMembersHaveConflict(List members) int endIndex = i; bool hasConflictingType = false; while (endIndex < membersInHierarchy.Count - 1 - && string.CompareOrdinal(membersInHierarchy[endIndex].member.Name, membersInHierarchy[endIndex + 1].member.Name) == 0 - && string.CompareOrdinal(membersInHierarchy[endIndex].ns, membersInHierarchy[endIndex + 1].ns) == 0) + && string.CompareOrdinal(membersInHierarchy[endIndex]._member.Name, membersInHierarchy[endIndex + 1]._member.Name) == 0 + && string.CompareOrdinal(membersInHierarchy[endIndex]._ns, membersInHierarchy[endIndex + 1]._ns) == 0) { - membersInHierarchy[endIndex].member.ConflictingMember = membersInHierarchy[endIndex + 1].member; + membersInHierarchy[endIndex]._member.ConflictingMember = membersInHierarchy[endIndex + 1]._member; if (!hasConflictingType) { - if (membersInHierarchy[endIndex + 1].member.HasConflictingNameAndType) + if (membersInHierarchy[endIndex + 1]._member.HasConflictingNameAndType) { hasConflictingType = true; } else { - hasConflictingType = (membersInHierarchy[endIndex].member.MemberType != membersInHierarchy[endIndex + 1].member.MemberType); + hasConflictingType = (membersInHierarchy[endIndex]._member.MemberType != membersInHierarchy[endIndex + 1]._member.MemberType); } } endIndex++; @@ -1039,7 +1002,7 @@ private void SetIfMembersHaveConflict(List members) { for (int j = startIndex; j <= endIndex; j++) { - membersInHierarchy[j].member.HasConflictingNameAndType = true; + membersInHierarchy[j]._member.HasConflictingNameAndType = true; } } @@ -1080,7 +1043,7 @@ internal void EnsureMethodsImported() { if (!_isMethodChecked) { - Type type = this.UnderlyingType; + Type type = UnderlyingType; MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); for (int i = 0; i < methods.Length; i++) { @@ -1155,7 +1118,7 @@ private static bool IsValidCallback(MethodInfo method, ParameterInfo[] parameter internal ClassDataContract? BaseContract { - get { return _baseContract; } + get => _baseContract; set { _baseContract = value; @@ -1166,8 +1129,8 @@ internal ClassDataContract? BaseContract internal List? Members { - get { return _members; } - set { _members = value; } + get => _members; + set => _members = value; } internal MethodInfo? OnSerializing @@ -1235,7 +1198,7 @@ internal override DataContractDictionary? KnownDataContracts { if (!_isKnownTypeAttributeChecked) { - _knownDataContracts = DataContract.ImportKnownTypeAttributes(this.UnderlyingType); + _knownDataContracts = DataContract.ImportKnownTypeAttributes(UnderlyingType); Interlocked.MemoryBarrier(); _isKnownTypeAttributeChecked = true; } @@ -1247,36 +1210,21 @@ internal override DataContractDictionary? KnownDataContracts set { _knownDataContracts = value; } } - internal string? SerializationExceptionMessage - { - get { return _serializationExceptionMessage; } - } + internal string? SerializationExceptionMessage => _serializationExceptionMessage; - internal string? DeserializationExceptionMessage - { - get { return (_serializationExceptionMessage == null) ? null : SR.Format(SR.ReadOnlyClassDeserialization, _serializationExceptionMessage); } - } + internal string? DeserializationExceptionMessage => (_serializationExceptionMessage == null) ? null : SR.Format(SR.ReadOnlyClassDeserialization, _serializationExceptionMessage); internal override bool IsISerializable { - get { return _isISerializable; } - set { _isISerializable = value; } + get => _isISerializable; + set => _isISerializable = value; } - internal bool HasDataContract - { - get { return _hasDataContract; } - } + internal bool HasDataContract => _hasDataContract; - internal bool HasExtensionData - { - get { return _hasExtensionData; } - } + internal bool HasExtensionData => _hasExtensionData; - internal bool IsNonAttributedType - { - get { return _isNonAttributedType; } - } + internal bool IsNonAttributedType => _isNonAttributedType; internal ConstructorInfo? GetISerializableConstructor() { @@ -1292,7 +1240,7 @@ internal bool IsNonAttributedType internal ConstructorInfo? GetNonAttributedTypeConstructor() { - if (!this.IsNonAttributedType) + if (!IsNonAttributedType) return null; Type type = UnderlyingType; @@ -1309,20 +1257,20 @@ internal bool IsNonAttributedType internal XmlFormatClassWriterDelegate? XmlFormatWriterDelegate { - get { return _xmlFormatWriterDelegate; } - set { _xmlFormatWriterDelegate = value; } + get => _xmlFormatWriterDelegate; + set => _xmlFormatWriterDelegate = value; } internal XmlFormatClassReaderDelegate? XmlFormatReaderDelegate { - get { return _xmlFormatReaderDelegate; } - set { _xmlFormatReaderDelegate = value; } + get => _xmlFormatReaderDelegate; + set => _xmlFormatReaderDelegate = value; } public XmlDictionaryString?[]? ChildElementNamespaces { - get { return _childElementNamespaces; } - set { _childElementNamespaces = value; } + get => _childElementNamespaces; + set => _childElementNamespaces = value; } private static Type[] SerInfoCtorArgs => s_serInfoCtorArgs ??= new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }; @@ -1331,28 +1279,28 @@ internal struct Member { internal Member(DataMember member, string ns, int baseTypeIndex) { - this.member = member; - this.ns = ns; - this.baseTypeIndex = baseTypeIndex; + _member = member; + _ns = ns; + _baseTypeIndex = baseTypeIndex; } - internal DataMember member; - internal string ns; - internal int baseTypeIndex; + internal DataMember _member; + internal string _ns; + internal int _baseTypeIndex; } internal sealed class DataMemberConflictComparer : IComparer { public int Compare(Member x, Member y) { - int nsCompare = string.CompareOrdinal(x.ns, y.ns); + int nsCompare = string.CompareOrdinal(x._ns, y._ns); if (nsCompare != 0) return nsCompare; - int nameCompare = string.CompareOrdinal(x.member.Name, y.member.Name); + int nameCompare = string.CompareOrdinal(x._member.Name, y._member.Name); if (nameCompare != 0) return nameCompare; - return x.baseTypeIndex - y.baseTypeIndex; + return x._baseTypeIndex - y._baseTypeIndex; } internal static DataMemberConflictComparer Singleton = new DataMemberConflictComparer(); @@ -1360,7 +1308,7 @@ public int Compare(Member x, Member y) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) + public override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) { Type type = UnderlyingType; if (!type.IsGenericType || !type.ContainsGenericParameters) @@ -1368,8 +1316,7 @@ internal override DataContract BindGenericParameters(DataContract[] paramContrac lock (this) { - DataContract? boundContract; - if (boundContracts.TryGetValue(this, out boundContract)) + if (boundContracts.TryGetValue(this, out DataContract? boundContract)) return boundContract; XmlQualifiedName stableName; @@ -1377,12 +1324,12 @@ internal override DataContract BindGenericParameters(DataContract[] paramContrac Type boundType; if (type.IsGenericTypeDefinition) { - stableName = this.StableName; + stableName = StableName; genericParams = paramContracts; - // NOTE TODO smolloy - this type-binding ('boundType') stuff is new. We did not do this in NetFx. We used to use default constructors. But default - // constructors for DataContracts runs afoul of requiring an underlying type. Our web of nullable notations make it hard to get around. - // But it also allows us to feel good about using .UnderlyingType from matching parameter contracts. + // NOTE TODO smolloy - this type-binding ('boundType') stuff is new. We did not do this in NetFx. We used to use default constructors and let the + // underlying type get filled in later. But default constructors for DataContracts runs afoul of requiring an underlying type. Our web of nullable + // notations make it hard to get around. But it also allows us to feel good about using .UnderlyingType from matching parameter contracts. Type[] underlyingParamTypes = new Type[paramContracts.Length]; for (int i = 0; i < paramContracts.Length; i++) underlyingParamTypes[i] = paramContracts[i].UnderlyingType; @@ -1411,12 +1358,12 @@ internal override DataContract BindGenericParameters(DataContract[] paramContrac } ClassDataContract boundClassContract = new ClassDataContract(boundType); boundContracts.Add(this, boundClassContract); - boundClassContract.StableName = CreateQualifiedName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(stableName.Name), new GenericNameProvider(DataContract.GetClrTypeFullName(this.UnderlyingType), genericParams)), stableName.Namespace); + boundClassContract.StableName = CreateQualifiedName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(stableName.Name), new GenericNameProvider(DataContract.GetClrTypeFullName(UnderlyingType), genericParams)), stableName.Namespace); if (BaseContract != null) boundClassContract.BaseContract = (ClassDataContract)BaseContract.BindGenericParameters(paramContracts, boundContracts); - boundClassContract.IsISerializable = this.IsISerializable; - boundClassContract.IsValueType = this.IsValueType; - boundClassContract.IsReference = this.IsReference; + boundClassContract.IsISerializable = IsISerializable; + boundClassContract.IsValueType = IsValueType; + boundClassContract.IsReference = IsReference; if (Members != null) { boundClassContract.Members = new List(Members.Count); @@ -1474,8 +1421,7 @@ internal override bool Equals(object? other, HashSet checke for (int i = 0; i < dataContract.Members.Count; i++) { // check that all datamembers common to both datacontracts match - DataMember? dataMember; - if (membersDictionary.TryGetValue(dataContract.Members[i].Name, out dataMember)) + if (membersDictionary.TryGetValue(dataContract.Members[i].Name, out DataMember? dataMember)) { if (dataMember.Equals(dataContract.Members[i], checkedContracts)) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs index 466acca4b3bf0..9ea98fc9862d9 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs @@ -2,17 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections; using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; -using System.Xml; using System.Reflection; using System.Reflection.Emit; -using System.IO; -using System.Security; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.Serialization.Json; namespace System.Runtime.Serialization { @@ -176,15 +171,15 @@ internal MethodInfo CurrentMethod internal ArgBuilder GetArg(int index) { - return (ArgBuilder)_argList[index]; + return _argList[index]; } internal static Type GetVariableType(object var) { - if (var is ArgBuilder) - return ((ArgBuilder)var).ArgType; - else if (var is LocalBuilder) - return ((LocalBuilder)var).LocalType; + if (var is ArgBuilder argBuilder) + return argBuilder.ArgType; + else if (var is LocalBuilder localBuilder) + return localBuilder.LocalType; else return var.GetType(); } @@ -267,8 +262,7 @@ internal void InternalBreakFor(object userForState, OpCode branchInstruction) { foreach (object block in _blockStack) { - ForState? forState = block as ForState; - if (forState != null && (object)forState == userForState) + if (block == userForState && block is ForState forState) { if (!forState.RequiresEndLabel) { @@ -680,20 +674,20 @@ internal void Load(object? obj) { _ilGen.Emit(OpCodes.Ldnull); } - else if (obj is ArgBuilder) - Ldarg((ArgBuilder)obj); - else if (obj is LocalBuilder) - Ldloc((LocalBuilder)obj); + else if (obj is ArgBuilder argBuilder) + Ldarg(argBuilder); + else if (obj is LocalBuilder localBuilder) + Ldloc(localBuilder); else Ldc(obj); } internal void Store(object var) { - if (var is ArgBuilder) - Starg((ArgBuilder)var); - else if (var is LocalBuilder) - Stloc((LocalBuilder)var); + if (var is ArgBuilder argBuilder) + Starg(argBuilder); + else if (var is LocalBuilder localBuilder) + Stloc(localBuilder); else { DiagnosticUtility.DebugAssert("Data can only be stored into ArgBuilder or LocalBuilder."); @@ -711,10 +705,10 @@ internal void Dec(object var) internal void LoadAddress(object obj) { - if (obj is ArgBuilder) - LdargAddress((ArgBuilder)obj); - else if (obj is LocalBuilder) - LdlocAddress((LocalBuilder)obj); + if (obj is ArgBuilder argBuilder) + LdargAddress(argBuilder); + else if (obj is LocalBuilder localBuilder) + LdlocAddress(localBuilder); else Load(obj); } @@ -802,9 +796,9 @@ internal void Ldtoken(Type t) internal void Ldc(object o) { Type valueType = o.GetType(); - if (o is Type) + if (o is Type t) { - Ldtoken((Type)o); + Ldtoken(t); Call(GetTypeFromHandle); } else if (valueType.IsEnum) @@ -1338,8 +1332,8 @@ internal sealed class ArgBuilder internal Type ArgType; internal ArgBuilder(int index, Type argType) { - this.Index = index; - this.ArgType = argType; + Index = index; + ArgType = argType; } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs index 9210091ed38fa..4174e8a8c5db5 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs @@ -8,10 +8,10 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; -using System.Runtime.CompilerServices; using System.Security; using System.Threading; using System.Xml; + using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization @@ -37,27 +37,27 @@ internal KeyValue(K key, V value) [DataMember(IsRequired = true)] public K Key { - get { return _key; } - set { _key = value; } + get => _key; + set => _key = value; } [DataMember(IsRequired = true)] public V Value { - get { return _value; } - set { _value = value; } + get => _value; + set => _value = value; } object? IKeyValue.Key { - get { return _key; } - set { _key = (K)value!; } + get => _key; + set => _key = (K)value!; } object? IKeyValue.Value { - get { return _value; } - set { _value = (V)value!; } + get => _value; + set => _value = (V)value!; } } @@ -144,31 +144,16 @@ private void InitCollectionDataContract(DataContract? sharedTypeContract) _helper.SharedTypeContract = sharedTypeContract; } - private static Type[] KnownInterfaces - { - get - { return CollectionDataContractCriticalHelper.KnownInterfaces; } - } + private static Type[] KnownInterfaces => CollectionDataContractCriticalHelper.KnownInterfaces; - internal CollectionKind Kind - { - get - { return _helper.Kind; } - } + internal CollectionKind Kind => _helper.Kind; - internal Type ItemType - { - get - { return _helper.ItemType; } - } + internal Type ItemType => _helper.ItemType; public DataContract ItemContract { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - get - { - return _itemContract ?? _helper.ItemContract; - } + get => _itemContract ?? _helper.ItemContract; set { @@ -177,48 +162,29 @@ public DataContract ItemContract } } - internal DataContract? SharedTypeContract - { - get - { return _helper.SharedTypeContract; } - } + internal DataContract? SharedTypeContract => _helper.SharedTypeContract; internal string ItemName { - get - { return _helper.ItemName; } - - set - { _helper.ItemName = value; } + get => _helper.ItemName; + set => _helper.ItemName = value; } - public XmlDictionaryString CollectionItemName - { - get { return _collectionItemName; } - } + public XmlDictionaryString CollectionItemName => _collectionItemName; internal string? KeyName { - get - { return _helper.KeyName; } - - set - { _helper.KeyName = value; } + get => _helper.KeyName; + set => _helper.KeyName = value; } internal string? ValueName { - get - { return _helper.ValueName; } - - set - { _helper.ValueName = value; } + get => _helper.ValueName; + set => _helper.ValueName = value; } - internal bool IsDictionary - { - get { return KeyName != null; } - } + internal bool IsDictionary => KeyName != null; public XmlDictionaryString? ChildElementNamespace { @@ -247,72 +213,38 @@ public XmlDictionaryString? ChildElementNamespace internal bool IsItemTypeNullable { - get { return _helper.IsItemTypeNullable; } - set { _helper.IsItemTypeNullable = value; } + get => _helper.IsItemTypeNullable; + set => _helper.IsItemTypeNullable = value; } internal bool IsConstructorCheckRequired { - get - { return _helper.IsConstructorCheckRequired; } - - set - { _helper.IsConstructorCheckRequired = value; } + get => _helper.IsConstructorCheckRequired; + set => _helper.IsConstructorCheckRequired = value; } - internal MethodInfo? GetEnumeratorMethod - { - get - { return _helper.GetEnumeratorMethod; } - } + internal MethodInfo? GetEnumeratorMethod => _helper.GetEnumeratorMethod; - internal MethodInfo? AddMethod - { - get - { return _helper.AddMethod; } - } + internal MethodInfo? AddMethod => _helper.AddMethod; - internal ConstructorInfo? Constructor - { - get - { return _helper.Constructor; } - } + internal ConstructorInfo? Constructor => _helper.Constructor; internal override DataContractDictionary? KnownDataContracts { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - get - { return _helper.KnownDataContracts; } - - set - { _helper.KnownDataContracts = value; } + get => _helper.KnownDataContracts; + set => _helper.KnownDataContracts = value; } - internal string? InvalidCollectionInSharedContractMessage - { - get - { return _helper.InvalidCollectionInSharedContractMessage; } - } + internal string? InvalidCollectionInSharedContractMessage => _helper.InvalidCollectionInSharedContractMessage; - internal string? SerializationExceptionMessage - { - get { return _helper.SerializationExceptionMessage; } - } + internal string? SerializationExceptionMessage => _helper.SerializationExceptionMessage; - internal string? DeserializationExceptionMessage - { - get { return _helper.DeserializationExceptionMessage; } - } + internal string? DeserializationExceptionMessage => _helper.DeserializationExceptionMessage; - internal bool IsReadOnlyContract - { - get { return DeserializationExceptionMessage != null; } - } + internal bool IsReadOnlyContract => DeserializationExceptionMessage != null; - private bool ItemNameSetExplicit - { - get { return _helper.ItemNameSetExplicit; } - } + private bool ItemNameSetExplicit => _helper.ItemNameSetExplicit; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private XmlFormatCollectionWriterDelegate CreateXmlFormatWriterDelegate() @@ -525,8 +457,8 @@ private void Init(CollectionKind kind, Type? itemType, CollectionDataContractAtt } XmlDictionary dictionary = isDictionary ? new XmlDictionary(5) : new XmlDictionary(3); - this.Name = dictionary.Add(this.StableName.Name); - this.Namespace = dictionary.Add(this.StableName.Namespace); + Name = dictionary.Add(StableName.Name); + Namespace = dictionary.Add(StableName.Namespace); _itemName = itemName ?? DataContract.GetStableName(DataContract.UnwrapNullableType(itemType)).Name; _collectionItemName = dictionary.Add(_itemName); if (isDictionary) @@ -537,7 +469,7 @@ private void Init(CollectionKind kind, Type? itemType, CollectionDataContractAtt } if (collectionContractAttribute != null) { - this.IsReference = collectionContractAttribute.IsReference; + IsReference = collectionContractAttribute.IsReference; } } @@ -550,7 +482,7 @@ internal CollectionDataContractCriticalHelper( type = Globals.TypeOfObjectArray; if (type.GetArrayRank() > 1) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.SupportForMultidimensionalArraysNotPresent)); - this.StableName = DataContract.GetStableName(type); + StableName = DataContract.GetStableName(type); Init(CollectionKind.Array, type.GetElementType(), null); } @@ -560,7 +492,7 @@ internal CollectionDataContractCriticalHelper( Type type, CollectionKind kind) : base(type) { - StableName = DataContract.GetStableName(type); // TODO smolloy - Not sure how much sense this makes with a dummy type + StableName = DataContract.GetStableName(type); Init(kind, type.GetElementType(), null); } @@ -573,7 +505,7 @@ internal CollectionDataContractCriticalHelper( { if (type.GetArrayRank() > 1) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.SupportForMultidimensionalArraysNotPresent)); - this.StableName = CreateQualifiedName(Globals.ArrayPrefix + itemContract.StableName.Name, itemContract.StableName.Namespace); + StableName = CreateQualifiedName(Globals.ArrayPrefix + itemContract.StableName.Name, itemContract.StableName.Namespace); _itemContract = itemContract; Init(CollectionKind.Array, type.GetElementType(), null); } @@ -592,7 +524,7 @@ internal CollectionDataContractCriticalHelper( throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.CollectionMustHaveItemType, GetClrTypeFullName(type)))); CollectionDataContractAttribute? collectionContractAttribute; - this.StableName = DataContract.GetCollectionStableName(type, itemType, out collectionContractAttribute); + StableName = DataContract.GetCollectionStableName(type, itemType, out collectionContractAttribute); Init(kind, itemType, collectionContractAttribute); _getEnumeratorMethod = getEnumeratorMethod; @@ -633,15 +565,9 @@ internal CollectionDataContractCriticalHelper( _invalidCollectionInSharedContractMessage = invalidCollectionInSharedContractMessage; } - internal CollectionKind Kind - { - get { return _kind; } - } + internal CollectionKind Kind => _kind; - internal Type ItemType - { - get { return _itemType; } - } + internal Type ItemType => _itemType; internal DataContract ItemContract { @@ -679,37 +605,34 @@ internal DataContract ItemContract internal DataContract? SharedTypeContract { - get { return _sharedTypeContract; } - set { _sharedTypeContract = value; } + get => _sharedTypeContract; + set => _sharedTypeContract = value; } internal string ItemName { - get { return _itemName; } - set { _itemName = value; } + get => _itemName; + set => _itemName = value; } internal bool IsConstructorCheckRequired { - get { return _isConstructorCheckRequired; } - set { _isConstructorCheckRequired = value; } + get => _isConstructorCheckRequired; + set => _isConstructorCheckRequired = value; } - public XmlDictionaryString CollectionItemName - { - get { return _collectionItemName; } - } + public XmlDictionaryString CollectionItemName => _collectionItemName; internal string? KeyName { - get { return _keyName; } - set { _keyName = value; } + get => _keyName; + set => _keyName = value; } internal string? ValueName { - get { return _valueName; } - set { _valueName = value; } + get => _valueName; + set => _valueName = value; } internal bool IsDictionary => KeyName != null; @@ -720,14 +643,14 @@ internal string? ValueName public XmlDictionaryString? ChildElementNamespace { - get { return _childElementNamespace; } - set { _childElementNamespace = value; } + get => _childElementNamespace; + set => _childElementNamespace = value; } internal bool IsItemTypeNullable { - get { return _isItemTypeNullable; } - set { _isItemTypeNullable = value; } + get => _isItemTypeNullable; + set => _isItemTypeNullable = value; } internal MethodInfo? GetEnumeratorMethod => _getEnumeratorMethod; @@ -747,7 +670,7 @@ internal override DataContractDictionary? KnownDataContracts { if (!_isKnownTypeAttributeChecked) { - _knownDataContracts = DataContract.ImportKnownTypeAttributes(this.UnderlyingType); + _knownDataContracts = DataContract.ImportKnownTypeAttributes(UnderlyingType); Interlocked.MemoryBarrier(); _isKnownTypeAttributeChecked = true; } @@ -766,20 +689,20 @@ internal override DataContractDictionary? KnownDataContracts internal XmlFormatCollectionWriterDelegate? XmlFormatWriterDelegate { - get { return _xmlFormatWriterDelegate; } - set { _xmlFormatWriterDelegate = value; } + get => _xmlFormatWriterDelegate; + set => _xmlFormatWriterDelegate = value; } internal XmlFormatCollectionReaderDelegate? XmlFormatReaderDelegate { - get { return _xmlFormatReaderDelegate; } - set { _xmlFormatReaderDelegate = value; } + get => _xmlFormatReaderDelegate; + set => _xmlFormatReaderDelegate = value; } internal XmlFormatGetOnlyCollectionReaderDelegate? XmlFormatGetOnlyCollectionReaderDelegate { - get { return _xmlFormatGetOnlyCollectionReaderDelegate; } - set { _xmlFormatGetOnlyCollectionReaderDelegate = value; } + get => _xmlFormatGetOnlyCollectionReaderDelegate; + set => _xmlFormatGetOnlyCollectionReaderDelegate = value; } private delegate void IncrementCollectionCountDelegate(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context); @@ -807,13 +730,13 @@ internal void IncrementCollectionCount(XmlWriterDelegator xmlWriter, object obj, case CollectionKind.GenericCollection: case CollectionKind.GenericList: { - var buildIncrementCollectionCountDelegate = GetBuildIncrementCollectionCountGenericDelegate(ItemType); + MethodInfo? buildIncrementCollectionCountDelegate = GetBuildIncrementCollectionCountGenericDelegate(ItemType); _incrementCollectionCountDelegate = (IncrementCollectionCountDelegate)buildIncrementCollectionCountDelegate.Invoke(null, Array.Empty())!; } break; case CollectionKind.GenericDictionary: { - var buildIncrementCollectionCountDelegate = GetBuildIncrementCollectionCountGenericDelegate(typeof(KeyValuePair<,>).MakeGenericType(ItemType.GetGenericArguments())); + MethodInfo? buildIncrementCollectionCountDelegate = GetBuildIncrementCollectionCountGenericDelegate(typeof(KeyValuePair<,>).MakeGenericType(ItemType.GetGenericArguments())); _incrementCollectionCountDelegate = (IncrementCollectionCountDelegate)buildIncrementCollectionCountDelegate.Invoke(null, Array.Empty())!; } break; @@ -859,7 +782,7 @@ internal IEnumerator GetEnumeratorForCollection(object obj) { if (_createGenericDictionaryEnumeratorDelegate == null) { - var keyValueTypes = ItemType.GetGenericArguments(); + Type[]? keyValueTypes = ItemType.GetGenericArguments(); MethodInfo buildCreateGenericDictionaryEnumerator = GetBuildCreateGenericDictionaryEnumeratorGenericMethod(keyValueTypes); _createGenericDictionaryEnumeratorDelegate = (CreateGenericDictionaryEnumeratorDelegate)buildCreateGenericDictionaryEnumerator.Invoke(null, Array.Empty())!; } @@ -1295,7 +1218,7 @@ private static bool HandleIfInvalidCollection(Type type, bool tryCreate, bool ha private static void GetReadOnlyCollectionExceptionMessages(Type type, bool hasCollectionDataContract, string message, string? param, out string serializationExceptionMessage, out string deserializationExceptionMessage) { - serializationExceptionMessage = GetInvalidCollectionMessage(message, SR.Format(hasCollectionDataContract ? SR.InvalidCollectionDataContract : SR.InvalidCollectionType, GetClrTypeFullName(type)), param); + serializationExceptionMessage = GetInvalidCollectionMessage(message, SR.Format(hasCollectionDataContract ? SR.InvalidCollectionDataContract : SR.InvalidCollectionType, GetClrTypeFullName(type)), param); deserializationExceptionMessage = GetInvalidCollectionMessage(message, SR.Format(SR.ReadOnlyCollectionDeserialization, GetClrTypeFullName(type)), param); } @@ -1399,15 +1322,15 @@ private static bool IsKnownInterface(Type type) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) + public override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) { DataContract boundContract; if (boundContracts.TryGetValue(this, out boundContract!)) return boundContract; - // NOTE TODO smolloy - this type-binding ('boundType') stuff is new. We did not do this in NetFx. We used to use default constructors. But default - // constructors for DataContracts runs afoul of requiring an underlying type. Our web of nullable notations make it hard to get around. - // But it also allows us to feel good about using .UnderlyingType from matching parameter contracts. + // NOTE TODO smolloy - this type-binding ('boundType') stuff is new. We did not do this in NetFx. We used to use default constructors and let the + // underlying type get filled in later. But default constructors for DataContracts runs afoul of requiring an underlying type. Our web of nullable + // notations make it hard to get around. But it also allows us to feel good about using .UnderlyingType from matching parameter contracts. Type type = UnderlyingType; Type[] paramTypes = type.GetGenericArguments(); for (int i = 0; i < paramTypes.Length; i++) @@ -1419,19 +1342,19 @@ internal override DataContract BindGenericParameters(DataContract[] paramContrac CollectionDataContract boundCollectionContract = new CollectionDataContract(boundType); boundContracts.Add(this, boundCollectionContract); - boundCollectionContract.ItemContract = this.ItemContract.BindGenericParameters(paramContracts, boundContracts); + boundCollectionContract.ItemContract = ItemContract.BindGenericParameters(paramContracts, boundContracts); boundCollectionContract.IsItemTypeNullable = !boundCollectionContract.ItemContract.IsValueType; - boundCollectionContract.ItemName = ItemNameSetExplicit ? this.ItemName : boundCollectionContract.ItemContract.StableName.Name; - boundCollectionContract.KeyName = this.KeyName; - boundCollectionContract.ValueName = this.ValueName; - boundCollectionContract.StableName = CreateQualifiedName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(this.StableName.Name), new GenericNameProvider(DataContract.GetClrTypeFullName(this.UnderlyingType), paramContracts)), - IsCollectionDataContract(UnderlyingType) ? this.StableName.Namespace : DataContract.GetCollectionNamespace(boundCollectionContract.ItemContract.StableName.Namespace)); + boundCollectionContract.ItemName = ItemNameSetExplicit ? ItemName : boundCollectionContract.ItemContract.StableName.Name; + boundCollectionContract.KeyName = KeyName; + boundCollectionContract.ValueName = ValueName; + boundCollectionContract.StableName = CreateQualifiedName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(StableName.Name), new GenericNameProvider(DataContract.GetClrTypeFullName(UnderlyingType), paramContracts)), + IsCollectionDataContract(UnderlyingType) ? StableName.Namespace : DataContract.GetCollectionNamespace(boundCollectionContract.ItemContract.StableName.Namespace)); return boundCollectionContract; } internal override DataContract GetValidContract(bool verifyConstructor = false) { - if (verifyConstructor && this.IsConstructorCheckRequired) + if (verifyConstructor && IsConstructorCheckRequired) { CheckConstructor(); return this; @@ -1444,13 +1367,13 @@ internal override DataContract GetValidContract(bool verifyConstructor = false) private void CheckConstructor() { - if (this.Constructor == null) + if (Constructor == null) { - throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.CollectionTypeDoesNotHaveDefaultCtor, DataContract.GetClrTypeFullName(this.UnderlyingType)))); + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.CollectionTypeDoesNotHaveDefaultCtor, DataContract.GetClrTypeFullName(UnderlyingType)))); } else { - this.IsConstructorCheckRequired = false; + IsConstructorCheckRequired = false; } } @@ -1502,7 +1425,7 @@ internal bool RequiresMemberAccessForRead(SecurityException? securityException) } return true; } - if (MethodRequiresMemberAccess(this.AddMethod)) + if (MethodRequiresMemberAccess(AddMethod)) { if (securityException != null) { @@ -1510,7 +1433,7 @@ internal bool RequiresMemberAccessForRead(SecurityException? securityException) new SecurityException(SR.Format( SR.PartialTrustCollectionContractAddMethodNotPublic, DataContract.GetClrTypeFullName(UnderlyingType), - this.AddMethod!.Name), + AddMethod!.Name), securityException)); } return true; @@ -1577,7 +1500,7 @@ internal override bool Equals(object? other, HashSet checke public override int GetHashCode() => base.GetHashCode(); [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext? context) { Debug.Assert(context != null); @@ -1587,7 +1510,7 @@ public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, Xml } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext? context) { Debug.Assert(context != null); @@ -1626,15 +1549,9 @@ public bool MoveNext() return _enumerator.MoveNext(); } - public KeyValue Current - { - get { return new KeyValue(_enumerator.Key, _enumerator.Value); } - } + public KeyValue Current => new KeyValue(_enumerator.Key, _enumerator.Value); - object System.Collections.IEnumerator.Current - { - get { return Current; } - } + object System.Collections.IEnumerator.Current => Current; public void Reset() { @@ -1670,10 +1587,7 @@ public KeyValue Current } } - object System.Collections.IEnumerator.Current - { - get { return Current; } - } + object System.Collections.IEnumerator.Current => Current; public void Reset() { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs index 5f814135aa89b..a05ef3fd2a952 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs @@ -4,7 +4,6 @@ using System; using System.Buffers.Binary; using System.Collections; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -13,18 +12,25 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Text; -using System.Text.RegularExpressions; using System.Xml; -using System.Xml.Schema; + using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization { - internal abstract class DataContract + public abstract class DataContract { internal const string SerializerTrimmerWarning = "Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the " + "required types are preserved."; + internal const DynamicallyAccessedMemberTypes DataContractPreserveMemberTypes = + DynamicallyAccessedMemberTypes.PublicMethods | + DynamicallyAccessedMemberTypes.NonPublicMethods | + DynamicallyAccessedMemberTypes.PublicConstructors | + DynamicallyAccessedMemberTypes.NonPublicConstructors | + DynamicallyAccessedMemberTypes.PublicFields | + DynamicallyAccessedMemberTypes.PublicProperties; + private XmlDictionaryString _name; private XmlDictionaryString _ns; private readonly DataContractCriticalHelper _helper; @@ -36,13 +42,10 @@ internal DataContract(DataContractCriticalHelper helper) _ns = helper.Namespace; } - internal MethodInfo? ParseMethod - { - get { return _helper.ParseMethod; } - } + internal MethodInfo? ParseMethod => _helper.ParseMethod; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static DataContract GetDataContract(Type type) + public static DataContract GetDataContract(Type type) { return GetDataContract(type.TypeHandle, type); } @@ -102,7 +105,7 @@ internal static int GetId(RuntimeTypeHandle typeHandle) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public static DataContract? GetBuiltInDataContract(Type type) + internal static DataContract? GetBuiltInDataContract(Type type) { return DataContractCriticalHelper.GetBuiltInDataContract(type); } @@ -114,7 +117,7 @@ internal static int GetId(RuntimeTypeHandle typeHandle) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public static DataContract? GetBuiltInDataContract(string typeName) + internal static DataContract? GetBuiltInDataContract(string typeName) { return DataContractCriticalHelper.GetBuiltInDataContract(typeName); } @@ -129,164 +132,118 @@ internal static XmlDictionaryString GetClrTypeString(string key) return DataContractCriticalHelper.GetClrTypeString(key); } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + public static Type GetSurrogateType(ISerializationSurrogateProvider surrogateProvider, Type type) + { + if (surrogateProvider != null) + return DataContractSurrogateCaller.GetDataContractType(surrogateProvider, type); + + return type; + } + [DoesNotReturn] internal static void ThrowInvalidDataContractException(string? message, Type? type) { DataContractCriticalHelper.ThrowInvalidDataContractException(message, type); } - protected DataContractCriticalHelper Helper - { - get { return _helper; } - } + internal DataContractCriticalHelper Helper => _helper; [DynamicallyAccessedMembers(ClassDataContract.DataContractPreserveMemberTypes)] - internal Type UnderlyingType - { - get { return _helper.UnderlyingType; } - } + public virtual Type UnderlyingType => _helper.UnderlyingType; - internal Type OriginalUnderlyingType - { - get { return _helper.OriginalUnderlyingType; } - } + public virtual Type OriginalUnderlyingType => _helper.OriginalUnderlyingType; - internal virtual bool IsBuiltInDataContract - { - get { return _helper.IsBuiltInDataContract; } - } + public virtual bool IsBuiltInDataContract => _helper.IsBuiltInDataContract; - internal Type TypeForInitialization - { - get - { return _helper.TypeForInitialization; } - } + internal Type TypeForInitialization => _helper.TypeForInitialization; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public virtual void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext? context) + internal virtual void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext? context) { - throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.UnexpectedContractType, DataContract.GetClrTypeFullName(this.GetType()), DataContract.GetClrTypeFullName(UnderlyingType)))); + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.UnexpectedContractType, DataContract.GetClrTypeFullName(GetType()), DataContract.GetClrTypeFullName(UnderlyingType)))); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public virtual object? ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext? context) + internal virtual object? ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext? context) { - throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.UnexpectedContractType, DataContract.GetClrTypeFullName(this.GetType()), DataContract.GetClrTypeFullName(UnderlyingType)))); + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.UnexpectedContractType, DataContract.GetClrTypeFullName(GetType()), DataContract.GetClrTypeFullName(UnderlyingType)))); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public virtual void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) + internal virtual void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) { - throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.UnexpectedContractType, DataContract.GetClrTypeFullName(this.GetType()), DataContract.GetClrTypeFullName(UnderlyingType)))); + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.UnexpectedContractType, DataContract.GetClrTypeFullName(GetType()), DataContract.GetClrTypeFullName(UnderlyingType)))); } - public virtual object ReadXmlElement(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context) + internal virtual object ReadXmlElement(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context) { - throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.UnexpectedContractType, DataContract.GetClrTypeFullName(this.GetType()), DataContract.GetClrTypeFullName(UnderlyingType)))); + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.UnexpectedContractType, DataContract.GetClrTypeFullName(GetType()), DataContract.GetClrTypeFullName(UnderlyingType)))); } - internal bool IsValueType + public virtual bool IsValueType { - get - { return _helper.IsValueType; } - - set - { _helper.IsValueType = value; } + get => _helper.IsValueType; + internal set => _helper.IsValueType = value; } - internal bool IsReference + public virtual bool IsReference { - get - { return _helper.IsReference; } - - set - { _helper.IsReference = value; } + get => _helper.IsReference; + internal set => _helper.IsReference = value; } - internal XmlQualifiedName StableName + public virtual XmlQualifiedName StableName { - get - { return _helper.StableName; } - - set - { _helper.StableName = value; } + get => _helper.StableName; + internal set => _helper.StableName = value; } - internal GenericInfo? GenericInfo + public virtual GenericInfo? GenericInfo { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - get - { return _helper.GenericInfo; } - - set - { _helper.GenericInfo = value; } + get => _helper.GenericInfo; + internal set => _helper.GenericInfo = value; } internal virtual DataContractDictionary? KnownDataContracts { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - get - { return _helper.KnownDataContracts; } - - set - { _helper.KnownDataContracts = value; } + get => _helper.KnownDataContracts; + set => _helper.KnownDataContracts = value; } - internal virtual bool IsISerializable + public virtual bool IsISerializable { - get { return _helper.IsISerializable; } - - set { _helper.IsISerializable = value; } + get => _helper.IsISerializable; + internal set => _helper.IsISerializable = value; } - internal XmlDictionaryString Name - { - get - { return _name; } - } + internal XmlDictionaryString Name => _name; - internal virtual XmlDictionaryString Namespace - { - get - { return _ns; } - } + internal virtual XmlDictionaryString Namespace => _ns; - internal virtual bool HasRoot + public virtual bool HasRoot { - get - { return true; } - - set - { } + get => true; + internal set { } } - internal virtual XmlDictionaryString? TopLevelElementName + public virtual XmlDictionaryString? TopLevelElementName { - get - { return _helper.TopLevelElementName; } - - set - { _helper.TopLevelElementName = value; } + get => _helper.TopLevelElementName; + internal set => _helper.TopLevelElementName = value; } - internal virtual XmlDictionaryString? TopLevelElementNamespace + public virtual XmlDictionaryString? TopLevelElementNamespace { - get - { return _helper.TopLevelElementNamespace; } - - set - { _helper.TopLevelElementNamespace = value; } + get => _helper.TopLevelElementNamespace; + internal set => _helper.TopLevelElementNamespace = value; } - internal virtual bool CanContainReferences - { - get { return true; } - } + internal virtual bool CanContainReferences => true; - internal virtual bool IsPrimitive - { - get { return false; } - } + internal virtual bool IsPrimitive => false; internal virtual void WriteRootElement(XmlWriterDelegator writer, XmlDictionaryString name, XmlDictionaryString? ns) { @@ -297,7 +254,7 @@ internal virtual void WriteRootElement(XmlWriterDelegator writer, XmlDictionaryS } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal virtual DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) + public virtual DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) { return this; } @@ -597,7 +554,7 @@ private static RuntimeTypeHandle GetDataContractAdapterTypeHandle(RuntimeTypeHan } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public static DataContract? GetBuiltInDataContract(Type type) + internal static DataContract? GetBuiltInDataContract(Type type) { if (type.IsInterface && !CollectionDataContract.IsCollectionInterface(type)) type = Globals.TypeOfObject; @@ -606,8 +563,7 @@ private static RuntimeTypeHandle GetDataContractAdapterTypeHandle(RuntimeTypeHan { s_typeToBuiltInContract ??= new Dictionary(); - DataContract? dataContract; - if (!s_typeToBuiltInContract.TryGetValue(type, out dataContract)) + if (!s_typeToBuiltInContract.TryGetValue(type, out DataContract? dataContract)) { TryCreateBuiltInDataContract(type, out dataContract); s_typeToBuiltInContract.Add(type, dataContract); @@ -617,15 +573,14 @@ private static RuntimeTypeHandle GetDataContractAdapterTypeHandle(RuntimeTypeHan } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public static DataContract? GetBuiltInDataContract(string name, string ns) + internal static DataContract? GetBuiltInDataContract(string name, string ns) { lock (s_initBuiltInContractsLock) { s_nameToBuiltInContract ??= new Dictionary(); - DataContract? dataContract; XmlQualifiedName qname = new XmlQualifiedName(name, ns); - if (!s_nameToBuiltInContract.TryGetValue(qname, out dataContract)) + if (!s_nameToBuiltInContract.TryGetValue(qname, out DataContract? dataContract)) { if (TryCreateBuiltInDataContract(name, ns, out dataContract)) { @@ -637,7 +592,7 @@ private static RuntimeTypeHandle GetDataContractAdapterTypeHandle(RuntimeTypeHan } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public static DataContract? GetBuiltInDataContract(string typeName) + internal static DataContract? GetBuiltInDataContract(string typeName) { if (!typeName.StartsWith("System.", StringComparison.Ordinal)) return null; @@ -646,8 +601,7 @@ private static RuntimeTypeHandle GetDataContractAdapterTypeHandle(RuntimeTypeHan { s_typeNameToBuiltInContract ??= new Dictionary(); - DataContract? dataContract; - if (!s_typeNameToBuiltInContract.TryGetValue(typeName, out dataContract)) + if (!s_typeNameToBuiltInContract.TryGetValue(typeName, out DataContract? dataContract)) { Type? type = null; string name = typeName.Substring(7); @@ -714,7 +668,7 @@ private static RuntimeTypeHandle GetDataContractAdapterTypeHandle(RuntimeTypeHan } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public static bool TryCreateBuiltInDataContract(Type type, [NotNullWhen(true)] out DataContract? dataContract) + internal static bool TryCreateBuiltInDataContract(Type type, [NotNullWhen(true)] out DataContract? dataContract) { if (type.IsEnum) // Type.GetTypeCode will report Enums as TypeCode.IntXX { @@ -796,7 +750,7 @@ public static bool TryCreateBuiltInDataContract(Type type, [NotNullWhen(true)] o } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public static bool TryCreateBuiltInDataContract(string name, string ns, [NotNullWhen(true)] out DataContract? dataContract) + internal static bool TryCreateBuiltInDataContract(string name, string ns, [NotNullWhen(true)] out DataContract? dataContract) { dataContract = null; if (ns == DictionaryGlobals.SchemaNamespace.Value) @@ -961,8 +915,7 @@ internal static XmlDictionaryString GetClrTypeString(string key) throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(ex.Message, ex); } } - XmlDictionaryString? value; - if (s_clrTypeStrings.TryGetValue(key, out value)) + if (s_clrTypeStrings.TryGetValue(key, out XmlDictionaryString? value)) return value; value = s_clrTypeStringsDictionary!.Add(key); try @@ -1010,33 +963,18 @@ internal DataContractCriticalHelper( } [DynamicallyAccessedMembers(ClassDataContract.DataContractPreserveMemberTypes)] - internal Type UnderlyingType - { - get { return _underlyingType; } - } + internal Type UnderlyingType => _underlyingType; - internal Type OriginalUnderlyingType - { - get => _originalUnderlyingType ??= GetDataContractOriginalType(_underlyingType); - } + internal Type OriginalUnderlyingType => _originalUnderlyingType ??= GetDataContractOriginalType(_underlyingType); - internal virtual bool IsBuiltInDataContract - { - get - { - return false; - } - } + internal virtual bool IsBuiltInDataContract => false; - internal Type TypeForInitialization - { - get { return _typeForInitialization; } - } + internal Type TypeForInitialization => _typeForInitialization; [MemberNotNull(nameof(_typeForInitialization))] private void SetTypeForInitialization(Type classType) { - // NOTE TODO smolloy - This 'if' was not commented in 4.8. But 4.8 was not dealing with nullable notations, which we do have here in Core. + // NOTE TODO smolloy - This 'if' was not commented out in 4.8. But 4.8 was not dealing with nullable notations, which we do have here in Core. // With the absence of schema importing, it does not make sense to have a data contract without a valid serializable underlying type. (Even // with schema importing it doesn't make sense, but there is a building period while we're still figuring out all the data types and contracts // where the underlying type may be null.) Anyway... might it make sense to re-instate this if clause - but use it to throw an exception if @@ -1049,65 +987,62 @@ private void SetTypeForInitialization(Type classType) internal bool IsReference { - get { return _isReference; } - set - { - _isReference = value; - } + get => _isReference; + set => _isReference = value; } internal bool IsValueType { - get { return _isValueType; } - set { _isValueType = value; } + get => _isValueType; + set => _isValueType = value; } internal XmlQualifiedName StableName { - get { return _stableName; } - set { _stableName = value; } + get => _stableName; + set => _stableName = value; } internal GenericInfo? GenericInfo { - get { return _genericInfo; } - set { _genericInfo = value; } + get => _genericInfo; + set => _genericInfo = value; } internal virtual DataContractDictionary? KnownDataContracts { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - get { return null; } + get => null; set { /* do nothing */ } } internal virtual bool IsISerializable { - get { return false; } - set { ThrowInvalidDataContractException(SR.RequiresClassDataContractToSetIsISerializable); } + get => false; + set => ThrowInvalidDataContractException(SR.RequiresClassDataContractToSetIsISerializable); } internal XmlDictionaryString Name { - get { return _name; } - set { _name = value; } + get => _name; + set => _name = value; } - public XmlDictionaryString Namespace + internal XmlDictionaryString Namespace { - get { return _ns; } - set { _ns = value; } + get => _ns; + set => _ns = value; } internal virtual bool HasRoot { - get { return true; } + get => true; set { } } internal virtual XmlDictionaryString? TopLevelElementName { - get { return _name; } + get => _name; set { Debug.Assert(value != null); @@ -1117,7 +1052,7 @@ internal virtual XmlDictionaryString? TopLevelElementName internal virtual XmlDictionaryString? TopLevelElementNamespace { - get { return _ns; } + get => _ns; set { Debug.Assert(value != null); @@ -1125,15 +1060,9 @@ internal virtual XmlDictionaryString? TopLevelElementNamespace } } - internal virtual bool CanContainReferences - { - get { return true; } - } + internal virtual bool CanContainReferences => true; - internal virtual bool IsPrimitive - { - get { return false; } - } + internal virtual bool IsPrimitive => false; internal MethodInfo? ParseMethod { @@ -1157,16 +1086,16 @@ internal MethodInfo? ParseMethod internal void SetDataContractName(XmlQualifiedName stableName) { XmlDictionary dictionary = new XmlDictionary(2); - this.Name = dictionary.Add(stableName.Name); - this.Namespace = dictionary.Add(stableName.Namespace); - this.StableName = stableName; + Name = dictionary.Add(stableName.Name); + Namespace = dictionary.Add(stableName.Namespace); + StableName = stableName; } internal void SetDataContractName(XmlDictionaryString name, XmlDictionaryString ns) { - this.Name = name; - this.Namespace = ns; - this.StableName = CreateQualifiedName(name.Value, ns.Value); + Name = name; + Namespace = ns; + StableName = CreateQualifiedName(name.Value, ns.Value); } [DoesNotReturn] @@ -1177,7 +1106,7 @@ internal void ThrowInvalidDataContractException(string message) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static bool IsTypeSerializable(Type type) + public static bool IsTypeSerializable(Type type) { return IsTypeSerializable(type, new HashSet()); } @@ -1185,8 +1114,6 @@ internal static bool IsTypeSerializable(Type type) [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private static bool IsTypeSerializable(Type type, HashSet previousCollectionTypes) { - Type? itemType; - if (type.IsSerializable || type.IsEnum || type.IsDefined(Globals.TypeOfDataContractAttribute, false) || @@ -1198,7 +1125,7 @@ private static bool IsTypeSerializable(Type type, HashSet previousCollecti { return true; } - if (CollectionDataContract.IsCollection(type, out itemType)) + if (CollectionDataContract.IsCollection(type, out Type? itemType)) { ValidatePreviousCollectionTypes(type, itemType, previousCollectionTypes); if (IsTypeSerializable(itemType, previousCollectionTypes)) @@ -1281,7 +1208,7 @@ private static bool IsAsciiLocalName(string localName) return true; } - internal static string EncodeLocalName(string localName) + public static string EncodeLocalName(string localName) { if (IsAsciiLocalName(localName)) return localName; @@ -1306,7 +1233,7 @@ internal static bool IsValidNCName(string name) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static XmlQualifiedName GetStableName(Type type) + public static XmlQualifiedName GetStableName(Type type) { return GetStableName(type, out _); } @@ -1321,15 +1248,13 @@ internal static XmlQualifiedName GetStableName(Type type, out bool hasDataContra internal static XmlQualifiedName GetStableName(Type type, HashSet previousCollectionTypes, out bool hasDataContract) { type = UnwrapRedundantNullableType(type); - XmlQualifiedName? stableName; - if (TryGetBuiltInXmlAndArrayTypeStableName(type, previousCollectionTypes, out stableName)) + if (TryGetBuiltInXmlAndArrayTypeStableName(type, previousCollectionTypes, out XmlQualifiedName? stableName)) { hasDataContract = false; } else { - DataContractAttribute? dataContractAttribute; - if (TryGetDCAttribute(type, out dataContractAttribute)) + if (TryGetDCAttribute(type, out DataContractAttribute? dataContractAttribute)) { stableName = GetDCTypeStableName(type, dataContractAttribute); hasDataContract = true; @@ -1378,8 +1303,7 @@ private static XmlQualifiedName GetNonDCTypeStableName(Type type, HashSet { string? name, ns; - Type? itemType; - if (CollectionDataContract.IsCollection(type, out itemType)) + if (CollectionDataContract.IsCollection(type, out Type? itemType)) { ValidatePreviousCollectionTypes(type, itemType, previousCollectionTypes); return GetCollectionStableName(type, itemType, previousCollectionTypes, out _); @@ -1410,8 +1334,7 @@ private static bool TryGetBuiltInXmlAndArrayTypeStableName(Type type, HashSet nestedParamCounts = GetDataContractNameForGenericName(localName, localNameBuilder); foreach (CodeTypeReference typeArg in typeReference.TypeArguments) { - string typeArgName, typeArgNs; - GetDefaultStableName(typeArg, out typeArgName, out typeArgNs); + GetDefaultStableName(typeArg, out string typeArgName, out string typeArgNs); localNameBuilder.Append(typeArgName); argNamespacesBuilder.Append(' ').Append(typeArgNs); if (parametersFromBuiltInNamespaces) @@ -1734,8 +1656,7 @@ private static void CheckExplicitDataContractNamespaceUri(string dataContractNs, ThrowInvalidDataContractException(SR.Format(SR.DataContractNamespaceIsNotValid, dataContractNs), type); dataContractNs = trimmedNs; } - Uri? uri; - if (Uri.TryCreate(dataContractNs, UriKind.RelativeOrAbsolute, out uri)) + if (Uri.TryCreate(dataContractNs, UriKind.RelativeOrAbsolute, out Uri? uri)) { if (uri.ToString() == Globals.SerializationNamespace) ThrowInvalidDataContractException(SR.Format(SR.DataContractNamespaceReserved, Globals.SerializationNamespace), type); @@ -1981,8 +1902,7 @@ internal static string ExpandGenericParameters(string format, IGenericNameProvid } else { - int paramIndex; - if (!int.TryParse(format.AsSpan(start, i - start), out paramIndex) || paramIndex < 0 || paramIndex >= genericNameProvider.GetParameterCount()) + if (!int.TryParse(format.AsSpan(start, i - start), out int paramIndex) || paramIndex < 0 || paramIndex >= genericNameProvider.GetParameterCount()) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericParameterNotValid, format.Substring(start, i - start), genericNameProvider.GetGenericTypeName(), genericNameProvider.GetParameterCount() - 1))); typeName.Append(genericNameProvider.GetParameterName(paramIndex)); } @@ -2078,12 +1998,11 @@ private static void ImportKnownTypeAttributes(Type? type, Dictionary } } - // NOTE TODO smolloy - This try/catch block is new in CoreFx from the beginning. I wonder why it wasn't there in NetFx. Is it needed there? Or not-needed here? + // NOTE TODO smolloy - This entire try/catch block is new in CoreFx from the beginning. I wonder why it wasn't there in NetFx. Is it needed there? Or not-needed here? //For Json we need to add KeyValuePair to KnownTypes if the UnderLyingType is a Dictionary try { - CollectionDataContract? collectionDataContract = DataContract.GetDataContract(type) as CollectionDataContract; - if (collectionDataContract != null && collectionDataContract.IsDictionary && + if (DataContract.GetDataContract(type) is CollectionDataContract collectionDataContract && collectionDataContract.IsDictionary && collectionDataContract.ItemType.GetGenericTypeDefinition() == Globals.TypeOfKeyValue) { DataContract itemDataContract = DataContract.GetDataContract(Globals.TypeOfKeyValuePair.MakeGenericType(collectionDataContract.ItemType.GetGenericArguments())); @@ -2109,12 +2028,11 @@ internal static void CheckAndAdd(Type type, Dictionary typesChecked, { type = DataContract.UnwrapNullableType(type); DataContract dataContract = DataContract.GetDataContract(type); - DataContract? alreadyExistingContract; if (nameToDataContractTable == null) { nameToDataContractTable = new DataContractDictionary(); } - else if (nameToDataContractTable.TryGetValue(dataContract.StableName, out alreadyExistingContract)) + else if (nameToDataContractTable.TryGetValue(dataContract.StableName, out DataContract? alreadyExistingContract)) { // NOTE TODO smolloy - The existing contract type was used as-is in NetFx. The call to get the appropriate adapter type was added in CoreFx with https://github.com/dotnet/runtime/commit/50c0a70c52fa66fafa1227be552ccdab5e4cf8e4 // Don't throw duplicate if its a KeyValuePair as it could have been added by Dictionary @@ -2129,18 +2047,17 @@ internal static void CheckAndAdd(Type type, Dictionary typesChecked, [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", Justification = "DataContract is an internal type, but the override here is the very public Object.Equals(). Being an internal type" + "though, we control when this is called, and all callers are annotated with [RequiresUnreferencedCode].")] - public sealed override bool Equals(object? other) + public sealed override bool Equals(object? obj) { - if ((object)this == other) + if ((object)this == obj) return true; - return Equals(other, new HashSet()); + return Equals(obj, new HashSet()); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal virtual bool Equals(object? other, HashSet checkedContracts) { - DataContract? dataContract = other as DataContract; - if (dataContract != null) + if (other is DataContract dataContract) { return (StableName.Name == dataContract.StableName.Name && StableName.Namespace == dataContract.StableName.Namespace && IsReference == dataContract.IsReference); } @@ -2343,8 +2260,7 @@ internal GenericNameProvider(string genericTypeName, object[] genericParams) _genericParams = new object[genericParams.Length]; genericParams.CopyTo(_genericParams, 0); - string name; - DataContract.GetClrNameAndNamespace(genericTypeName, out name, out _); + DataContract.GetClrNameAndNamespace(genericTypeName, out string name, out _); _nestedParamCounts = DataContract.GetDataContractNameForGenericName(name, null); } @@ -2412,9 +2328,7 @@ private XmlQualifiedName GetStableName(int i) } } - // TODO smolloy - This class looks like it came back in the re-alignment... but much of it is unused in-box. After reworking schema - // import/export, check back on this and see if there are still unused methods that can go away. - internal sealed class GenericInfo : IGenericNameProvider + public sealed class GenericInfo : IGenericNameProvider { private string? _genericTypeName; private XmlQualifiedName _stableName; @@ -2429,6 +2343,18 @@ internal GenericInfo(XmlQualifiedName stableName, string? genericTypeName) _nestedParamCounts.Add(0); } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + public XmlQualifiedName GetExpandedStableName() + { + if (_paramGenericInfos == null) + return _stableName; + return new XmlQualifiedName(DataContract.EncodeLocalName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(_stableName.Name), this)), _stableName.Namespace); + } + + public XmlQualifiedName StableName => _stableName; + + public IList? Parameters => _paramGenericInfos; + internal void Add(GenericInfo actualParamInfo) { if (_paramGenericInfos == null) @@ -2449,48 +2375,30 @@ internal void AddToLevel(int level, int count) _nestedParamCounts[level] = _nestedParamCounts[level] + count; } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal XmlQualifiedName GetExpandedStableName() - { - if (_paramGenericInfos == null) - return _stableName; - return new XmlQualifiedName(DataContract.EncodeLocalName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(_stableName.Name), this)), _stableName.Namespace); - } - internal string GetStableNamespace() { return _stableName.Namespace; } - internal XmlQualifiedName StableName - { - get { return _stableName; } - } - - internal IList? Parameters - { - get { return _paramGenericInfos; } - } - - public int GetParameterCount() + int IGenericNameProvider.GetParameterCount() { return _paramGenericInfos?.Count ?? 0; } - public IList GetNestedParameterCounts() + IList IGenericNameProvider.GetNestedParameterCounts() { return _nestedParamCounts; } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public string GetParameterName(int paramIndex) + string IGenericNameProvider.GetParameterName(int paramIndex) { Debug.Assert(_paramGenericInfos != null); return _paramGenericInfos[paramIndex].GetExpandedStableName().Name; } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public string GetNamespaces() + string IGenericNameProvider.GetNamespaces() { if (_paramGenericInfos == null || _paramGenericInfos.Count == 0) return ""; @@ -2501,12 +2409,12 @@ public string GetNamespaces() return namespaces.ToString(); } - public string? GetGenericTypeName() + string? IGenericNameProvider.GetGenericTypeName() { return _genericTypeName; } - public bool ParametersFromBuiltInNamespaces + bool IGenericNameProvider.ParametersFromBuiltInNamespaces { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get @@ -2526,7 +2434,6 @@ public bool ParametersFromBuiltInNamespaces return parametersFromBuiltInNamespaces; } } - } internal sealed class DataContractPairKey @@ -2534,7 +2441,7 @@ internal sealed class DataContractPairKey private object _object1; private object _object2; - public DataContractPairKey(object object1, object object2) + internal DataContractPairKey(object object1, object object2) { _object1 = object1; _object2 = object2; @@ -2542,8 +2449,7 @@ public DataContractPairKey(object object1, object object2) public override bool Equals(object? other) { - DataContractPairKey? otherKey = other as DataContractPairKey; - if (otherKey == null) + if (other is not DataContractPairKey otherKey) return false; return ((otherKey._object1 == _object1 && otherKey._object2 == _object2) || (otherKey._object1 == _object2 && otherKey._object2 == _object1)); } @@ -2595,14 +2501,8 @@ public TypeHandleRef(RuntimeTypeHandle value) public RuntimeTypeHandle Value { - get - { - return _value; - } - set - { - _value = value; - } + get => _value; + set => _value = value; } } @@ -2615,12 +2515,6 @@ public IntRef(int value) _value = value; } - public int Value - { - get - { - return _value; - } - } + public int Value => _value; } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs index 354f6fd8d09a9..c0d6cfec922d8 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs @@ -2,17 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.IO; -using System.Reflection; using System.Runtime.CompilerServices; -using System.Text; using System.Xml; + using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization @@ -28,8 +23,8 @@ public sealed class DataContractSerializer : XmlObjectSerializer private bool _ignoreExtensionDataObject; private bool _preserveObjectReferences; private ReadOnlyCollection? _knownTypeCollection; - internal IList? knownTypeList; - internal DataContractDictionary? knownDataContracts; + internal IList? _knownTypeList; + internal DataContractDictionary? _knownDataContracts; private DataContractResolver? _dataContractResolver; private ISerializationSurrogateProvider? _serializationSurrogateProvider; private bool _serializeReadOnlyTypes; @@ -119,10 +114,10 @@ private void Initialize(Type type, if (knownTypes != null) { - this.knownTypeList = new List(); + _knownTypeList = new List(); foreach (Type knownType in knownTypes) { - this.knownTypeList.Add(knownType); + _knownTypeList.Add(knownType); } } @@ -158,9 +153,9 @@ public ReadOnlyCollection KnownTypes { if (_knownTypeCollection == null) { - if (knownTypeList != null) + if (_knownTypeList != null) { - _knownTypeCollection = new ReadOnlyCollection(knownTypeList); + _knownTypeCollection = new ReadOnlyCollection(_knownTypeList); } else { @@ -176,15 +171,15 @@ internal override DataContractDictionary? KnownDataContracts [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get { - if (this.knownDataContracts == null && this.knownTypeList != null) + if (_knownDataContracts == null && _knownTypeList != null) { // This assignment may be performed concurrently and thus is a race condition. // It's safe, however, because at worse a new (and identical) dictionary of // data contracts will be created and re-assigned to this field. Introduction // of a lock here could lead to deadlocks. - this.knownDataContracts = XmlObjectSerializerContext.GetDataContractsForKnownTypes(this.knownTypeList); + _knownDataContracts = XmlObjectSerializerContext.GetDataContractsForKnownTypes(_knownTypeList); } - return this.knownDataContracts; + return _knownDataContracts; } } @@ -358,7 +353,7 @@ internal void InternalWriteObjectContent(XmlWriterDelegator writer, object? grap graph = SurrogateToDataContractType(_serializationSurrogateProvider, graph, declaredType, ref graphType); } - dataContractResolver ??= this.DataContractResolver; + dataContractResolver ??= DataContractResolver; if (graph == null) { @@ -437,7 +432,7 @@ internal override void InternalWriteEndObject(XmlWriterDelegator writer) if (MaxItemsInObjectGraph == 0) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ExceededMaxItemsQuota, MaxItemsInObjectGraph))); - dataContractResolver ??= this.DataContractResolver; + dataContractResolver ??= DataContractResolver; if (verifyObjectName) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs index 5056dc0f96289..520b1e51364f8 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs @@ -6,22 +6,23 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Text; +using System.Xml.Schema; using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization { - internal sealed class DataContractSet + public sealed class DataContractSet { - private Dictionary? _contracts; + private DataContractDictionary? _contracts; private Dictionary? _processedContracts; - private ISerializationExtendedSurrogateProvider? _extendedSurrogateProvider; + private readonly ISerializationExtendedSurrogateProvider? _extendedSurrogateProvider; private Hashtable? _surrogateDataTable; private DataContractDictionary? _knownTypesForObject; private readonly ICollection? _referencedTypes; private readonly ICollection? _referencedCollectionTypes; - internal DataContractSet(ISerializationExtendedSurrogateProvider? dataContractExtendedSurrogate, ICollection? referencedTypes, ICollection? referencedCollectionTypes) + public DataContractSet(ISerializationExtendedSurrogateProvider? dataContractExtendedSurrogate, ICollection? referencedTypes, ICollection? referencedCollectionTypes) { _referencedTypes = referencedTypes; _referencedCollectionTypes = referencedCollectionTypes; @@ -29,7 +30,7 @@ internal DataContractSet(ISerializationExtendedSurrogateProvider? dataContractEx } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal DataContractSet(DataContractSet dataContractSet) + public DataContractSet(DataContractSet dataContractSet) { ArgumentNullException.ThrowIfNull(dataContractSet); @@ -37,9 +38,9 @@ internal DataContractSet(DataContractSet dataContractSet) _referencedCollectionTypes = dataContractSet._referencedCollectionTypes; _extendedSurrogateProvider = dataContractSet._extendedSurrogateProvider; - foreach (KeyValuePair pair in dataContractSet) + foreach (KeyValuePair pair in dataContractSet.Contracts) { - Add(pair.Key, pair.Value); + InternalAdd(pair.Key, pair.Value); } if (dataContractSet._processedContracts != null) @@ -51,22 +52,22 @@ internal DataContractSet(DataContractSet dataContractSet) } } - private Dictionary Contracts => - _contracts ??= new Dictionary(); + internal DataContractDictionary Contracts => + _contracts ??= new DataContractDictionary(); - private Dictionary ProcessedContracts => + public Dictionary ProcessedContracts => _processedContracts ??= new Dictionary(); private Hashtable SurrogateDataTable => _surrogateDataTable ??= new Hashtable(); - internal DataContractDictionary? KnownTypesForObject + public DataContractDictionary? KnownTypesForObject { - get { return _knownTypesForObject; } - set { _knownTypesForObject = value; } + get => _knownTypesForObject; + internal set => _knownTypesForObject = value; } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal void Add(Type type) + public void Add(Type type) { DataContract dataContract = GetDataContract(type); EnsureTypeNotGeneric(dataContract.UnderlyingType); @@ -86,18 +87,18 @@ private void Add(DataContract dataContract) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public void Add(XmlQualifiedName name, DataContract dataContract) + internal void Add(XmlQualifiedName name, DataContract dataContract) { if (dataContract.IsBuiltInDataContract) return; - InternalAdd(name, dataContract); + if (dataContract is DataContract dataContractInternal) + InternalAdd(name, dataContractInternal); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal void InternalAdd(XmlQualifiedName name, DataContract dataContract) { - DataContract? dataContractInSet; - if (Contracts.TryGetValue(name, out dataContractInSet)) + if (Contracts.TryGetValue(name, out DataContract? dataContractInSet)) { if (!dataContractInSet.Equals(dataContract)) { @@ -114,17 +115,17 @@ internal void InternalAdd(XmlQualifiedName name, DataContract dataContract) { Contracts.Add(name, dataContract); - if (dataContract is ClassDataContract) + if (dataContract is ClassDataContract classDC) { - AddClassDataContract((ClassDataContract)dataContract); + AddClassDataContract(classDC); } - else if (dataContract is CollectionDataContract) + else if (dataContract is CollectionDataContract collectionDC) { - AddCollectionDataContract((CollectionDataContract)dataContract); + AddCollectionDataContract(collectionDC); } - else if (dataContract is XmlDataContract) + else if (dataContract is XmlDataContract xmlDC) { - AddXmlDataContract((XmlDataContract)dataContract); + AddXmlDataContract(xmlDC); } } } @@ -209,20 +210,20 @@ internal XmlQualifiedName GetStableName(Type clrType) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal DataContract GetDataContract(Type clrType) + public DataContract GetDataContract(Type type) { if (_extendedSurrogateProvider == null) - return DataContract.GetDataContract(clrType); + return DataContract.GetDataContract(type); - DataContract? dataContract = DataContract.GetBuiltInDataContract(clrType); + DataContract? dataContract = DataContract.GetBuiltInDataContract(type); if (dataContract != null) return dataContract; - Type dcType = DataContractSurrogateCaller.GetDataContractType(_extendedSurrogateProvider, clrType); + Type dcType = DataContractSurrogateCaller.GetDataContractType(_extendedSurrogateProvider, type); dataContract = DataContract.GetDataContract(dcType); if (!SurrogateDataTable.Contains(dataContract)) { - object? customData = DataContractSurrogateCaller.GetCustomDataToExport(_extendedSurrogateProvider, clrType, dcType); + object? customData = DataContractSurrogateCaller.GetCustomDataToExport(_extendedSurrogateProvider, type, dcType); if (customData != null) SurrogateDataTable.Add(dataContract, customData); } @@ -230,6 +231,17 @@ internal DataContract GetDataContract(Type clrType) return dataContract; } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + public DataContract? GetDataContract(XmlQualifiedName key) + { + DataContract? dataContract = DataContract.GetBuiltInDataContract(key.Name, key.Namespace); + if (dataContract == null) + { + Contracts.TryGetValue(key, out dataContract); + } + return dataContract; + } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal DataContract GetMemberTypeDataContract(DataMember dataMember) { @@ -263,19 +275,6 @@ internal DataContract GetItemTypeDataContract(CollectionDataContract collectionC return collectionContract.ItemContract; } - internal DataContract? this[XmlQualifiedName key] - { - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - get - { - DataContract? dataContract = DataContract.GetBuiltInDataContract(key.Name, key.Namespace); - if (dataContract == null) - { - Contracts.TryGetValue(key, out dataContract); - } - return dataContract; - } - } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal bool Remove(XmlQualifiedName key) { @@ -400,39 +399,39 @@ private static bool IsTypeReferenceable(Type type) return false; } - //[RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - //private bool TryGetReferencedType(XmlQualifiedName stableName, DataContract? dataContract, [NotNullWhen(true)] out Type? type) - //{ - // if (dataContract == null) - // { - // if (_dataContractSet.TryGetReferencedCollectionType(stableName, null, out type)) - // return true; - // if (_dataContractSet.TryGetReferencedType(stableName, null, out type)) - // { - // // enforce that collection types only be specified via ReferencedCollectionTypes - // if (CollectionDataContract.IsCollection(type)) - // { - // type = null; - // return false; - // } - // return true; - // } - // return false; - // } - // else if (dataContract is CollectionDataContract) - // return _dataContractSet.TryGetReferencedCollectionType(stableName, dataContract, out type); - // else - // { - // if (dataContract is XmlDataContract xmlDataContract && xmlDataContract.IsAnonymous) - // { - // stableName = SchemaImporter.ImportActualType(xmlDataContract.XsdType?.Annotation, stableName, dataContract.StableName); - // } - // return _dataContractSet.TryGetReferencedType(stableName, dataContract, out type); - // } - //} + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + public bool TryGetReferencedType(XmlQualifiedName stableName, DataContract? dataContract, [NotNullWhen(true)] out Type? type) + { + if (dataContract == null) + { + if (TryGetReferencedCollectionType(stableName, null, out type)) + return true; + if (TryGetReferencedSingleType(stableName, null, out type)) + { + // enforce that collection types only be specified via ReferencedCollectionTypes + if (CollectionDataContract.IsCollection(type)) + { + type = null; + return false; + } + return true; + } + return false; + } + else if (dataContract is CollectionDataContract) + return TryGetReferencedCollectionType(stableName, dataContract, out type); + else + { + if (dataContract is XmlDataContract xmlDataContract && xmlDataContract.IsAnonymous) + { + stableName = SchemaImporter.ImportActualType(xmlDataContract.XsdType?.Annotation, stableName, dataContract.StableName); + } + return TryGetReferencedSingleType(stableName, dataContract, out type); + } + } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal bool TryGetReferencedType(XmlQualifiedName stableName, DataContract? dataContract, [NotNullWhen(true)] out Type? type) + internal bool TryGetReferencedSingleType(XmlQualifiedName stableName, DataContract? dataContract, [NotNullWhen(true)] out Type? type) { return TryGetReferencedType(stableName, dataContract, false/*useReferencedCollectionTypes*/, out type); } @@ -492,10 +491,7 @@ private bool TryGetReferencedType(XmlQualifiedName stableName, DataContract? dat return false; } - internal ISerializationExtendedSurrogateProvider? SerializationExtendedSurrogateProvider - { - get { return _extendedSurrogateProvider; } - } + internal ISerializationExtendedSurrogateProvider? SerializationExtendedSurrogateProvider => _extendedSurrogateProvider; internal object? GetSurrogateData(object key) { @@ -506,10 +502,6 @@ internal void SetSurrogateData(object key, object? surrogateData) { SurrogateDataTable[key] = surrogateData; } - public IEnumerator> GetEnumerator() - { - return Contracts.GetEnumerator(); - } internal bool IsContractProcessed(DataContract dataContract) { @@ -520,5 +512,57 @@ internal void SetContractProcessed(DataContract dataContract) { ProcessedContracts.Add(dataContract, dataContract); } + + public IEnumerator> GetEnumerator() + { + return Contracts.GetEnumerator(); + } + + public static void CompileSchemaSet(XmlSchemaSet schemaSet) + { + SchemaImporter.CompileSchemaSet(schemaSet); + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + public void ExportSchemaSet(XmlSchemaSet schemaSet) + { + SchemaExporter exporter = new SchemaExporter(schemaSet, this); + exporter.Export(); + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + public void ImportSchemaSet(XmlSchemaSet schemaSet, ICollection? typeNames, ICollection elements, XmlQualifiedName[] elementTypeNames /*filled on return*/, bool importXmlDataType) + { + SchemaImporter importer = new SchemaImporter(schemaSet, typeNames, elements, elementTypeNames, this, importXmlDataType); + importer.Import(); + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + public Type? GetReferencedTypeOnImport(DataContract dataContract) + { + ISerializationExtendedSurrogateProvider? dataContractSurrogate = SerializationExtendedSurrogateProvider; + Type? type = null; + if (dataContractSurrogate != null) + { + type = DataContractSurrogateCaller.GetReferencedTypeOnImport( + dataContractSurrogate, + dataContract.StableName.Name, + dataContract.StableName.Namespace, + GetSurrogateData(dataContract)); + } + return type; + } + + public bool TryGetSurrogateData(object key, out object? value) + { + if (SerializationExtendedSurrogateProvider != null) + { + value = GetSurrogateData(key); + return true; + } + + value = null; + return false; + } } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs index 04e4dd422b0fe..66995ae4345b2 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs @@ -2,18 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections; using System.Collections.Generic; -using System.Globalization; -using System.Reflection; -using System.Xml; -using System.Security; using System.Diagnostics.CodeAnalysis; -using System.Diagnostics; +using System.Reflection; namespace System.Runtime.Serialization { - internal sealed class DataMember + public sealed class DataMember { private readonly CriticalHelper _helper; @@ -27,102 +22,68 @@ internal DataMember(DataContract memberTypeContract, string name, bool isNullabl _helper = new CriticalHelper(memberTypeContract, name, isNullable, isRequired, emitDefaultValue, order); } - internal MemberInfo MemberInfo - { - get - { return _helper.MemberInfo; } - } + internal MemberInfo MemberInfo => _helper.MemberInfo; public string Name { - get - { return _helper.Name; } - - set - { _helper.Name = value; } + get => _helper.Name; + internal set => _helper.Name = value; } public int Order { - get - { return _helper.Order; } - - set - { _helper.Order = value; } + get => _helper.Order; + internal set => _helper.Order = value; } public bool IsRequired { - get - { return _helper.IsRequired; } - - set - { _helper.IsRequired = value; } + get => _helper.IsRequired; + internal set => _helper.IsRequired = value; } public bool EmitDefaultValue { - get - { return _helper.EmitDefaultValue; } - - set - { _helper.EmitDefaultValue = value; } + get => _helper.EmitDefaultValue; + internal set => _helper.EmitDefaultValue = value; } public bool IsNullable { - get - { return _helper.IsNullable; } - - set - { _helper.IsNullable = value; } + get => _helper.IsNullable; + internal set => _helper.IsNullable = value; } - public bool IsGetOnlyCollection + internal bool IsGetOnlyCollection { - get - { return _helper.IsGetOnlyCollection; } - - set - { _helper.IsGetOnlyCollection = value; } + get => _helper.IsGetOnlyCollection; + set => _helper.IsGetOnlyCollection = value; } - internal Type MemberType - { - get - { return _helper.MemberType; } - } + internal Type MemberType => _helper.MemberType; - internal DataContract MemberTypeContract + public DataContract MemberTypeContract { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - get - { return _helper.MemberTypeContract; } + get => _helper.MemberTypeContract; } internal PrimitiveDataContract? MemberPrimitiveContract { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - get - { return _helper.MemberPrimitiveContract; } + get => _helper.MemberPrimitiveContract; } - public bool HasConflictingNameAndType + internal bool HasConflictingNameAndType { - get - { return _helper.HasConflictingNameAndType; } - - set - { _helper.HasConflictingNameAndType = value; } + get => _helper.HasConflictingNameAndType; + set => _helper.HasConflictingNameAndType = value; } internal DataMember? ConflictingMember { - get - { return _helper.ConflictingMember; } - - set - { _helper.ConflictingMember = value; } + get => _helper.ConflictingMember; + set => _helper.ConflictingMember = value; } private FastInvokerBuilder.Getter? _getter; @@ -163,45 +124,42 @@ internal CriticalHelper(DataContract memberTypeContract, string name, bool isNul _memberInfo = memberTypeContract.UnderlyingType; } - internal MemberInfo MemberInfo - { - get { return _memberInfo; } - } + internal MemberInfo MemberInfo => _memberInfo; internal string Name { - get { return _name; } - set { _name = value; } + get => _name; + set => _name = value; } internal int Order { - get { return _order; } - set { _order = value; } + get => _order; + set => _order = value; } internal bool IsRequired { - get { return _isRequired; } - set { _isRequired = value; } + get => _isRequired; + set => _isRequired = value; } internal bool EmitDefaultValue { - get { return _emitDefaultValue; } - set { _emitDefaultValue = value; } + get => _emitDefaultValue; + set => _emitDefaultValue = value; } internal bool IsNullable { - get { return _isNullable; } - set { _isNullable = value; } + get => _isNullable; + set => _isNullable = value; } internal bool IsGetOnlyCollection { - get { return _isGetOnlyCollection; } - set { _isGetOnlyCollection = value; } + get => _isGetOnlyCollection; + set => _isGetOnlyCollection = value; } internal Type MemberType @@ -210,8 +168,7 @@ internal Type MemberType { if (_memberType == null) { - FieldInfo? field = MemberInfo as FieldInfo; - if (field != null) + if (MemberInfo is FieldInfo field) _memberType = field.FieldType; else _memberType = ((PropertyInfo)MemberInfo).PropertyType; @@ -228,7 +185,7 @@ internal DataContract MemberTypeContract { if (_memberTypeContract == null) { - if (this.IsGetOnlyCollection) + if (IsGetOnlyCollection) { _memberTypeContract = DataContract.GetGetOnlyCollectionDataContract(DataContract.GetId(MemberType.TypeHandle), MemberType.TypeHandle, MemberType); } @@ -248,14 +205,14 @@ internal DataContract MemberTypeContract internal bool HasConflictingNameAndType { - get { return _hasConflictingNameAndType; } - set { _hasConflictingNameAndType = value; } + get => _hasConflictingNameAndType; + set => _hasConflictingNameAndType = value; } internal DataMember? ConflictingMember { - get { return _conflictingMember; } - set { _conflictingMember = value; } + get => _conflictingMember; + set => _conflictingMember = value; } private PrimitiveDataContract? _memberPrimitiveContract; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DateTimeOffsetAdapter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DateTimeOffsetAdapter.cs index 20cb05471fe63..da469b0c337c6 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DateTimeOffsetAdapter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DateTimeOffsetAdapter.cs @@ -66,7 +66,7 @@ public static DateTimeOffsetAdapter GetDateTimeOffsetAdapter(DateTimeOffset valu public string ToString(IFormatProvider provider) { - return "DateTime: " + this.UtcDateTime + ", Offset: " + this.OffsetMinutes; + return "DateTime: " + UtcDateTime + ", Offset: " + OffsetMinutes; } } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs index 98485d0c8e61a..5b1480e7befa2 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs @@ -2,14 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections; using System.Collections.Generic; -using System.Globalization; using System.Reflection; using System.Threading; -using System.Text; using System.Xml; -using System.Security; using System.Linq; using System.Diagnostics.CodeAnalysis; using System.Diagnostics; @@ -39,41 +35,27 @@ public XmlQualifiedName BaseContractName public List Members { - get - { return _helper.Members; } - set { _helper.Members = value; } + get => _helper.Members; + set => _helper.Members = value; } public List? Values { - get - { return _helper.Values; } - set { _helper.Values = value; } + get => _helper.Values; + set => _helper.Values = value; } public bool IsFlags { - get - { return _helper.IsFlags; } - set { _helper.IsFlags = value; } + get => _helper.IsFlags; + set => _helper.IsFlags = value; } - public bool IsULong - { - get - { return _helper.IsULong; } - } + public bool IsULong => _helper.IsULong; - public XmlDictionaryString[]? ChildElementNames - { - get - { return _helper.ChildElementNames; } - } + public XmlDictionaryString[]? ChildElementNames => _helper.ChildElementNames; - internal override bool CanContainReferences - { - get { return false; } - } + internal override bool CanContainReferences => false; private sealed class EnumDataContractCriticalHelper : DataContract.DataContractCriticalHelper { @@ -109,8 +91,7 @@ internal static void Add(Type type, string localName) internal static XmlQualifiedName GetBaseContractName(Type type) { - XmlQualifiedName? retVal; - s_typeToName.TryGetValue(type, out retVal); + s_typeToName.TryGetValue(type, out XmlQualifiedName? retVal); Debug.Assert(retVal != null); // Enums can only have certain base types. We shouldn't come up empty here. return retVal; @@ -118,8 +99,7 @@ internal static XmlQualifiedName GetBaseContractName(Type type) internal static Type? GetBaseType(XmlQualifiedName baseContractName) { - Type? retVal; - s_nameToType.TryGetValue(baseContractName, out retVal); + s_nameToType.TryGetValue(baseContractName, out Type? retVal); return retVal; } @@ -128,7 +108,7 @@ internal EnumDataContractCriticalHelper( [DynamicallyAccessedMembers(ClassDataContract.DataContractPreserveMemberTypes)] Type type) : base(type) { - this.StableName = DataContract.GetStableName(type, out _hasDataContract); + StableName = DataContract.GetStableName(type, out _hasDataContract); Type baseType = Enum.GetUnderlyingType(type); _baseContractName = GetBaseContractName(baseType); ImportBaseType(baseType); @@ -141,8 +121,7 @@ internal EnumDataContractCriticalHelper( _childElementNames = new XmlDictionaryString[Members.Count]; for (int i = 0; i < Members.Count; i++) _childElementNames[i] = dictionary.Add(Members[i].Name); - DataContractAttribute? dataContractAttribute; - if (TryGetDCAttribute(type, out dataContractAttribute)) + if (TryGetDCAttribute(type, out DataContractAttribute? dataContractAttribute)) { if (dataContractAttribute.IsReference) { @@ -158,7 +137,7 @@ internal EnumDataContractCriticalHelper( internal XmlQualifiedName BaseContractName { - get { return _baseContractName; } + get => _baseContractName; set { @@ -173,32 +152,32 @@ internal XmlQualifiedName BaseContractName internal List Members { - get { return _members; } - set { _members = value; } + get => _members; + set => _members = value; } internal List? Values { - get { return _values; } - set { _values = value; } + get => _values; + set => _values = value; } internal bool IsFlags { - get { return _isFlags; } - set { _isFlags = value; } + get => _isFlags; + set => _isFlags = value; } internal bool IsULong { - get { return _isULong; } - set { _isULong = value; } + get => _isULong; + set => _isULong = value; } internal XmlDictionaryString[]? ChildElementNames { - get { return _childElementNames; } - set { _childElementNames = value; } + get => _childElementNames; + set => _childElementNames = value; } private void ImportBaseType(Type baseType) @@ -209,7 +188,7 @@ private void ImportBaseType(Type baseType) [MemberNotNull(nameof(_members))] private void ImportDataMembers() { - Type type = this.UnderlyingType; + Type type = UnderlyingType; FieldInfo[] fields = type.GetFields(BindingFlags.Static | BindingFlags.Public); Dictionary memberValuesTable = new Dictionary(); List tempMembers = new List(fields.Length); @@ -249,8 +228,7 @@ private void ImportDataMembers() { if (!field.IsNotSerialized) { - DataMember memberContract = new DataMember(field); - memberContract.Name = field.Name; + DataMember memberContract = new DataMember(field) { Name = field.Name }; ClassDataContract.CheckAndAddMember(tempMembers, memberContract, memberValuesTable); enumMemberValid = true; } @@ -403,13 +381,13 @@ internal long GetEnumValueFromString(string value) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext? context) { WriteEnumValue(xmlWriter, obj); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext? context) + internal override object ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext? context) { object obj = ReadEnumValue(xmlReader); if (context != null) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExtensionDataReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExtensionDataReader.cs index 08c7d552ec5c9..b339a271d56d5 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExtensionDataReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExtensionDataReader.cs @@ -105,11 +105,9 @@ internal void Reset() _elements = null; } -#pragma warning disable CS8775 // Member must have a non-null value when exiting in some condition. [MemberNotNullWhen(true, nameof(_xmlNodeReader))] [MemberNotNullWhen(false, nameof(_element))] private bool IsXmlDataNode { get { return (_internalNodeType == ExtensionDataNodeType.Xml); } } -#pragma warning restore CS8775 // Member must have a non-null value when exiting in some condition. public override XmlNodeType NodeType { get { return IsXmlDataNode ? _xmlNodeReader.NodeType : _nodeType; } } public override string LocalName { get { return IsXmlDataNode ? _xmlNodeReader.LocalName : _localName!; } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs index 7022db830c03c..2c355c8118161 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs @@ -18,19 +18,9 @@ internal GenericParameterDataContract(Type type) _helper = (base.Helper as GenericParameterDataContractCriticalHelper)!; } - internal int ParameterPosition - { - get - { return _helper.ParameterPosition; } - } + internal int ParameterPosition => _helper.ParameterPosition; - internal override bool IsBuiltInDataContract - { - get - { - return true; - } - } + public override bool IsBuiltInDataContract => true; private sealed class GenericParameterDataContractCriticalHelper : DataContract.DataContractCriticalHelper { @@ -46,14 +36,11 @@ internal GenericParameterDataContractCriticalHelper( _parameterPosition = type.GenericParameterPosition; } - internal int ParameterPosition - { - get { return _parameterPosition; } - } + internal int ParameterPosition => _parameterPosition; } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) + public override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) { return paramContracts[ParameterPosition]; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs index 9dcae7f027f79..a433e8ade6d0a 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs @@ -313,17 +313,16 @@ internal static Type TypeOfHashtable internal static Type TypeOfDBNull => s_typeOfDBNull ??= typeof(DBNull); - // TODO smolloy - change name inline with new name from class defined in SchemaHelper [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicFields)] - private static Type? s_typeOfSchemaTypePlaceholder; + private static Type? s_typeOfSchemaDefinedType; [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicFields)] - internal static Type TypeOfSchemaTypePlaceholder => - s_typeOfSchemaTypePlaceholder ??= typeof(SchemaTypePlaceholder); + internal static Type TypeOfSchemaDefinedType => + s_typeOfSchemaDefinedType ??= typeof(SchemaDefinedType); // TODO smolloy - change name inline with new name from SchemaHelper private static MemberInfo? s_schemaMemberInfoPlaceholder; internal static MemberInfo SchemaMemberInfoPlaceholder => - s_schemaMemberInfoPlaceholder ??= TypeOfSchemaTypePlaceholder.GetField("_stableName", BindingFlags.NonPublic | BindingFlags.Instance)!; + s_schemaMemberInfoPlaceholder ??= TypeOfSchemaDefinedType.GetField("_stableName", BindingFlags.NonPublic | BindingFlags.Instance)!; private static Uri? s_dataContractXsdBaseNamespaceUri; internal static Uri DataContractXsdBaseNamespaceUri => diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatWriter.cs index c65752936b5ce..3a924362045b9 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatWriter.cs @@ -27,8 +27,7 @@ public void ReflectionWriteClass(XmlWriterDelegator xmlWriter, object obj, XmlOb [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] public static void ReflectionWriteCollection(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContextComplexJson context, CollectionDataContract collectionContract) { - JsonWriterDelegator? jsonWriter = xmlWriter as JsonWriterDelegator; - if (jsonWriter == null) + if (xmlWriter is not JsonWriterDelegator jsonWriter) { throw new ArgumentException(nameof(xmlWriter)); } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/KnownTypeDataContractResolver.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/KnownTypeDataContractResolver.cs index ab1d030913b57..6a6acdfc56742 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/KnownTypeDataContractResolver.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/KnownTypeDataContractResolver.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Xml; -using System.Reflection; using System.Diagnostics.CodeAnalysis; namespace System.Runtime.Serialization diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs index 2179116d3c4f9..32fd5bf73c43d 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs @@ -39,12 +39,12 @@ protected PrimitiveDataContract( internal abstract string WriteMethodName { get; } internal abstract string ReadMethodName { get; } - internal override XmlDictionaryString? TopLevelElementNamespace + public override XmlDictionaryString? TopLevelElementNamespace { get { return DictionaryGlobals.SerializationNamespace; } - set + internal set { } } @@ -52,7 +52,7 @@ internal override XmlDictionaryString? TopLevelElementNamespace internal override bool IsPrimitive => true; - internal override bool IsBuiltInDataContract => true; + public override bool IsBuiltInDataContract => true; internal MethodInfo XmlFormatWriterMethod { @@ -90,7 +90,7 @@ internal MethodInfo XmlFormatContentWriterMethod _helper.XmlFormatReaderMethod ??= typeof(XmlReaderDelegator).GetMethod(ReadMethodName, Globals.ScanAllMembers)!; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext? context) { xmlWriter.WriteAnyType(obj); } @@ -120,7 +120,7 @@ internal override bool Equals(object? other, HashSet checke { if (other is PrimitiveDataContract) { - Type thisType = this.GetType(); + Type thisType = GetType(); Type otherType = other.GetType(); return (thisType.Equals(otherType) || thisType.IsSubclassOf(otherType) || otherType.IsSubclassOf(thisType)); } @@ -143,20 +143,20 @@ internal PrimitiveDataContractCriticalHelper( internal MethodInfo? XmlFormatWriterMethod { - get { return _xmlFormatWriterMethod; } - set { _xmlFormatWriterMethod = value; } + get => _xmlFormatWriterMethod; + set => _xmlFormatWriterMethod = value; } internal MethodInfo? XmlFormatContentWriterMethod { - get { return _xmlFormatContentWriterMethod; } - set { _xmlFormatContentWriterMethod = value; } + get => _xmlFormatContentWriterMethod; + set => _xmlFormatContentWriterMethod = value; } internal MethodInfo? XmlFormatReaderMethod { - get { return _xmlFormatReaderMethod; } - set { _xmlFormatReaderMethod = value; } + get => _xmlFormatReaderMethod; + set => _xmlFormatReaderMethod = value; } } } @@ -171,24 +171,24 @@ internal CharDataContract(XmlDictionaryString name, XmlDictionaryString ns) : ba { } - internal override string WriteMethodName { get { return "WriteChar"; } } - internal override string ReadMethodName { get { return "ReadElementContentAsChar"; } } + internal override string WriteMethodName => "WriteChar"; + internal override string ReadMethodName => "ReadElementContentAsChar"; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) { writer.WriteChar((char)obj); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { return (context == null) ? reader.ReadElementContentAsChar() : HandleReadValue(reader.ReadElementContentAsChar(), context); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) + internal override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) { xmlWriter.WriteChar((char)obj!, name, ns); } @@ -205,24 +205,24 @@ public BooleanDataContract() : base(typeof(bool), DictionaryGlobals.BooleanLocal { } - internal override string WriteMethodName { get { return "WriteBoolean"; } } - internal override string ReadMethodName { get { return "ReadElementContentAsBoolean"; } } + internal override string WriteMethodName => "WriteBoolean"; + internal override string ReadMethodName => "ReadElementContentAsBoolean"; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) { writer.WriteBoolean((bool)obj); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { return (context == null) ? reader.ReadElementContentAsBoolean() : HandleReadValue(reader.ReadElementContentAsBoolean(), context); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) + internal override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) { xmlWriter.WriteBoolean((bool)obj!, name, ns); } @@ -234,24 +234,24 @@ public SignedByteDataContract() : base(typeof(sbyte), DictionaryGlobals.SignedBy { } - internal override string WriteMethodName { get { return "WriteSignedByte"; } } - internal override string ReadMethodName { get { return "ReadElementContentAsSignedByte"; } } + internal override string WriteMethodName => "WriteSignedByte"; + internal override string ReadMethodName => "ReadElementContentAsSignedByte"; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) { writer.WriteSignedByte((sbyte)obj); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { return (context == null) ? reader.ReadElementContentAsSignedByte() : HandleReadValue(reader.ReadElementContentAsSignedByte(), context); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) + internal override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) { xmlWriter.WriteSignedByte((sbyte)obj!, name, ns); } @@ -263,24 +263,24 @@ public UnsignedByteDataContract() : base(typeof(byte), DictionaryGlobals.Unsigne { } - internal override string WriteMethodName { get { return "WriteUnsignedByte"; } } - internal override string ReadMethodName { get { return "ReadElementContentAsUnsignedByte"; } } + internal override string WriteMethodName => "WriteUnsignedByte"; + internal override string ReadMethodName => "ReadElementContentAsUnsignedByte"; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) { writer.WriteUnsignedByte((byte)obj); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { return (context == null) ? reader.ReadElementContentAsUnsignedByte() : HandleReadValue(reader.ReadElementContentAsUnsignedByte(), context); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) + internal override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) { xmlWriter.WriteUnsignedByte((byte)obj!, name, ns); } @@ -292,24 +292,24 @@ public ShortDataContract() : base(typeof(short), DictionaryGlobals.ShortLocalNam { } - internal override string WriteMethodName { get { return "WriteShort"; } } - internal override string ReadMethodName { get { return "ReadElementContentAsShort"; } } + internal override string WriteMethodName => "WriteShort"; + internal override string ReadMethodName => "ReadElementContentAsShort"; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) { writer.WriteShort((short)obj); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { return (context == null) ? reader.ReadElementContentAsShort() : HandleReadValue(reader.ReadElementContentAsShort(), context); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) + internal override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) { xmlWriter.WriteShort((short)obj!, name, ns); } @@ -321,24 +321,24 @@ public UnsignedShortDataContract() : base(typeof(ushort), DictionaryGlobals.Unsi { } - internal override string WriteMethodName { get { return "WriteUnsignedShort"; } } - internal override string ReadMethodName { get { return "ReadElementContentAsUnsignedShort"; } } + internal override string WriteMethodName => "WriteUnsignedShort"; + internal override string ReadMethodName => "ReadElementContentAsUnsignedShort"; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) { writer.WriteUnsignedShort((ushort)obj); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { return (context == null) ? reader.ReadElementContentAsUnsignedShort() : HandleReadValue(reader.ReadElementContentAsUnsignedShort(), context); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) + internal override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) { xmlWriter.WriteUnsignedShort((ushort)obj!, name, ns); } @@ -376,19 +376,19 @@ internal override string WriteMethodName } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) { throw new NotImplementedException(); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { throw new NotImplementedException(); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) + internal override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) { throw new NotImplementedException(); } @@ -400,24 +400,24 @@ public IntDataContract() : base(typeof(int), DictionaryGlobals.IntLocalName, Dic { } - internal override string WriteMethodName { get { return "WriteInt"; } } - internal override string ReadMethodName { get { return "ReadElementContentAsInt"; } } + internal override string WriteMethodName => "WriteInt"; + internal override string ReadMethodName => "ReadElementContentAsInt"; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) { writer.WriteInt((int)obj); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { return (context == null) ? reader.ReadElementContentAsInt() : HandleReadValue(reader.ReadElementContentAsInt(), context); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) + internal override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) { xmlWriter.WriteInt((int)obj!, name, ns); } @@ -429,24 +429,24 @@ public UnsignedIntDataContract() : base(typeof(uint), DictionaryGlobals.Unsigned { } - internal override string WriteMethodName { get { return "WriteUnsignedInt"; } } - internal override string ReadMethodName { get { return "ReadElementContentAsUnsignedInt"; } } + internal override string WriteMethodName => "WriteUnsignedInt"; + internal override string ReadMethodName => "ReadElementContentAsUnsignedInt"; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) { writer.WriteUnsignedInt((uint)obj); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { return (context == null) ? reader.ReadElementContentAsUnsignedInt() : HandleReadValue(reader.ReadElementContentAsUnsignedInt(), context); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) + internal override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) { xmlWriter.WriteUnsignedInt((uint)obj!, name, ns); } @@ -462,24 +462,24 @@ internal LongDataContract(XmlDictionaryString name, XmlDictionaryString ns) : ba { } - internal override string WriteMethodName { get { return "WriteLong"; } } - internal override string ReadMethodName { get { return "ReadElementContentAsLong"; } } + internal override string WriteMethodName => "WriteLong"; + internal override string ReadMethodName => "ReadElementContentAsLong"; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) { writer.WriteLong((long)obj); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { return (context == null) ? reader.ReadElementContentAsLong() : HandleReadValue(reader.ReadElementContentAsLong(), context); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) + internal override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) { xmlWriter.WriteLong((long)obj!, name, ns); } @@ -516,24 +516,24 @@ public UnsignedLongDataContract() : base(typeof(ulong), DictionaryGlobals.Unsign { } - internal override string WriteMethodName { get { return "WriteUnsignedLong"; } } - internal override string ReadMethodName { get { return "ReadElementContentAsUnsignedLong"; } } + internal override string WriteMethodName => "WriteUnsignedLong"; + internal override string ReadMethodName => "ReadElementContentAsUnsignedLong"; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) { writer.WriteUnsignedLong((ulong)obj); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { return (context == null) ? reader.ReadElementContentAsUnsignedLong() : HandleReadValue(reader.ReadElementContentAsUnsignedLong(), context); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) + internal override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) { xmlWriter.WriteUnsignedLong((ulong)obj!, name, ns); } @@ -545,24 +545,24 @@ public FloatDataContract() : base(typeof(float), DictionaryGlobals.FloatLocalNam { } - internal override string WriteMethodName { get { return "WriteFloat"; } } - internal override string ReadMethodName { get { return "ReadElementContentAsFloat"; } } + internal override string WriteMethodName => "WriteFloat"; + internal override string ReadMethodName => "ReadElementContentAsFloat"; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) { writer.WriteFloat((float)obj); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { return (context == null) ? reader.ReadElementContentAsFloat() : HandleReadValue(reader.ReadElementContentAsFloat(), context); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) + internal override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) { xmlWriter.WriteFloat((float)obj!, name, ns); } @@ -574,24 +574,24 @@ public DoubleDataContract() : base(typeof(double), DictionaryGlobals.DoubleLocal { } - internal override string WriteMethodName { get { return "WriteDouble"; } } - internal override string ReadMethodName { get { return "ReadElementContentAsDouble"; } } + internal override string WriteMethodName => "WriteDouble"; + internal override string ReadMethodName => "ReadElementContentAsDouble"; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) { writer.WriteDouble((double)obj); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { return (context == null) ? reader.ReadElementContentAsDouble() : HandleReadValue(reader.ReadElementContentAsDouble(), context); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) + internal override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) { xmlWriter.WriteDouble((double)obj!, name, ns); } @@ -603,24 +603,24 @@ public DecimalDataContract() : base(typeof(decimal), DictionaryGlobals.DecimalLo { } - internal override string WriteMethodName { get { return "WriteDecimal"; } } - internal override string ReadMethodName { get { return "ReadElementContentAsDecimal"; } } + internal override string WriteMethodName => "WriteDecimal"; + internal override string ReadMethodName => "ReadElementContentAsDecimal"; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) { writer.WriteDecimal((decimal)obj); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { return (context == null) ? reader.ReadElementContentAsDecimal() : HandleReadValue(reader.ReadElementContentAsDecimal(), context); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) + internal override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) { xmlWriter.WriteDecimal((decimal)obj!, name, ns); } @@ -636,24 +636,24 @@ public DateTimeDataContract() : base(typeof(DateTime), DictionaryGlobals.DateTim { } - internal override string WriteMethodName { get { return "WriteDateTime"; } } - internal override string ReadMethodName { get { return "ReadElementContentAsDateTime"; } } + internal override string WriteMethodName => "WriteDateTime"; + internal override string ReadMethodName => "ReadElementContentAsDateTime"; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) { writer.WriteDateTime((DateTime)obj); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { return (context == null) ? reader.ReadElementContentAsDateTime() : HandleReadValue(reader.ReadElementContentAsDateTime(), context); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) + internal override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) { xmlWriter.WriteDateTime((DateTime)obj!, name, ns); } @@ -669,17 +669,17 @@ internal StringDataContract(XmlDictionaryString name, XmlDictionaryString ns) : { } - internal override string WriteMethodName { get { return "WriteString"; } } - internal override string ReadMethodName { get { return "ReadElementContentAsString"; } } + internal override string WriteMethodName => "WriteString"; + internal override string ReadMethodName => "ReadElementContentAsString"; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) { writer.WriteString((string)obj); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { if (context == null) { @@ -692,7 +692,7 @@ public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObj } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) + internal override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) { context.WriteString(xmlWriter, (string?)obj, name, ns); } @@ -804,17 +804,17 @@ public ByteArrayDataContract() : base(typeof(byte[]), DictionaryGlobals.ByteArra { } - internal override string WriteMethodName { get { return "WriteBase64"; } } - internal override string ReadMethodName { get { return "ReadElementContentAsBase64"; } } + internal override string WriteMethodName => "WriteBase64"; + internal override string ReadMethodName => "ReadElementContentAsBase64"; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) { writer.WriteBase64((byte[])obj); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { if (context == null) { @@ -827,7 +827,7 @@ public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObj } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) + internal override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) { xmlWriter.WriteStartElement(name, ns); xmlWriter.WriteBase64((byte[]?)obj); @@ -841,17 +841,17 @@ public ObjectDataContract() : base(typeof(object), DictionaryGlobals.ObjectLocal { } - internal override string WriteMethodName { get { return "WriteAnyType"; } } - internal override string ReadMethodName { get { return "ReadElementContentAsAnyType"; } } + internal override string WriteMethodName => "WriteAnyType"; + internal override string ReadMethodName => "ReadElementContentAsAnyType"; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) { // write nothing } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { object obj; if (reader.IsEmptyElement) @@ -877,15 +877,9 @@ public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObj return (context == null) ? obj : HandleReadValue(obj, context); } - internal override bool CanContainReferences - { - get { return true; } - } + internal override bool CanContainReferences => true; - internal override bool IsPrimitive - { - get { return false; } - } + internal override bool IsPrimitive => false; } internal class TimeSpanDataContract : PrimitiveDataContract @@ -898,24 +892,24 @@ internal TimeSpanDataContract(XmlDictionaryString name, XmlDictionaryString ns) { } - internal override string WriteMethodName { get { return "WriteTimeSpan"; } } - internal override string ReadMethodName { get { return "ReadElementContentAsTimeSpan"; } } + internal override string WriteMethodName => "WriteTimeSpan"; + internal override string ReadMethodName => "ReadElementContentAsTimeSpan"; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) { writer.WriteTimeSpan((TimeSpan)obj); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { return (context == null) ? reader.ReadElementContentAsTimeSpan() : HandleReadValue(reader.ReadElementContentAsTimeSpan(), context); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlElement(XmlWriterDelegator writer, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) + internal override void WriteXmlElement(XmlWriterDelegator writer, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) { writer.WriteTimeSpan((TimeSpan)obj!, name, ns); } @@ -936,24 +930,24 @@ internal GuidDataContract(XmlDictionaryString name, XmlDictionaryString ns) : ba { } - internal override string WriteMethodName { get { return "WriteGuid"; } } - internal override string ReadMethodName { get { return "ReadElementContentAsGuid"; } } + internal override string WriteMethodName => "WriteGuid"; + internal override string ReadMethodName => "ReadElementContentAsGuid"; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) { writer.WriteGuid((Guid)obj); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { return (context == null) ? reader.ReadElementContentAsGuid() : HandleReadValue(reader.ReadElementContentAsGuid(), context); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) + internal override void WriteXmlElement(XmlWriterDelegator xmlWriter, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) { xmlWriter.WriteGuid((Guid)obj!, name, ns); } @@ -970,17 +964,17 @@ public UriDataContract() : base(typeof(Uri), DictionaryGlobals.UriLocalName, Dic { } - internal override string WriteMethodName { get { return "WriteUri"; } } - internal override string ReadMethodName { get { return "ReadElementContentAsUri"; } } + internal override string WriteMethodName => "WriteUri"; + internal override string ReadMethodName => "ReadElementContentAsUri"; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) { writer.WriteUri((Uri)obj); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { if (context == null) { @@ -993,7 +987,7 @@ public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObj } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlElement(XmlWriterDelegator writer, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) + internal override void WriteXmlElement(XmlWriterDelegator writer, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) { writer.WriteUri((Uri?)obj, name, ns); } @@ -1005,22 +999,19 @@ public QNameDataContract() : base(typeof(XmlQualifiedName), DictionaryGlobals.QN { } - internal override string WriteMethodName { get { return "WriteQName"; } } - internal override string ReadMethodName { get { return "ReadElementContentAsQName"; } } + internal override string WriteMethodName => "WriteQName"; + internal override string ReadMethodName => "ReadElementContentAsQName"; - internal override bool IsPrimitive - { - get { return false; } - } + internal override bool IsPrimitive => false; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObjectSerializerWriteContext? context) { writer.WriteQName((XmlQualifiedName)obj); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator reader, XmlObjectSerializerReadContext? context) { if (context == null) { @@ -1033,7 +1024,7 @@ public override void WriteXmlValue(XmlWriterDelegator writer, object obj, XmlObj } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlElement(XmlWriterDelegator writer, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) + internal override void WriteXmlElement(XmlWriterDelegator writer, object? obj, XmlObjectSerializerWriteContext context, XmlDictionaryString name, XmlDictionaryString? ns) { context.WriteQName(writer, (XmlQualifiedName?)obj, name, ns); } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs index 744120facdaa7..7d1881dc5be98 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs @@ -42,7 +42,7 @@ internal void Export() { // Remove this if we decide to publish serialization schema at well-known location ExportSerializationSchema(); - foreach (KeyValuePair pair in _dataContractSet) + foreach (KeyValuePair pair in _dataContractSet.Contracts) { DataContract dataContract = pair.Value; if (!_dataContractSet.IsContractProcessed(dataContract)) @@ -179,8 +179,7 @@ private static void AddReferenceAttributes(XmlSchemaObjectCollection attributes, private static void SetElementType(XmlSchemaElement element, DataContract dataContract, XmlSchema schema) { - XmlDataContract? xmlDataContract = dataContract as XmlDataContract; - if (xmlDataContract != null && xmlDataContract.IsAnonymous) + if (dataContract is XmlDataContract xmlDataContract && xmlDataContract.IsAnonymous) { element.SchemaType = xmlDataContract.XsdType; } @@ -640,8 +639,7 @@ private static bool InvokeSchemaProviderMethod(Type clrType, XmlSchemaSet schema } else { - XmlSchemaType? providerXsdType = typeInfo as XmlSchemaType; - if (providerXsdType != null) + if (typeInfo is XmlSchemaType providerXsdType) { string? typeName = providerXsdType.Name; string? typeNs = null; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs index 01301050919ec..9c0f606d0542d 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs @@ -27,12 +27,11 @@ internal SchemaObjectInfo(XmlSchemaType? type, XmlSchemaElement? element, XmlSch } } - // TODO smolloy - change name to something without placeholder. Like SchemaDefinedType or something. - internal sealed class SchemaTypePlaceholder + internal sealed class SchemaDefinedType { private XmlQualifiedName _stableName; - public SchemaTypePlaceholder(XmlQualifiedName stableName) + public SchemaDefinedType(XmlQualifiedName stableName) { _stableName = stableName; } @@ -70,8 +69,7 @@ internal static bool NamespacesEqual(string? ns1, string? ns2) outSchema = schema; foreach (XmlSchemaObject schemaObj in schema.Items) { - XmlSchemaType? schemaType = schemaObj as XmlSchemaType; - if (schemaType != null && schemaType.Name == typeQName.Name) + if (schemaObj is XmlSchemaType schemaType && schemaType.Name == typeQName.Name) { return schemaType; } @@ -103,8 +101,7 @@ internal static bool NamespacesEqual(string? ns1, string? ns2) outSchema = schema; foreach (XmlSchemaObject schemaObj in schema.Items) { - XmlSchemaElement? schemaElement = schemaObj as XmlSchemaElement; - if (schemaElement != null && schemaElement.Name == elementQName.Name) + if (schemaObj is XmlSchemaElement schemaElement && schemaElement.Name == elementQName.Name) { return schemaElement; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs index 6728f81ae3e80..f754b033f3819 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs @@ -8,6 +8,7 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; +using System.Linq; using System.Xml; using System.Xml.Schema; @@ -217,7 +218,7 @@ private void ImportKnownTypesForObject() List? knownTypes = schemaObjectInfo._knownTypes; if (knownTypes != null) { - DataContractDictionary knownDataContracts = new DataContractDictionary(); + Dictionary knownDataContracts = new Dictionary(); foreach (XmlSchemaType knownType in knownTypes) { // Expected: will throw exception if schema set contains types that are not supported @@ -246,8 +247,7 @@ internal SchemaObjectDictionary CreateSchemaObjects() { foreach (XmlSchemaObject schemaObj in schema.SchemaTypes.Values) { - XmlSchemaType? schemaType = schemaObj as XmlSchemaType; - if (schemaType != null) + if (schemaObj is XmlSchemaType schemaType) { knownTypesForObject.Add(schemaType); @@ -285,8 +285,7 @@ internal SchemaObjectDictionary CreateSchemaObjects() } foreach (XmlSchemaObject schemaObj in schema.Elements.Values) { - XmlSchemaElement? schemaElement = schemaObj as XmlSchemaElement; - if (schemaElement != null) + if (schemaObj is XmlSchemaElement schemaElement) { XmlQualifiedName currentElementName = new XmlQualifiedName(schemaElement.Name, schema.TargetNamespace); SchemaObjectInfo? schemaObjectInfo; @@ -403,7 +402,7 @@ private DataContract ImportType(XmlSchemaType type) [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private DataContract ImportType(XmlSchemaType type, XmlQualifiedName typeName, bool isAnonymous) { - DataContract? dataContract = _dataContractSet[typeName]; + DataContract? dataContract = _dataContractSet.GetDataContract(typeName); if (dataContract != null) return dataContract; @@ -495,8 +494,8 @@ private DataContract ImportType(XmlSchemaType type, XmlQualifiedName typeName, b return ImportXmlDataType(typeName, type, isAnonymous); } Type? referencedType; - if (_dataContractSet.TryGetReferencedType(typeName, dataContract, out referencedType) - || (string.IsNullOrEmpty(type.Name) && _dataContractSet.TryGetReferencedType(ImportActualType(type.Annotation, typeName, typeName), dataContract, out referencedType))) + if (_dataContractSet.TryGetReferencedSingleType(typeName, dataContract, out referencedType) + || (string.IsNullOrEmpty(type.Name) && _dataContractSet.TryGetReferencedSingleType(ImportActualType(type.Annotation, typeName, typeName), dataContract, out referencedType))) { if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(referencedType)) { @@ -517,7 +516,7 @@ private DataContract ImportType(XmlSchemaType type, XmlQualifiedName typeName, b [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private void RemoveFailedContract(XmlQualifiedName typeName) { - ClassDataContract? oldContract = _dataContractSet[typeName] as ClassDataContract; + ClassDataContract? oldContract = _dataContractSet.GetDataContract(typeName) as ClassDataContract; _dataContractSet.Remove(typeName); if (oldContract != null) { @@ -587,8 +586,7 @@ private static void RemoveOptionalUnknownSerializationElements(XmlSchemaObjectCo { for (int i = 0; i < items.Count; i++) { - XmlSchemaElement? element = items[i] as XmlSchemaElement; - if (element != null && element.RefName != null && + if (items[i] is XmlSchemaElement element && element.RefName != null && element.RefName.Namespace == Globals.SerializationNamespace && element.MinOccurs == 0) { @@ -645,7 +643,7 @@ private static void RemoveOptionalUnknownSerializationElements(XmlSchemaObjectCo [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private ClassDataContract ImportClass(XmlQualifiedName typeName, XmlSchemaSequence rootSequence, XmlQualifiedName? baseTypeName, XmlSchemaAnnotation? annotation, bool isReference) { - ClassDataContract dataContract = new ClassDataContract(Globals.TypeOfSchemaTypePlaceholder); + ClassDataContract dataContract = new ClassDataContract(Globals.TypeOfSchemaDefinedType); dataContract.StableName = typeName; AddDataContract(dataContract); @@ -687,7 +685,7 @@ private ClassDataContract ImportClass(XmlQualifiedName typeName, XmlSchemaSequen [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private DataContract ImportXmlDataType(XmlQualifiedName typeName, XmlSchemaType xsdType, bool isAnonymous) { - DataContract? dataContract = _dataContractSet[typeName]; + DataContract? dataContract = _dataContractSet.GetDataContract(typeName); if (dataContract != null) return dataContract; @@ -695,7 +693,7 @@ private DataContract ImportXmlDataType(XmlQualifiedName typeName, XmlSchemaType if (xmlDataContract != null) return xmlDataContract; - xmlDataContract = new XmlDataContract(Globals.TypeOfSchemaTypePlaceholder); + xmlDataContract = new XmlDataContract(Globals.TypeOfSchemaDefinedType); xmlDataContract.StableName = typeName; xmlDataContract.IsValueType = false; AddDataContract(xmlDataContract); @@ -728,15 +726,14 @@ private DataContract ImportXmlDataType(XmlQualifiedName typeName, XmlSchemaType { if (!isAnonymous) return null; - XmlSchemaComplexType? complexType = xsdType as XmlSchemaComplexType; - if (complexType == null) + if (xsdType is not XmlSchemaComplexType complexType) return null; if (IsXmlAnyElementType(complexType)) { //check if the type is XElement XmlQualifiedName xlinqTypeName = new XmlQualifiedName("XElement", "http://schemas.datacontract.org/2004/07/System.Xml.Linq"); Type? referencedType; - if (_dataContractSet.TryGetReferencedType(xlinqTypeName, null, out referencedType) + if (_dataContractSet.TryGetReferencedSingleType(xlinqTypeName, null, out referencedType) && Globals.TypeOfIXmlSerializable.IsAssignableFrom(referencedType)) { XmlDataContract xmlDataContract = new XmlDataContract(referencedType); @@ -820,7 +817,7 @@ private static bool IsValueType(XmlQualifiedName typeName, XmlSchemaAnnotation? [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private ClassDataContract ImportISerializable(XmlQualifiedName typeName, XmlSchemaSequence rootSequence, XmlQualifiedName? baseTypeName, XmlSchemaObjectCollection attributes, XmlSchemaAnnotation? annotation) { - ClassDataContract dataContract = new ClassDataContract(Globals.TypeOfSchemaTypePlaceholder); + ClassDataContract dataContract = new ClassDataContract(Globals.TypeOfSchemaDefinedType); dataContract.StableName = typeName; dataContract.IsISerializable = true; AddDataContract(dataContract); @@ -1049,7 +1046,7 @@ internal static XmlQualifiedName ImportActualType(XmlSchemaAnnotation? annotatio [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private CollectionDataContract ImportCollection(XmlQualifiedName typeName, XmlSchemaSequence rootSequence, XmlSchemaObjectCollection attributes, XmlSchemaAnnotation? annotation, bool isReference) { - CollectionDataContract dataContract = new CollectionDataContract(Globals.TypeOfSchemaTypePlaceholder, CollectionKind.Array); + CollectionDataContract dataContract = new CollectionDataContract(Globals.TypeOfSchemaDefinedType, CollectionKind.Array); dataContract.StableName = typeName; AddDataContract(dataContract); @@ -1079,7 +1076,7 @@ private CollectionDataContract ImportCollection(XmlQualifiedName typeName, XmlSc if (element.SchemaType != null) { XmlQualifiedName shortName = new XmlQualifiedName(element.Name, typeName.Namespace); - DataContract? contract = _dataContractSet[shortName]; + DataContract? contract = _dataContractSet.GetDataContract(shortName); if (contract == null) { dataContract.ItemContract = ImportAnonymousElement(element, shortName); @@ -1190,7 +1187,7 @@ private static bool IsDictionary(XmlQualifiedName typeName, XmlSchemaAnnotation? [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private EnumDataContract ImportEnum(XmlQualifiedName typeName, XmlSchemaSimpleTypeRestriction restriction, bool isFlags, XmlSchemaAnnotation? annotation) { - EnumDataContract dataContract = new EnumDataContract(Globals.TypeOfSchemaTypePlaceholder); + EnumDataContract dataContract = new EnumDataContract(Globals.TypeOfSchemaDefinedType); dataContract.StableName = typeName; dataContract.BaseContractName = ImportActualType(annotation, SchemaExporter.DefaultEnumBaseTypeName, typeName); dataContract.IsFlags = isFlags; @@ -1428,8 +1425,7 @@ private void AddDataContract(DataContract dataContract) { for (int i = 0; i < markup.Length; i++) { - XmlElement? annotationElement = markup[i] as XmlElement; - if (annotationElement != null && annotationElement.LocalName == annotationQualifiedName.Name && annotationElement.NamespaceURI == annotationQualifiedName.Namespace) + if (markup[i] is XmlElement annotationElement && annotationElement.LocalName == annotationQualifiedName.Name && annotationElement.NamespaceURI == annotationQualifiedName.Namespace) return annotationElement; } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SpecialTypeDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SpecialTypeDataContract.cs index b3c315d0943a0..010871e02e13a 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SpecialTypeDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SpecialTypeDataContract.cs @@ -18,7 +18,7 @@ public SpecialTypeDataContract( _helper = (base.Helper as SpecialTypeDataContractCriticalHelper)!; } - internal override bool IsBuiltInDataContract => true; + public override bool IsBuiltInDataContract => true; private sealed class SpecialTypeDataContractCriticalHelper : DataContract.DataContractCriticalHelper { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SurrogateDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SurrogateDataContract.cs index 02b82aaee0d80..199d62050bc2b 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SurrogateDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SurrogateDataContract.cs @@ -20,13 +20,10 @@ internal SurrogateDataContract(Type type, ISerializationSurrogate serializationS _helper = (base.Helper as SurrogateDataContractCriticalHelper)!; } - internal ISerializationSurrogate SerializationSurrogate - { - get { return _helper.SerializationSurrogate; } - } + internal ISerializationSurrogate SerializationSurrogate => _helper.SerializationSurrogate; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext? context) { Debug.Assert(context != null); @@ -62,7 +59,7 @@ private void SerializationSurrogateGetObjectData(object obj, SerializationInfo s } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext? context) { Debug.Assert(context != null); @@ -99,10 +96,7 @@ internal SurrogateDataContractCriticalHelper( SetDataContractName(CreateQualifiedName(name, ns)); } - internal ISerializationSurrogate SerializationSurrogate - { - get { return serializationSurrogate; } - } + internal ISerializationSurrogate SerializationSurrogate => serializationSurrogate; } } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs index 22bb9320f429c..aa78c06a943d7 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs @@ -30,63 +30,49 @@ internal XmlDataContract(Type type) : base(new XmlDataContractCriticalHelper(typ internal override DataContractDictionary? KnownDataContracts { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - get - { return _helper.KnownDataContracts; } - - set - { _helper.KnownDataContracts = value; } + get => _helper.KnownDataContracts; + set => _helper.KnownDataContracts = value; } internal XmlSchemaType? XsdType { - get { return _helper.XsdType; } - set { _helper.XsdType = value; } + get => _helper.XsdType; + set => _helper.XsdType = value; } - internal bool IsAnonymous { - get - { return _helper.IsAnonymous; } + get => _helper.IsAnonymous; } - internal override bool HasRoot + public override bool HasRoot { - get - { return _helper.HasRoot; } - - set - { _helper.HasRoot = value; } + get => _helper.HasRoot; + internal set => _helper.HasRoot = value; } - internal override XmlDictionaryString? TopLevelElementName + public override XmlDictionaryString? TopLevelElementName { - get - { return _helper.TopLevelElementName; } - - set - { _helper.TopLevelElementName = value; } + get => _helper.TopLevelElementName; + internal set => _helper.TopLevelElementName = value; } - internal override XmlDictionaryString? TopLevelElementNamespace + public override XmlDictionaryString? TopLevelElementNamespace { - get - { return _helper.TopLevelElementNamespace; } - - set - { _helper.TopLevelElementNamespace = value; } + get => _helper.TopLevelElementNamespace; + internal set => _helper.TopLevelElementNamespace = value; } internal bool IsTopLevelElementNullable { - get { return _helper.IsTopLevelElementNullable; } - set { _helper.IsTopLevelElementNullable = value; } + get => _helper.IsTopLevelElementNullable; + set => _helper.IsTopLevelElementNullable = value; } internal bool IsTypeDefinedOnImport { - get { return _helper.IsTypeDefinedOnImport; } - set { _helper.IsTypeDefinedOnImport = value; } + get => _helper.IsTypeDefinedOnImport; + set => _helper.IsTypeDefinedOnImport = value; } internal CreateXmlSerializableDelegate CreateXmlSerializableDelegate @@ -119,7 +105,7 @@ internal CreateXmlSerializableDelegate CreateXmlSerializableDelegate internal override bool CanContainReferences => false; - internal override bool IsBuiltInDataContract => UnderlyingType == Globals.TypeOfXmlElement || UnderlyingType == Globals.TypeOfXmlNodeArray; + public override bool IsBuiltInDataContract => UnderlyingType == Globals.TypeOfXmlElement || UnderlyingType == Globals.TypeOfXmlNodeArray; private sealed class XmlDataContractCriticalHelper : DataContract.DataContractCriticalHelper { @@ -206,53 +192,46 @@ internal override DataContractDictionary? KnownDataContracts internal XmlSchemaType? XsdType { - get { return _xsdType; } - set { _xsdType = value; } + get => _xsdType; + set => _xsdType = value; } internal bool IsAnonymous => _xsdType != null; internal override bool HasRoot { - get - { return _hasRoot; } - - set - { _hasRoot = value; } + get => _hasRoot; + set => _hasRoot = value; } internal override XmlDictionaryString? TopLevelElementName { - get - { return _topLevelElementName; } - set - { _topLevelElementName = value; } + get => _topLevelElementName; + set => _topLevelElementName = value; } internal override XmlDictionaryString? TopLevelElementNamespace { - get - { return _topLevelElementNamespace; } - set - { _topLevelElementNamespace = value; } + get => _topLevelElementNamespace; + set => _topLevelElementNamespace = value; } internal bool IsTopLevelElementNullable { - get { return _isTopLevelElementNullable; } - set { _isTopLevelElementNullable = value; } + get => _isTopLevelElementNullable; + set => _isTopLevelElementNullable = value; } internal bool IsTypeDefinedOnImport { - get { return _isTypeDefinedOnImport; } - set { _isTypeDefinedOnImport = value; } + get => _isTypeDefinedOnImport; + set => _isTypeDefinedOnImport = value; } internal CreateXmlSerializableDelegate? CreateXmlSerializableDelegate { - get { return _createXmlSerializable; } - set { _createXmlSerializable = value; } + get => _createXmlSerializable; + set => _createXmlSerializable = value; } } @@ -419,7 +398,7 @@ internal override bool Equals(object? other, HashSet checke } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext? context) + internal override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext? context) { if (context == null) XmlObjectSerializerWriteContext.WriteRootIXmlSerializable(xmlWriter, obj); @@ -428,7 +407,7 @@ public override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, Xml } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override object? ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext? context) + internal override object? ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext? context) { object? o; if (context == null) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs index 56cb7458123f0..b0de63121dd22 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs @@ -52,7 +52,7 @@ internal XmlObjectSerializerContext(DataContractSerializer serializer, DataContr ) { this.rootTypeDataContract = rootTypeDataContract; - this.serializerKnownTypeList = serializer.knownTypeList; + this.serializerKnownTypeList = serializer._knownTypeList; } internal virtual bool IsGetOnlyCollection diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlReaderDelegator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlReaderDelegator.cs index ea4dc414f809a..f8427dc8f2834 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlReaderDelegator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlReaderDelegator.cs @@ -1043,8 +1043,7 @@ internal bool Normalized { get { - XmlTextReader? xmlTextReader = reader as XmlTextReader; - if (xmlTextReader == null) + if (reader is not XmlTextReader xmlTextReader) { IXmlTextParser? xmlTextParser = reader as IXmlTextParser; return (xmlTextParser == null) ? false : xmlTextParser.Normalized; @@ -1054,11 +1053,9 @@ internal bool Normalized } set { - XmlTextReader? xmlTextReader = reader as XmlTextReader; - if (xmlTextReader == null) + if (reader is not XmlTextReader xmlTextReader) { - IXmlTextParser? xmlTextParser = reader as IXmlTextParser; - if (xmlTextParser != null) + if (reader is IXmlTextParser xmlTextParser) xmlTextParser.Normalized = value; } else @@ -1070,8 +1067,7 @@ internal WhitespaceHandling WhitespaceHandling { get { - XmlTextReader? xmlTextReader = reader as XmlTextReader; - if (xmlTextReader == null) + if (reader is not XmlTextReader xmlTextReader) { IXmlTextParser? xmlTextParser = reader as IXmlTextParser; return (xmlTextParser == null) ? WhitespaceHandling.None : xmlTextParser.WhitespaceHandling; @@ -1081,11 +1077,9 @@ internal WhitespaceHandling WhitespaceHandling } set { - XmlTextReader? xmlTextReader = reader as XmlTextReader; - if (xmlTextReader == null) + if (reader is not XmlTextReader xmlTextReader) { - IXmlTextParser? xmlTextParser = reader as IXmlTextParser; - if (xmlTextParser != null) + if (reader is IXmlTextParser xmlTextParser) xmlTextParser.WhitespaceHandling = value; } else diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlSerializableReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlSerializableReader.cs index fd312d260f791..7d01b25c192b5 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlSerializableReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlSerializableReader.cs @@ -136,8 +136,7 @@ bool IXmlTextParser.Normalized } set { - IXmlTextParser? xmlTextParser = InnerReader as IXmlTextParser; - if (xmlTextParser == null) + if (InnerReader is not IXmlTextParser xmlTextParser) _xmlReader.Normalized = value; else xmlTextParser.Normalized = value; @@ -153,8 +152,7 @@ WhitespaceHandling IXmlTextParser.WhitespaceHandling } set { - IXmlTextParser? xmlTextParser = InnerReader as IXmlTextParser; - if (xmlTextParser == null) + if (InnerReader is not IXmlTextParser xmlTextParser) _xmlReader.WhitespaceHandling = value; else xmlTextParser.WhitespaceHandling = value; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs index 1337766eb1535..3158b1fd98619 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs @@ -138,8 +138,7 @@ public XmlQualifiedName GetSchemaTypeName(Type type) type = GetSurrogatedType(type); DataContract dataContract = DataContract.GetDataContract(type); DataContractSet.EnsureTypeNotGeneric(dataContract.UnderlyingType); - XmlDataContract? xmlDataContract = dataContract as XmlDataContract; - if (xmlDataContract != null && xmlDataContract.IsAnonymous) + if (dataContract is XmlDataContract xmlDataContract && xmlDataContract.IsAnonymous) return XmlQualifiedName.Empty; return dataContract.StableName; } @@ -152,8 +151,7 @@ public XmlQualifiedName GetSchemaTypeName(Type type) type = GetSurrogatedType(type); DataContract dataContract = DataContract.GetDataContract(type); DataContractSet.EnsureTypeNotGeneric(dataContract.UnderlyingType); - XmlDataContract? xmlDataContract = dataContract as XmlDataContract; - if (xmlDataContract != null && xmlDataContract.IsAnonymous) + if (dataContract is XmlDataContract xmlDataContract && xmlDataContract.IsAnonymous) return xmlDataContract.XsdType; return null; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlDictionaryReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlDictionaryReader.cs index 141f572e24bea..d065ef92957b4 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlDictionaryReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlDictionaryReader.cs @@ -1798,9 +1798,7 @@ public override object ReadContentAs(Type type, IXmlNamespaceResolver? namespace public bool HasLineInfo() { - IXmlLineInfo? lineInfo = _reader as IXmlLineInfo; - - if (lineInfo == null) + if (_reader is not IXmlLineInfo lineInfo) return false; return lineInfo.HasLineInfo(); @@ -1810,9 +1808,7 @@ public int LineNumber { get { - IXmlLineInfo? lineInfo = _reader as IXmlLineInfo; - - if (lineInfo == null) + if (_reader is not IXmlLineInfo lineInfo) return 1; return lineInfo.LineNumber; @@ -1823,9 +1819,7 @@ public int LinePosition { get { - IXmlLineInfo? lineInfo = _reader as IXmlLineInfo; - - if (lineInfo == null) + if (_reader is not IXmlLineInfo lineInfo) return 1; return lineInfo.LinePosition; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlDictionaryWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlDictionaryWriter.cs index 5fb9823249492..938eefb42fd03 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlDictionaryWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlDictionaryWriter.cs @@ -375,8 +375,7 @@ protected virtual void WriteTextNode(XmlDictionaryReader reader, bool isAttribut public override void WriteNode(XmlReader reader, bool defattr) { - XmlDictionaryReader? dictionaryReader = reader as XmlDictionaryReader; - if (dictionaryReader != null) + if (reader is XmlDictionaryReader dictionaryReader) WriteNode(dictionaryReader, defattr); else base.WriteNode(reader, defattr); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlExceptionHelper.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlExceptionHelper.cs index 7170d045183cf..8e0a939970998 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlExceptionHelper.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlExceptionHelper.cs @@ -31,8 +31,7 @@ private static void ThrowXmlException(XmlDictionaryReader reader, string res, st private static void ThrowXmlException(XmlDictionaryReader reader, string res, string? arg1, string? arg2, string? arg3) { string s = SR.Format(res, arg1, arg2, arg3); - IXmlLineInfo? lineInfo = reader as IXmlLineInfo; - if (lineInfo != null && lineInfo.HasLineInfo()) + if (reader is IXmlLineInfo lineInfo && lineInfo.HasLineInfo()) { s += " " + SR.Format(SR.XmlLineInfo, lineInfo.LineNumber, lineInfo.LinePosition); } @@ -44,8 +43,7 @@ private static void ThrowXmlException(XmlDictionaryReader reader, string res, st public static void ThrowXmlException(XmlDictionaryReader reader, XmlException exception) { string s = exception.Message; - IXmlLineInfo? lineInfo = reader as IXmlLineInfo; - if (lineInfo != null && lineInfo.HasLineInfo()) + if (reader is IXmlLineInfo lineInfo && lineInfo.HasLineInfo()) { s += " " + SR.Format(SR.XmlLineInfo, lineInfo.LineNumber, lineInfo.LinePosition); } diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj b/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj index 44030932998b5..4978d17e6576e 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj @@ -25,17 +25,12 @@ System.Runtime.Serialization.Schema.XsdDataContractImporter - - - - - diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs index fffcafed85a0f..d6639aefc5bc7 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs @@ -484,8 +484,7 @@ private static CodeTypeDeclaration CreateTypeDeclaration(string typeName, DataCo // System.Diagnostics.DebuggerStepThroughAttribute not allowed on enums // ensure that the attribute is only generated on types that are not enums - EnumDataContract? enumDataContract = dataContract as EnumDataContract; - if (enumDataContract == null) + if (dataContract is not EnumDataContract) { typeDecl.CustomAttributes.Add(debuggerStepThroughAttribute); } diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/Globals.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/Globals.cs index 22ad633b47dd7..cd7b0cb1b83e9 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/Globals.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/Globals.cs @@ -27,6 +27,7 @@ internal static class Globals public const string AnyTypeLocalName = "anyType"; public const string ArrayPrefix = "ArrayOf"; public const string ClrNamespaceProperty = "ClrNamespace"; + public const string CollectionsNamespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays"; public const string ContextFieldName = "context"; public const string CurrentPropertyName = "Current"; public const string DataContractXsdBaseNamespace = "http://schemas.datacontract.org/2004/07/"; diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs index fb07d8bc98286..532fd9c629c74 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs @@ -185,15 +185,15 @@ public XmlQualifiedName GetSchemaTypeName(Type type) type = GetSurrogatedType(type); DataContract dataContract = DataContract.GetDataContract(type); EnsureTypeNotGeneric(dataContract.UnderlyingType); - //if (dataContract.HasRoot) - //{ - // return new XmlQualifiedName(dataContract.TopLevelElementName!.Value, dataContract.TopLevelElementNamespace!.Value); - //} - // TODO smolloy - the above is now done with the new API below. - if (dataContract.GetRootElementName(out XmlQualifiedName? root)) + if (dataContract.HasRoot) { - return root; + return new XmlQualifiedName(dataContract.TopLevelElementName!.Value, dataContract.TopLevelElementNamespace!.Value); } + // TODO smolloy - the above is now done with the new API below. + //if (dataContract.GetRootElementName(out XmlQualifiedName? root)) + //{ + // return root; + //} else { return null; diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/_Stubs.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/_Stubs.cs index 5d584ce6ee897..f864eb893337b 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/_Stubs.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/_Stubs.cs @@ -10,7 +10,7 @@ using DataContractDictionary = System.Collections.Generic.Dictionary; -namespace System.Runtime.Serialization +namespace System.Runtime.Serialization.HideStubs { public sealed class DataContractSet { @@ -75,19 +75,30 @@ public class DataContract { // ======================================================================================================= // These existed internal in Core - public static bool IsTypeSerializable(Type type) { return false; } - public XmlQualifiedName StableName => XmlQualifiedName.Empty; public Type UnderlyingType => typeof(DataContract); + public Type OriginalUnderlyingType => UnderlyingType; + public XmlQualifiedName StableName { get => XmlQualifiedName.Empty; internal set { } } + public bool HasRoot { get; internal set; } + public bool IsBuiltInDataContract { get; } + public bool IsISerializable { get; internal set; } + public bool IsReference { get; internal set; } + public bool IsValueType { get; internal set; } + public XmlDictionaryString? TopLevelElementName { get; internal set; } + public XmlDictionaryString? TopLevelElementNamespace { get; internal set; } + public static bool IsTypeSerializable(Type type) { return false; } public static DataContract GetDataContract(Type type) { return new DataContract(); } public static DataContract? GetBuiltInDataContract(string name, string ns) { return null; } + public static XmlQualifiedName GetStableName(Type type) { return XmlQualifiedName.Empty; } // This API exists and is used internally. It can easily be copied externally if we want to reduce the API surface here. // But it's also a semi-logical exposure of a DC-intended static utility function. It makes sense to just expose and re-use it. public static string EncodeLocalName(string localName) { return "string"; } + public XmlQualifiedName GetArrayTypeName(bool isNullable) { return XmlQualifiedName.Empty; } // ======================================================================================================= // These existed internal in 4.8 and are brought back for schema support public GenericInfo? GenericInfo => null; + public DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) { return new DataContract(); } // ======================================================================================================= @@ -96,26 +107,6 @@ public class DataContract // This one - similar to a couple DCSet API's - allows us to keep surrogate execution logic internal to DC/DCSet. // Basically and entry to [surrogate_caller.GetDataContractType()] public static Type GetSurrogateType(ISerializationSurrogateProvider surrogateProvider, Type type) { return type; } - - // This is a new API that hides 'HasRoot', 'TopLevelElementName', and 'TopLevelElementNamespace' which already - // exist internally in Core. There are other places that use these properties though. Check those places to see - // if this new API works for them, or if it needs to be re-worked, or if we just stick with exposing those - // niche properties for niche cases. - // Upon further review, we don't even have to do a boolean/out pattern. We can just return - // something or null and our usage pattern here already flows like that. Maybe simplify this. - public bool GetRootElementName([NotNullWhen(true)] out XmlQualifiedName? rootElementName) { rootElementName = null; return false; } - - - // ======================================================================================================= - // More API's that need exposing - - // DataContract BindGenericParameters(DataContract[], Dictionary) - // XmlQualifiedName GetArrayTypeName(bool) - // XmlQualifiedName static GetStableName(Type t) {} - - // bool IsBuiltInDataContract - // bool IsValueType - // Type OriginalUnderlyingType } @@ -123,18 +114,18 @@ public class DataContract public class ClassDataContract : DataContract { // BaseContract - // IsISerializable - // IsReference - // IsValueType - // KnownDataContracts + // *IsISerializable + // *IsReference + // *IsValueType + // *KnownDataContracts // Members } public class CollectionDataContract : DataContract { - // IsCollection + // IsCollection() static - This could be on base DataContract // IsDictionary // IsItemTypeNullable - // IsReference + // *IsReference // ItemContract // ItemName // KeyName @@ -143,10 +134,11 @@ public class CollectionDataContract : DataContract public class EnumDataContract : DataContract { // BaseContractName - // GetBaseType - // GetStringFromEnumValue - // IsFlags + // GetBaseType << and ^^ can be combined into one Type GetType() + + // GetStringFromEnumValue() This is the one non-data item. Should we bring an enum-specific function up to DCBase? or perhaps this and IsUlong can go away if Values just returns int[] or string[] appropriately // IsULong + // IsFlags // Members // Values } @@ -156,12 +148,12 @@ public class XmlDataContract : DataContract // IsAnonymous // IsTopLevelElementNullable // IsTypeDefinedOnImport - // IsValueType + // *IsValueType // XsdType // These three are actually on DC itself. We worked around with a new API in one case. Can we use that for all cases? - // HasRoot - // TopLevelElementName - // TopLevelElementNamespace + // *HasRoot + // *TopLevelElementName + // *TopLevelElementNamespace } } diff --git a/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs b/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs index 6a3d406d81026..5becb86120c30 100644 --- a/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs +++ b/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs @@ -6,6 +6,45 @@ namespace System.Runtime.Serialization { + public abstract partial class DataContract + { + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public DataContract BindGenericParameters(DataContract[] paramContracts, System.Collections.Generic.Dictionary boundContracts) { throw null; } + internal DataContract(DataContractCriticalHelper helper) { } + internal const System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes DataContractPreserveMemberTypes = + System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods | + System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicMethods | + System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | + System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicConstructors | + System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | + System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties; + public static string EncodeLocalName(string localName) { throw null; } + public GenericInfo? GenericInfo { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public System.Xml.XmlQualifiedName GetArrayTypeName(bool isNullable) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public static DataContract? GetBuiltInDataContract(string name, string ns) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public static DataContract GetDataContract(Type type) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public static System.Xml.XmlQualifiedName GetStableName(Type type) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public static Type GetSurrogateType(ISerializationSurrogateProvider surrogateProvider, Type type) { throw null; } + public bool HasRoot { get { throw null; } } + public bool IsBuiltInDataContract { get { throw null; } } + public bool IsISerializable { get { throw null; } } + public bool IsReference { get { throw null; } } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public static bool IsTypeSerializable(Type type) { throw null; } + public bool IsValueType { get { throw null; } } + public Type OriginalUnderlyingType { get { throw null; } } + public System.Xml.XmlQualifiedName StableName { get { throw null; } } + [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(DataContract.DataContractPreserveMemberTypes)] + public Type UnderlyingType { get { throw null; } } + public System.Xml.XmlDictionaryString? TopLevelElementName { get { throw null; } } + public System.Xml.XmlDictionaryString? TopLevelElementNamespace { get { throw null; } } + } + internal abstract partial class DataContractCriticalHelper { } public abstract partial class DataContractResolver { protected DataContractResolver() { } @@ -75,6 +114,41 @@ public DataContractSerializerSettings() { } public System.Xml.XmlDictionaryString? RootNamespace { get { throw null; } set { } } public bool SerializeReadOnlyTypes { get { throw null; } set { } } } + public sealed partial class DataContractSet + { + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public void Add(Type type) { throw null; } + public static void CompileSchemaSet(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; } + public DataContractSet(ISerializationExtendedSurrogateProvider? dataContractExtendedSurrogate, System.Collections.Generic.ICollection? referencedTypes, System.Collections.Generic.ICollection? referencedCollectionTypes) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public DataContractSet(DataContractSet dataContractSet) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public void ExportSchemaSet(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public DataContract GetDataContract(Type type) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public DataContract? GetDataContract(System.Xml.XmlQualifiedName key) { throw null; } + public System.Collections.Generic.IEnumerator> GetEnumerator() { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public Type? GetReferencedTypeOnImport(DataContract dataContract) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public void ImportSchemaSet(System.Xml.Schema.XmlSchemaSet schemaSet, System.Collections.Generic.ICollection? typeNames, System.Collections.Generic.ICollection elements, System.Xml.XmlQualifiedName[] elementTypeNames, bool importXmlDataType) { throw null; } + public System.Collections.Generic.Dictionary? KnownTypesForObject { get { throw null; } } + public System.Collections.Generic.Dictionary ProcessedContracts { get { throw null; } } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public bool TryGetReferencedType(System.Xml.XmlQualifiedName stableName, DataContract? dataContract, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out Type? type) { throw null; } + public bool TryGetSurrogateData(object key, out object? value) { throw null; } + } + public sealed partial class DataMember + { + internal DataMember() { } + public bool EmitDefaultValue { get { throw null; } } + public bool IsNullable { get { throw null; } } + public bool IsRequired { get { throw null; } } + public DataContract MemberTypeContract { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } } + public string Name { get { throw null; } } + public int Order { get { throw null; } } + } public partial class ExportOptions { public ExportOptions() { } @@ -84,6 +158,14 @@ public sealed partial class ExtensionDataObject { internal ExtensionDataObject() { } } + public sealed partial class GenericInfo + { + internal GenericInfo() { } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public System.Xml.XmlQualifiedName GetExpandedStableName() { throw null; } + public System.Collections.Generic.IList? Parameters { get { throw null; } } + public System.Xml.XmlQualifiedName StableName { get { throw null; } } + } public partial interface IExtensibleDataObject { System.Runtime.Serialization.ExtensionDataObject? ExtensionData { get; set; } From 71d4ab4a6db050a5532889e307dc15fc436e9e2a Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Wed, 6 Jul 2022 22:34:27 -0700 Subject: [PATCH 05/33] All APIs in. --- .../src/Resources/Strings.resx | 1326 ----------------- .../Serialization/ClassDataContract.cs | 85 +- .../Serialization/CollectionDataContract.cs | 19 +- .../Runtime/Serialization/DataContract.cs | 22 +- .../Runtime/Serialization/DataContractSet.cs | 4 +- .../Runtime/Serialization/DataMember.cs | 10 +- .../Runtime/Serialization/EnumDataContract.cs | 51 +- .../Json/JsonFormatReaderGenerator.cs | 18 +- .../Json/JsonFormatWriterGenerator.cs | 12 +- .../Json/ReflectionJsonFormatWriter.cs | 4 +- .../Serialization/PrimitiveDataContract.cs | 3 + .../Serialization/ReflectionClassWriter.cs | 8 +- .../Runtime/Serialization/ReflectionReader.cs | 10 +- .../ReflectionXmlFormatReader.cs | 2 +- .../ReflectionXmlFormatWriter.cs | 6 +- .../Runtime/Serialization/SchemaExporter.cs | 10 +- .../Runtime/Serialization/SchemaImporter.cs | 28 +- .../Serialization/XPathQueryGenerator.cs | 4 +- .../Runtime/Serialization/XmlDataContract.cs | 21 +- .../Serialization/XmlFormatReaderGenerator.cs | 14 +- .../Serialization/XmlFormatWriterGenerator.cs | 14 +- .../Serialization/XmlObjectSerializer.cs | 4 +- ...System.Runtime.Serialization.Schema.csproj | 2 +- .../Serialization/Schema/CodeExporter.cs | 249 ++-- .../Serialization/Schema/SchemaHelper.cs | 53 + .../Schema/XsdDataContractExporter.cs | 8 +- .../Runtime/Serialization/Schema/_Stubs.cs | 15 +- .../ref/System.Runtime.Serialization.Xml.cs | 17 +- 28 files changed, 420 insertions(+), 1599 deletions(-) diff --git a/src/libraries/System.Private.DataContractSerialization/src/Resources/Strings.resx b/src/libraries/System.Private.DataContractSerialization/src/Resources/Strings.resx index cefa459d78bde..d2a7b88ce8b30 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/Resources/Strings.resx +++ b/src/libraries/System.Private.DataContractSerialization/src/Resources/Strings.resx @@ -1203,8 +1203,6 @@ Using surrogates with get-only collection properties is not supported. Consider removing the surrogate associated with '{0}' or adding a setter to '{1}.{2}'. - - The element cannot have 'abstract' set to 'true'. @@ -1400,1328 +1398,4 @@ Attributes must be optional and from namespace '{0}'. - - - - diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs index 36a0942744ab5..bad42886f0708 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs @@ -17,6 +17,9 @@ namespace System.Runtime.Serialization { internal sealed class ClassDataContract : DataContract { + internal const string ContractTypeString = "ClassDataContract"; + public override string? ContractType => ContractTypeString; + public XmlDictionaryString[]? ContractNamespaces; public XmlDictionaryString[]? MemberNames; @@ -48,16 +51,22 @@ private void InitClassDataContract() MemberNamespaces = _helper.MemberNamespaces; } - internal ClassDataContract? BaseContract + public override DataContract? BaseContract + { + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + get => BaseClassContract; + } + + internal ClassDataContract? BaseClassContract { - get => _helper.BaseContract; - set => _helper.BaseContract = value; + get => _helper.BaseClassContract; + set => _helper.BaseClassContract = value; } - internal List? Members + public override List? Members { get => _helper.Members; - set => _helper.Members = value; + internal set => _helper.Members = value; } public XmlDictionaryString?[]? ChildElementNamespaces @@ -95,7 +104,7 @@ public XmlDictionaryString?[]? ChildElementNamespaces internal MethodInfo? ExtensionDataSetMethod => _helper.ExtensionDataSetMethod; - internal override DataContractDictionary? KnownDataContracts + public override DataContractDictionary? KnownDataContracts { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get => _helper.KnownDataContracts; @@ -327,8 +336,8 @@ internal static bool IsNonAttributedTypeValidForSerialization( return null; XmlDictionaryString?[]? baseChildElementNamespaces = null; - if (BaseContract != null) - baseChildElementNamespaces = BaseContract.ChildElementNamespaces; + if (BaseClassContract != null) + baseChildElementNamespaces = BaseClassContract.ChildElementNamespaces; int baseChildElementNamespaceCount = (baseChildElementNamespaces != null) ? baseChildElementNamespaces.Length : 0; XmlDictionaryString?[] childElementNamespaces = new XmlDictionaryString?[Members.Count + baseChildElementNamespaceCount]; if (baseChildElementNamespaceCount > 0) @@ -384,7 +393,7 @@ internal bool RequiresMemberAccessForRead(SecurityException? securityException) } return true; } - if (BaseContract != null && BaseContract.RequiresMemberAccessForRead(securityException)) + if (BaseClassContract != null && BaseClassContract.RequiresMemberAccessForRead(securityException)) return true; if (ConstructorRequiresMemberAccess(GetISerializableConstructor())) @@ -498,7 +507,7 @@ internal bool RequiresMemberAccessForWrite(SecurityException? securityException) return true; } - if (BaseContract != null && BaseContract.RequiresMemberAccessForWrite(securityException)) + if (BaseClassContract != null && BaseClassContract.RequiresMemberAccessForWrite(securityException)) return true; if (MethodRequiresMemberAccess(OnSerializing)) @@ -630,14 +639,14 @@ internal ClassDataContractCriticalHelper([DynamicallyAccessedMembers(DataContrac DataContract baseContract = DataContract.GetDataContract(baseType); if (baseContract is CollectionDataContract collectionDC) { - BaseContract = collectionDC.SharedTypeContract as ClassDataContract; + BaseClassContract = collectionDC.SharedTypeContract as ClassDataContract; } else { - BaseContract = baseContract as ClassDataContract; + BaseClassContract = baseContract as ClassDataContract; } - if (BaseContract != null && BaseContract.IsNonAttributedType && !_isNonAttributedType) + if (BaseClassContract != null && BaseClassContract.IsNonAttributedType && !_isNonAttributedType) { throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError (new InvalidDataContractException(SR.Format(SR.AttributedTypesCannotInheritFromNonAttributedSerializableTypes, @@ -646,7 +655,7 @@ internal ClassDataContractCriticalHelper([DynamicallyAccessedMembers(DataContrac } else { - BaseContract = null; + BaseClassContract = null; } _hasExtensionData = (Globals.TypeOfIExtensibleDataObject.IsAssignableFrom(type)); @@ -669,7 +678,7 @@ internal ClassDataContractCriticalHelper([DynamicallyAccessedMembers(DataContrac int baseMemberCount = 0; int baseContractCount = 0; - if (BaseContract == null) + if (BaseClassContract == null) { MemberNames = new XmlDictionaryString[Members.Count]; MemberNamespaces = new XmlDictionaryString[Members.Count]; @@ -677,18 +686,18 @@ internal ClassDataContractCriticalHelper([DynamicallyAccessedMembers(DataContrac } else { - if (BaseContract.IsReadOnlyContract) + if (BaseClassContract.IsReadOnlyContract) { - _serializationExceptionMessage = BaseContract.SerialiazationExceptionMessage; + _serializationExceptionMessage = BaseClassContract.SerialiazationExceptionMessage; } - baseMemberCount = BaseContract.MemberNames!.Length; + baseMemberCount = BaseClassContract.MemberNames!.Length; MemberNames = new XmlDictionaryString[Members.Count + baseMemberCount]; - Array.Copy(BaseContract.MemberNames, MemberNames, baseMemberCount); + Array.Copy(BaseClassContract.MemberNames, MemberNames, baseMemberCount); MemberNamespaces = new XmlDictionaryString[Members.Count + baseMemberCount]; - Array.Copy(BaseContract.MemberNamespaces!, MemberNamespaces, baseMemberCount); - baseContractCount = BaseContract.ContractNamespaces!.Length; + Array.Copy(BaseClassContract.MemberNamespaces!, MemberNamespaces, baseMemberCount); + baseContractCount = BaseClassContract.ContractNamespaces!.Length; ContractNamespaces = new XmlDictionaryString[1 + baseContractCount]; - Array.Copy(BaseContract.ContractNamespaces, ContractNamespaces, baseContractCount); + Array.Copy(BaseClassContract.ContractNamespaces, ContractNamespaces, baseContractCount); } ContractNamespaces[baseContractCount] = Namespace; for (int i = 0; i < Members.Count; i++) @@ -728,11 +737,11 @@ private void EnsureIsReferenceImported(Type type) bool isReference = false; bool hasDataContractAttribute = TryGetDCAttribute(type, out DataContractAttribute? dataContractAttribute); - if (BaseContract != null) + if (BaseClassContract != null) { if (hasDataContractAttribute && dataContractAttribute!.IsReferenceSetExplicitly) { - bool baseIsReference = BaseContract.IsReference; + bool baseIsReference = BaseClassContract.IsReference; if ((baseIsReference && !dataContractAttribute.IsReference) || (!baseIsReference && dataContractAttribute.IsReference)) { @@ -740,8 +749,8 @@ private void EnsureIsReferenceImported(Type type) SR.Format(SR.InconsistentIsReference, DataContract.GetClrTypeFullName(type), dataContractAttribute.IsReference, - DataContract.GetClrTypeFullName(BaseContract.UnderlyingType), - BaseContract.IsReference), + DataContract.GetClrTypeFullName(BaseClassContract.UnderlyingType), + BaseClassContract.IsReference), type); } else @@ -751,7 +760,7 @@ private void EnsureIsReferenceImported(Type type) } else { - isReference = BaseContract.IsReference; + isReference = BaseClassContract.IsReference; } } else if (hasDataContractAttribute) @@ -950,7 +959,7 @@ private static bool SetIfGetOnlyCollection(DataMember memberContract, bool skipI private void SetIfMembersHaveConflict(List members) { - if (BaseContract == null) + if (BaseClassContract == null) return; int baseTypeIndex = 0; @@ -959,7 +968,7 @@ private void SetIfMembersHaveConflict(List members) { membersInHierarchy.Add(new Member(member, StableName!.Namespace, baseTypeIndex)); } - ClassDataContract? currContract = BaseContract; + ClassDataContract? currContract = BaseClassContract; while (currContract != null) { baseTypeIndex++; @@ -968,7 +977,7 @@ private void SetIfMembersHaveConflict(List members) { membersInHierarchy.Add(new Member(member, currContract.StableName!.Namespace, baseTypeIndex)); } - currContract = currContract.BaseContract; + currContract = currContract.BaseClassContract; } IComparer comparer = DataMemberConflictComparer.Singleton; @@ -1116,7 +1125,7 @@ private static bool IsValidCallback(MethodInfo method, ParameterInfo[] parameter return false; } - internal ClassDataContract? BaseContract + internal ClassDataContract? BaseClassContract { get => _baseContract; set @@ -1359,8 +1368,8 @@ public override DataContract BindGenericParameters(DataContract[] paramContracts ClassDataContract boundClassContract = new ClassDataContract(boundType); boundContracts.Add(this, boundClassContract); boundClassContract.StableName = CreateQualifiedName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(stableName.Name), new GenericNameProvider(DataContract.GetClrTypeFullName(UnderlyingType), genericParams)), stableName.Namespace); - if (BaseContract != null) - boundClassContract.BaseContract = (ClassDataContract)BaseContract.BindGenericParameters(paramContracts, boundContracts); + if (BaseClassContract != null) + boundClassContract.BaseClassContract = (ClassDataContract)BaseClassContract.BindGenericParameters(paramContracts, boundContracts); boundClassContract.IsISerializable = IsISerializable; boundClassContract.IsValueType = IsValueType; boundClassContract.IsReference = IsReference; @@ -1447,12 +1456,12 @@ internal override bool Equals(object? other, HashSet checke } } - if (BaseContract == null) - return (dataContract.BaseContract == null); - else if (dataContract.BaseContract == null) + if (BaseClassContract == null) + return (dataContract.BaseClassContract == null); + else if (dataContract.BaseClassContract == null) return false; else - return BaseContract.Equals(dataContract.BaseContract, checkedContracts); + return BaseClassContract.Equals(dataContract.BaseClassContract, checkedContracts); } } return false; @@ -1482,7 +1491,7 @@ public int Compare(DataMember? x, DataMember? y) if (x == null || y == null) return -1; - int orderCompare = x.Order - y.Order; + int orderCompare = (int)(x.Order - y.Order); if (orderCompare != 0) return orderCompare; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs index 4174e8a8c5db5..320e73d52d2f1 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs @@ -77,6 +77,9 @@ internal enum CollectionKind : byte internal sealed class CollectionDataContract : DataContract { + internal const string ContractTypeString = "CollectionDataContract"; + public override string? ContractType => ContractTypeString; + private XmlDictionaryString _collectionItemName; private XmlDictionaryString? _childElementNamespace; @@ -184,6 +187,20 @@ internal string? ValueName set => _helper.ValueName = value; } + public override bool IsKeyValue(out string? keyName, out string? valueName, out string? itemName) + { + keyName = KeyName; + valueName = ValueName; + itemName = ItemName; + return IsDictionary; + } + + public override DataContract BaseContract + { + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + get => ItemContract; + } + internal bool IsDictionary => KeyName != null; public XmlDictionaryString? ChildElementNamespace @@ -229,7 +246,7 @@ internal bool IsConstructorCheckRequired internal ConstructorInfo? Constructor => _helper.Constructor; - internal override DataContractDictionary? KnownDataContracts + public override DataContractDictionary? KnownDataContracts { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get => _helper.KnownDataContracts; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs index a05ef3fd2a952..c3d7f653c8f86 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs @@ -42,6 +42,8 @@ internal DataContract(DataContractCriticalHelper helper) _ns = helper.Namespace; } + public virtual string? ContractType => null; + internal MethodInfo? ParseMethod => _helper.ParseMethod; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -199,6 +201,12 @@ public virtual XmlQualifiedName StableName internal set => _helper.StableName = value; } + public virtual DataContract? BaseContract + { + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + get => null; + } + public virtual GenericInfo? GenericInfo { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -206,7 +214,7 @@ public virtual GenericInfo? GenericInfo internal set => _helper.GenericInfo = value; } - internal virtual DataContractDictionary? KnownDataContracts + public virtual DataContractDictionary? KnownDataContracts { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get => _helper.KnownDataContracts; @@ -245,6 +253,18 @@ public virtual XmlDictionaryString? TopLevelElementNamespace internal virtual bool IsPrimitive => false; + public virtual bool IsKeyValue(out string? keyName, out string? valueName, out string? itemName) + { + keyName = valueName = itemName = null; + return false; + } + + public virtual List? Members + { + get => null; + internal set { } + } + internal virtual void WriteRootElement(XmlWriterDelegator writer, XmlDictionaryString name, XmlDictionaryString? ns) { if (object.ReferenceEquals(ns, DictionaryGlobals.SerializationNamespace) && !IsPrimitive) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs index 520b1e51364f8..06fee1988e97b 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs @@ -133,9 +133,9 @@ internal void InternalAdd(XmlQualifiedName name, DataContract dataContract) [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private void AddClassDataContract(ClassDataContract classDataContract) { - if (classDataContract.BaseContract != null) + if (classDataContract.BaseClassContract != null) { - Add(classDataContract.BaseContract.StableName, classDataContract.BaseContract); + Add(classDataContract.BaseClassContract.StableName, classDataContract.BaseClassContract); } if (!classDataContract.IsISerializable) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs index 66995ae4345b2..15971d3a8845a 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs @@ -17,7 +17,7 @@ internal DataMember(MemberInfo memberInfo) _helper = new CriticalHelper(memberInfo); } - internal DataMember(DataContract memberTypeContract, string name, bool isNullable, bool isRequired, bool emitDefaultValue, int order) + internal DataMember(DataContract memberTypeContract, string name, bool isNullable, bool isRequired, bool emitDefaultValue, long order) { _helper = new CriticalHelper(memberTypeContract, name, isNullable, isRequired, emitDefaultValue, order); } @@ -30,7 +30,7 @@ public string Name internal set => _helper.Name = value; } - public int Order + public long Order { get => _helper.Order; internal set => _helper.Order = value; @@ -96,7 +96,7 @@ private sealed class CriticalHelper { private DataContract? _memberTypeContract; private string _name = null!; // Name is always initialized right after construction - private int _order; + private long _order; private bool _isRequired; private bool _emitDefaultValue; private bool _isNullable; @@ -113,7 +113,7 @@ internal CriticalHelper(MemberInfo memberInfo) _memberPrimitiveContract = PrimitiveDataContract.NullContract; } - internal CriticalHelper(DataContract memberTypeContract, string name, bool isNullable, bool isRequired, bool emitDefaultValue, int order) + internal CriticalHelper(DataContract memberTypeContract, string name, bool isNullable, bool isRequired, bool emitDefaultValue, long order) { _memberTypeContract = memberTypeContract; _name = name; @@ -132,7 +132,7 @@ internal string Name set => _name = value; } - internal int Order + internal long Order { get => _order; set => _order = value; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs index 5b1480e7befa2..cab5cf7b03106 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs @@ -14,6 +14,9 @@ namespace System.Runtime.Serialization { internal sealed class EnumDataContract : DataContract { + internal const string ContractTypeString = "EnumDataContract"; + public override string? ContractType => ContractTypeString; + private readonly EnumDataContractCriticalHelper _helper; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -27,16 +30,24 @@ internal EnumDataContract(Type type) : base(new EnumDataContractCriticalHelper(t return EnumDataContractCriticalHelper.GetBaseType(baseContractName); } + public override DataContract BaseContract + { + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + get => _helper.BaseContract; + } + public XmlQualifiedName BaseContractName { get => _helper.BaseContractName; + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] set => _helper.BaseContractName = value; } - public List Members + [NotNull] + public override List? Members { get => _helper.Members; - set => _helper.Members = value; + internal set => _helper.Members = value!; } public List? Values @@ -62,7 +73,7 @@ private sealed class EnumDataContractCriticalHelper : DataContract.DataContractC private static readonly Dictionary s_typeToName = new Dictionary(); private static readonly Dictionary s_nameToType = new Dictionary(); - private XmlQualifiedName _baseContractName; + private DataContract _baseContract; private List _members; private List? _values; private bool _isULong; @@ -72,14 +83,14 @@ private sealed class EnumDataContractCriticalHelper : DataContract.DataContractC static EnumDataContractCriticalHelper() { - Add(typeof(sbyte), "byte"); - Add(typeof(byte), "unsignedByte"); - Add(typeof(short), "short"); - Add(typeof(ushort), "unsignedShort"); - Add(typeof(int), "int"); - Add(typeof(uint), "unsignedInt"); - Add(typeof(long), "long"); - Add(typeof(ulong), "unsignedLong"); + Add(typeof(sbyte), DictionaryGlobals.SignedByteLocalName.Value); // "byte" + Add(typeof(byte), DictionaryGlobals.UnsignedByteLocalName.Value); // "unsignedByte" + Add(typeof(short), DictionaryGlobals.ShortLocalName.Value); // "short" + Add(typeof(ushort), DictionaryGlobals.UnsignedShortLocalName.Value); // "unsignedShort" + Add(typeof(int), DictionaryGlobals.IntLocalName.Value); // "int" + Add(typeof(uint), DictionaryGlobals.UnsignedIntLocalName.Value); // "unsignedInt" + Add(typeof(long), DictionaryGlobals.LongLocalName.Value); // "long" + Add(typeof(ulong), DictionaryGlobals.UnsignedLongLocalName.Value); // "unsignedLong" } internal static void Add(Type type, string localName) @@ -110,7 +121,10 @@ internal EnumDataContractCriticalHelper( { StableName = DataContract.GetStableName(type, out _hasDataContract); Type baseType = Enum.GetUnderlyingType(type); - _baseContractName = GetBaseContractName(baseType); + XmlQualifiedName baseTypeName = GetBaseContractName(baseType); + _baseContract = DataContract.GetBuiltInDataContract(baseTypeName.Name, baseTypeName.Namespace)!; + // TODO smolloy - Setting StableName might be redundant. But I don't want to miss an edge case. + _baseContract.StableName = baseTypeName; ImportBaseType(baseType); IsFlags = type.IsDefined(Globals.TypeOfFlagsAttribute, false); ImportDataMembers(); @@ -135,18 +149,23 @@ internal EnumDataContractCriticalHelper( } } + internal DataContract BaseContract => _baseContract; + internal XmlQualifiedName BaseContractName { - get => _baseContractName; + get => _baseContract.StableName; + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] set { - _baseContractName = value; - Type? baseType = GetBaseType(_baseContractName); + Type? baseType = GetBaseType(value); if (baseType == null) ThrowInvalidDataContractException( SR.Format(SR.InvalidEnumBaseType, value.Name, value.Namespace, StableName.Name, StableName.Namespace)); ImportBaseType(baseType); + _baseContract = DataContract.GetBuiltInDataContract(value.Name, value.Namespace)!; + // TODO smolloy - Setting StableName might be redundant. But I don't want to miss an edge case. + _baseContract.StableName = value; } } @@ -216,6 +235,7 @@ private void ImportDataMembers() } else memberContract.Name = field.Name; + memberContract.Order = _isULong ? (long)Convert.ToUInt64(field.GetValue(null)) : Convert.ToInt64(field.GetValue(null)); ClassDataContract.CheckAndAddMember(tempMembers, memberContract, memberValuesTable); enumMemberValid = true; } @@ -229,6 +249,7 @@ private void ImportDataMembers() if (!field.IsNotSerialized) { DataMember memberContract = new DataMember(field) { Name = field.Name }; + memberContract.Order = _isULong ? (long)Convert.ToUInt64(field.GetValue(null)) : Convert.ToInt64(field.GetValue(null)); ClassDataContract.CheckAndAddMember(tempMembers, memberContract, memberValuesTable); enumMemberValid = true; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs index a835648fb74a0..177aba2e87060 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs @@ -222,8 +222,8 @@ private void CreateObject(ClassDataContract classContract) private void InvokeOnDeserializing(ClassDataContract classContract) { - if (classContract.BaseContract != null) - InvokeOnDeserializing(classContract.BaseContract); + if (classContract.BaseClassContract != null) + InvokeOnDeserializing(classContract.BaseClassContract); if (classContract.OnDeserializing != null) { _ilg.LoadAddress(_objectLocal); @@ -236,8 +236,8 @@ private void InvokeOnDeserializing(ClassDataContract classContract) private void InvokeOnDeserialized(ClassDataContract classContract) { - if (classContract.BaseContract != null) - InvokeOnDeserialized(classContract.BaseContract); + if (classContract.BaseClassContract != null) + InvokeOnDeserialized(classContract.BaseClassContract); if (classContract.OnDeserialized != null) { _ilg.LoadAddress(_objectLocal); @@ -285,7 +285,7 @@ private void ReadClass(ClassDataContract classContract) MethodInfo? extensionDataSetMethod = currentContract.ExtensionDataSetMethod; if (extensionDataSetMethod != null) _ilg.Call(_objectLocal, extensionDataSetMethod, extensionDataLocal); - currentContract = currentContract.BaseContract; + currentContract = currentContract.BaseClassContract; } } else @@ -346,8 +346,8 @@ private void ReadMembers(ClassDataContract classContract, LocalBuilder? extensio private int ReadMembers(ClassDataContract classContract, BitFlagsGenerator expectedElements, Label[] memberLabels, Label throwDuplicateMemberLabel, LocalBuilder memberIndexLocal) { - int memberCount = (classContract.BaseContract == null) ? 0 : - ReadMembers(classContract.BaseContract, expectedElements, memberLabels, throwDuplicateMemberLabel, memberIndexLocal); + int memberCount = (classContract.BaseClassContract == null) ? 0 : + ReadMembers(classContract.BaseClassContract, expectedElements, memberLabels, throwDuplicateMemberLabel, memberIndexLocal); for (int i = 0; i < classContract.Members!.Count; i++, memberCount++) { @@ -409,8 +409,8 @@ private void LoadArray(byte[] array, string name) private int SetRequiredElements(ClassDataContract contract, byte[] requiredElements) { - int memberCount = (contract.BaseContract == null) ? 0 : - SetRequiredElements(contract.BaseContract, requiredElements); + int memberCount = (contract.BaseClassContract == null) ? 0 : + SetRequiredElements(contract.BaseClassContract, requiredElements); List members = contract.Members!; for (int i = 0; i < members.Count; i++, memberCount++) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs index 9a7797a9882f4..f3263d067c13e 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs @@ -167,8 +167,8 @@ private void ThrowIfCannotSerializeReadOnlyTypes(PropertyInfo serializationExcep private void InvokeOnSerializing(ClassDataContract classContract) { - if (classContract.BaseContract != null) - InvokeOnSerializing(classContract.BaseContract); + if (classContract.BaseClassContract != null) + InvokeOnSerializing(classContract.BaseClassContract); if (classContract.OnSerializing != null) { _ilg.LoadAddress(_objectLocal); @@ -180,8 +180,8 @@ private void InvokeOnSerializing(ClassDataContract classContract) private void InvokeOnSerialized(ClassDataContract classContract) { - if (classContract.BaseContract != null) - InvokeOnSerialized(classContract.BaseContract); + if (classContract.BaseClassContract != null) + InvokeOnSerialized(classContract.BaseClassContract); if (classContract.OnSerialized != null) { _ilg.LoadAddress(_objectLocal); @@ -223,8 +223,8 @@ private void WriteClass(ClassDataContract classContract) [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private int WriteMembers(ClassDataContract classContract, LocalBuilder? extensionDataLocal, ClassDataContract derivedMostClassContract) { - int memberCount = (classContract.BaseContract == null) ? 0 : - WriteMembers(classContract.BaseContract, extensionDataLocal, derivedMostClassContract); + int memberCount = (classContract.BaseClassContract == null) ? 0 : + WriteMembers(classContract.BaseClassContract, extensionDataLocal, derivedMostClassContract); int classMemberCount = classContract.Members!.Count; _ilg.Call(thisObj: _contextArg, XmlFormatGeneratorStatics.IncrementItemCountMethod, classMemberCount); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatWriter.cs index 3a924362045b9..a2cc3eed509ef 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatWriter.cs @@ -198,8 +198,8 @@ protected override int ReflectionWriteMembers(XmlWriterDelegator xmlWriter, obje { Debug.Assert(memberNames != null); - int memberCount = (classContract.BaseContract == null) ? 0 : - ReflectionWriteMembers(xmlWriter, obj, context, classContract.BaseContract, derivedMostClassContract, childElementIndex, memberNames); + int memberCount = (classContract.BaseClassContract == null) ? 0 : + ReflectionWriteMembers(xmlWriter, obj, context, classContract.BaseClassContract, derivedMostClassContract, childElementIndex, memberNames); childElementIndex += memberCount; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs index 32fd5bf73c43d..b6a305f376da9 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs @@ -13,6 +13,9 @@ namespace System.Runtime.Serialization { internal abstract class PrimitiveDataContract : DataContract { + internal const string ContractTypeString = "PrimitiveDataContract"; + public override string? ContractType => ContractTypeString; + internal static readonly PrimitiveDataContract NullContract = new NullPrimitiveDataContract(); private readonly PrimitiveDataContractCriticalHelper _helper; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionClassWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionClassWriter.cs index a8df2b1d0ca3f..a2c462953ba1f 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionClassWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionClassWriter.cs @@ -124,8 +124,8 @@ protected static bool ReflectionTryWritePrimitive(XmlWriterDelegator xmlWriter, private void InvokeOnSerializing(object obj, XmlObjectSerializerWriteContext context, ClassDataContract classContract) { - if (classContract.BaseContract != null) - InvokeOnSerializing(obj, context, classContract.BaseContract); + if (classContract.BaseClassContract != null) + InvokeOnSerializing(obj, context, classContract.BaseClassContract); if (classContract.OnSerializing != null) { var contextArg = context.GetStreamingContext(); @@ -135,8 +135,8 @@ private void InvokeOnSerializing(object obj, XmlObjectSerializerWriteContext con private void InvokeOnSerialized(object obj, XmlObjectSerializerWriteContext context, ClassDataContract classContract) { - if (classContract.BaseContract != null) - InvokeOnSerialized(obj, context, classContract.BaseContract); + if (classContract.BaseClassContract != null) + InvokeOnSerialized(obj, context, classContract.BaseClassContract); if (classContract.OnSerialized != null) { var contextArg = context.GetStreamingContext(); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs index 319fb0fdbfb37..d895befacdecb 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs @@ -197,7 +197,7 @@ protected virtual bool ReflectionReadSpecialCollection(XmlReaderDelegator xmlRea protected int ReflectionGetMembers(ClassDataContract classContract, DataMember[] members) { - int memberCount = (classContract.BaseContract == null) ? 0 : ReflectionGetMembers(classContract.BaseContract, members); + int memberCount = (classContract.BaseClassContract == null) ? 0 : ReflectionGetMembers(classContract.BaseClassContract, members); int childElementIndex = memberCount; for (int i = 0; i < classContract.Members!.Count; i++, memberCount++) { @@ -377,8 +377,8 @@ private static void ReflectionSetMemberValue(ref object obj, object? memberValue private void InvokeOnDeserializing(XmlObjectSerializerReadContext context, ClassDataContract classContract, object obj) { - if (classContract.BaseContract != null) - InvokeOnDeserializing(context, classContract.BaseContract, obj); + if (classContract.BaseClassContract != null) + InvokeOnDeserializing(context, classContract.BaseClassContract, obj); if (classContract.OnDeserializing != null) { var contextArg = context.GetStreamingContext(); @@ -388,8 +388,8 @@ private void InvokeOnDeserializing(XmlObjectSerializerReadContext context, Class private void InvokeOnDeserialized(XmlObjectSerializerReadContext context, ClassDataContract classContract, object obj) { - if (classContract.BaseContract != null) - InvokeOnDeserialized(context, classContract.BaseContract, obj); + if (classContract.BaseClassContract != null) + InvokeOnDeserialized(context, classContract.BaseClassContract, obj); if (classContract.OnDeserialized != null) { var contextArg = context.GetStreamingContext(); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatReader.cs index 98e3c1ea9a4ff..63572bd37dc26 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatReader.cs @@ -135,7 +135,7 @@ private bool[] GetRequiredMembers(ClassDataContract contract, out int firstRequi private int GetRequiredMembers(ClassDataContract contract, bool[] requiredMembers) { - int memberCount = (contract.BaseContract == null) ? 0 : GetRequiredMembers(contract.BaseContract, requiredMembers); + int memberCount = (contract.BaseClassContract == null) ? 0 : GetRequiredMembers(contract.BaseClassContract, requiredMembers); List members = contract.Members!; for (int i = 0; i < members.Count; i++, memberCount++) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatWriter.cs index 35916664cae7b..204d4cb8c15fb 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatWriter.cs @@ -131,8 +131,8 @@ internal sealed class ReflectionXmlClassWriter : ReflectionClassWriter [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] protected override int ReflectionWriteMembers(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext context, ClassDataContract classContract, ClassDataContract derivedMostClassContract, int childElementIndex, XmlDictionaryString[]? emptyStringArray) { - int memberCount = (classContract.BaseContract == null) ? 0 : - ReflectionWriteMembers(xmlWriter, obj, context, classContract.BaseContract, derivedMostClassContract, childElementIndex, emptyStringArray); + int memberCount = (classContract.BaseClassContract == null) ? 0 : + ReflectionWriteMembers(xmlWriter, obj, context, classContract.BaseClassContract, derivedMostClassContract, childElementIndex, emptyStringArray); childElementIndex += memberCount; @@ -243,7 +243,7 @@ private static bool CheckIfMemberHasConflict(DataMember member, ClassDataContrac return CheckIfConflictingMembersHaveDifferentTypes(members[j]); } } - currentContract = currentContract.BaseContract; + currentContract = currentContract.BaseClassContract; } return false; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs index 7d1881dc5be98..fbc73634fb3f8 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs @@ -149,11 +149,11 @@ private void ExportClassDataContract(ClassDataContract classDataContract, XmlSch } XmlElement? isValueTypeElement = null; - if (classDataContract.BaseContract != null) + if (classDataContract.BaseClassContract != null) { - XmlSchemaComplexContentExtension extension = CreateTypeContent(type, classDataContract.BaseContract.StableName, schema); + XmlSchemaComplexContentExtension extension = CreateTypeContent(type, classDataContract.BaseClassContract.StableName, schema); extension.Particle = rootSequence; - if (classDataContract.IsReference && !classDataContract.BaseContract.IsReference) + if (classDataContract.IsReference && !classDataContract.BaseClassContract.IsReference) { AddReferenceAttributes(extension.Attributes, schema); } @@ -461,9 +461,9 @@ private void ExportISerializableDataContract(ClassDataContract dataContract, Xml genericInfoElement = ExportGenericInfo(dataContract.UnderlyingType, Globals.GenericTypeLocalName, Globals.SerializationNamespace); XmlElement? isValueTypeElement = null; - if (dataContract.BaseContract != null) + if (dataContract.BaseClassContract != null) { - _ = CreateTypeContent(type, dataContract.BaseContract.StableName, schema); + _ = CreateTypeContent(type, dataContract.BaseClassContract.StableName, schema); } else { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs index f754b033f3819..559c89462151a 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs @@ -520,11 +520,11 @@ private void RemoveFailedContract(XmlQualifiedName typeName) _dataContractSet.Remove(typeName); if (oldContract != null) { - ClassDataContract? ancestorDataContract = oldContract.BaseContract; + ClassDataContract? ancestorDataContract = oldContract.BaseClassContract; while (ancestorDataContract != null) { ancestorDataContract.KnownDataContracts?.Remove(typeName); - ancestorDataContract = ancestorDataContract.BaseContract; + ancestorDataContract = ancestorDataContract.BaseClassContract; } if (_dataContractSet.KnownTypesForObject != null) _dataContractSet.KnownTypesForObject.Remove(typeName); @@ -652,15 +652,15 @@ private ClassDataContract ImportClass(XmlQualifiedName typeName, XmlSchemaSequen if (baseTypeName != null) { ImportBaseContract(baseTypeName, dataContract); - Debug.Assert(dataContract.BaseContract != null); // ImportBaseContract will always set this... or throw. - if (dataContract.BaseContract.IsISerializable) + Debug.Assert(dataContract.BaseClassContract != null); // ImportBaseContract will always set this... or throw. + if (dataContract.BaseClassContract.IsISerializable) { if (IsISerializableDerived(typeName, rootSequence)) dataContract.IsISerializable = true; else ThrowTypeCannotBeImportedException(dataContract.StableName.Name, dataContract.StableName.Namespace, SR.Format(SR.DerivedTypeNotISerializable, baseTypeName.Name, baseTypeName.Namespace)); } - if (dataContract.BaseContract.IsReference) + if (dataContract.BaseClassContract.IsReference) { dataContract.IsReference = true; } @@ -707,6 +707,7 @@ private DataContract ImportXmlDataType(XmlQualifiedName typeName, XmlSchemaType } else { + // TODO smolloy - I think this might be dead code. It doesn't appear like xsdType can be null in this method. //Value type can be used by both nillable and non-nillable elements but reference type cannot be used by non nillable elements xmlDataContract.IsValueType = true; xmlDataContract.IsTypeDefinedOnImport = false; @@ -828,8 +829,8 @@ private ClassDataContract ImportISerializable(XmlQualifiedName typeName, XmlSche else { ImportBaseContract(baseTypeName, dataContract); - Debug.Assert(dataContract.BaseContract != null); // ImportBaseContract will always set this... or throw. - if (!dataContract.BaseContract.IsISerializable) + Debug.Assert(dataContract.BaseClassContract != null); // ImportBaseContract will always set this... or throw. + if (!dataContract.BaseClassContract.IsISerializable) ThrowISerializableTypeCannotBeImportedException(dataContract.StableName.Name, dataContract.StableName.Namespace, SR.Format(SR.BaseTypeNotISerializable, baseTypeName.Name, baseTypeName.Namespace)); if (!IsISerializableDerived(typeName, rootSequence)) ThrowISerializableTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ISerializableDerivedContainsOneOrMoreItems)); @@ -910,10 +911,10 @@ private void ImportBaseContract(XmlQualifiedName baseTypeName, ClassDataContract ancestorDataContract.KnownDataContracts = knownDataContracts; } knownDataContracts.Add(dataContract.StableName, dataContract); - ancestorDataContract = ancestorDataContract.BaseContract; + ancestorDataContract = ancestorDataContract.BaseClassContract; } - dataContract.BaseContract = baseContract; + dataContract.BaseClassContract = baseContract; } private void ImportTopLevelElement(XmlQualifiedName typeName) @@ -1205,11 +1206,10 @@ private EnumDataContract ImportEnum(XmlQualifiedName typeName, XmlSchemaSimpleTy ThrowEnumTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.EnumEnumerationFacetsMustHaveValue)); string? valueInnerText = GetInnerText(typeName, ImportAnnotation(enumFacet.Annotation, SchemaExporter.EnumerationValueAnnotationName)); - if (valueInnerText == null) - dataContract.Values.Add(SchemaExporter.GetDefaultEnumValue(isFlags, dataContract.Members.Count)); - else - dataContract.Values.Add(dataContract.GetEnumValueFromString(valueInnerText)); - DataMember dataMember = new DataMember(Globals.SchemaMemberInfoPlaceholder) { Name = enumFacet.Value }; + long enumValue = (valueInnerText == null) ? SchemaExporter.GetDefaultEnumValue(isFlags, dataContract.Members.Count) + : dataContract.GetEnumValueFromString(valueInnerText); + dataContract.Values.Add(enumValue); + DataMember dataMember = new DataMember(Globals.SchemaMemberInfoPlaceholder) { Name = enumFacet.Value, Order = enumValue }; dataContract.Members.Add(dataMember); } return dataContract; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XPathQueryGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XPathQueryGenerator.cs index 364038c247a3e..469685278a86f 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XPathQueryGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XPathQueryGenerator.cs @@ -80,9 +80,9 @@ private static DataContract ProcessClassDataContract(ClassDataContract contract, private static IEnumerable GetDataMembers(ClassDataContract contract) { - if (contract.BaseContract != null) + if (contract.BaseClassContract != null) { - foreach (DataMember baseClassMember in GetDataMembers(contract.BaseContract)) + foreach (DataMember baseClassMember in GetDataMembers(contract.BaseClassContract)) { yield return baseClassMember; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs index aa78c06a943d7..9e4e6921e284c 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs @@ -17,8 +17,11 @@ namespace System.Runtime.Serialization { internal delegate IXmlSerializable CreateXmlSerializableDelegate(); - internal sealed class XmlDataContract : DataContract + public sealed class XmlDataContract : DataContract { + internal const string ContractTypeString = "XmlDataContract"; + public override string? ContractType => ContractTypeString; + private readonly XmlDataContractCriticalHelper _helper; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -27,24 +30,26 @@ internal XmlDataContract(Type type) : base(new XmlDataContractCriticalHelper(typ _helper = (base.Helper as XmlDataContractCriticalHelper)!; } - internal override DataContractDictionary? KnownDataContracts + public override DataContractDictionary? KnownDataContracts { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get => _helper.KnownDataContracts; set => _helper.KnownDataContracts = value; } - internal XmlSchemaType? XsdType + public XmlSchemaType? XsdType { get => _helper.XsdType; - set => _helper.XsdType = value; + internal set => _helper.XsdType = value; } - internal bool IsAnonymous + public bool IsAnonymous { get => _helper.IsAnonymous; } + public void SetIsValueType(bool isValueType) => IsValueType = isValueType; + public override bool HasRoot { get => _helper.HasRoot; @@ -63,13 +68,13 @@ public override XmlDictionaryString? TopLevelElementNamespace internal set => _helper.TopLevelElementNamespace = value; } - internal bool IsTopLevelElementNullable + public bool IsTopLevelElementNullable { get => _helper.IsTopLevelElementNullable; - set => _helper.IsTopLevelElementNullable = value; + internal set => _helper.IsTopLevelElementNullable = value; } - internal bool IsTypeDefinedOnImport + public bool IsTypeDefinedOnImport { get => _helper.IsTypeDefinedOnImport; set => _helper.IsTypeDefinedOnImport = value; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs index e2bf095b7e236..eab43fba40bde 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs @@ -281,8 +281,8 @@ private void InvokeOnDeserializing(ClassDataContract classContract) Debug.Assert(_objectLocal != null); Debug.Assert(_objectType != null); - if (classContract.BaseContract != null) - InvokeOnDeserializing(classContract.BaseContract); + if (classContract.BaseClassContract != null) + InvokeOnDeserializing(classContract.BaseClassContract); if (classContract.OnDeserializing != null) { _ilg.LoadAddress(_objectLocal); @@ -298,8 +298,8 @@ private void InvokeOnDeserialized(ClassDataContract classContract) Debug.Assert(_objectLocal != null); Debug.Assert(_objectType != null); - if (classContract.BaseContract != null) - InvokeOnDeserialized(classContract.BaseContract); + if (classContract.BaseClassContract != null) + InvokeOnDeserialized(classContract.BaseClassContract); if (classContract.OnDeserialized != null) { _ilg.LoadAddress(_objectLocal); @@ -349,7 +349,7 @@ private void ReadClass(ClassDataContract classContract) MethodInfo? extensionDataSetMethod = currentContract.ExtensionDataSetMethod; if (extensionDataSetMethod != null) _ilg.Call(_objectLocal, extensionDataSetMethod, extensionDataLocal); - currentContract = currentContract.BaseContract; + currentContract = currentContract.BaseClassContract; } } else @@ -403,7 +403,7 @@ private int ReadMembers(ClassDataContract classContract, bool[] requiredMembers, Debug.Assert(_objectLocal != null); Debug.Assert(_objectType != null); - int memberCount = (classContract.BaseContract == null) ? 0 : ReadMembers(classContract.BaseContract, requiredMembers, + int memberCount = (classContract.BaseClassContract == null) ? 0 : ReadMembers(classContract.BaseClassContract, requiredMembers, memberLabels, memberIndexLocal, requiredIndexLocal); for (int i = 0; i < classContract.Members!.Count; i++, memberCount++) @@ -461,7 +461,7 @@ private bool[] GetRequiredMembers(ClassDataContract contract, out int firstRequi private int GetRequiredMembers(ClassDataContract contract, bool[] requiredMembers) { - int memberCount = (contract.BaseContract == null) ? 0 : GetRequiredMembers(contract.BaseContract, requiredMembers); + int memberCount = (contract.BaseClassContract == null) ? 0 : GetRequiredMembers(contract.BaseClassContract, requiredMembers); List members = contract.Members!; for (int i = 0; i < members.Count; i++, memberCount++) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs index ee38570e49528..0e984e1a3adb3 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs @@ -199,8 +199,8 @@ private void ThrowIfCannotSerializeReadOnlyTypes(PropertyInfo serializationExcep private void InvokeOnSerializing(ClassDataContract classContract) { - if (classContract.BaseContract != null) - InvokeOnSerializing(classContract.BaseContract); + if (classContract.BaseClassContract != null) + InvokeOnSerializing(classContract.BaseClassContract); if (classContract.OnSerializing != null) { _ilg.LoadAddress(_objectLocal); @@ -212,8 +212,8 @@ private void InvokeOnSerializing(ClassDataContract classContract) private void InvokeOnSerialized(ClassDataContract classContract) { - if (classContract.BaseContract != null) - InvokeOnSerialized(classContract.BaseContract); + if (classContract.BaseClassContract != null) + InvokeOnSerialized(classContract.BaseClassContract); if (classContract.OnSerialized != null) { _ilg.LoadAddress(_objectLocal); @@ -279,8 +279,8 @@ private void WriteClass(ClassDataContract classContract) [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private int WriteMembers(ClassDataContract classContract, LocalBuilder? extensionDataLocal, ClassDataContract derivedMostClassContract) { - int memberCount = (classContract.BaseContract == null) ? 0 : - WriteMembers(classContract.BaseContract, extensionDataLocal, derivedMostClassContract); + int memberCount = (classContract.BaseClassContract == null) ? 0 : + WriteMembers(classContract.BaseClassContract, extensionDataLocal, derivedMostClassContract); LocalBuilder namespaceLocal = _ilg.DeclareLocal(typeof(XmlDictionaryString), "ns"); if (_contractNamespacesLocal == null) @@ -794,7 +794,7 @@ private static bool CheckIfMemberHasConflict(DataMember member, ClassDataContrac return CheckIfConflictingMembersHaveDifferentTypes(members[j]); } } - currentContract = currentContract.BaseContract; + currentContract = currentContract.BaseClassContract; } return false; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializer.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializer.cs index 5e300472c8a6e..c42bc3bb61893 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializer.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializer.cs @@ -378,12 +378,12 @@ internal static bool IsRootElement(XmlReaderDelegator reader, DataContract contr ClassDataContract? classContract = contract as ClassDataContract; if (classContract != null) - classContract = classContract.BaseContract; + classContract = classContract.BaseClassContract; while (classContract != null) { if (reader.IsStartElement(classContract.TopLevelElementName!, classContract.TopLevelElementNamespace!)) return true; - classContract = classContract.BaseContract; + classContract = classContract.BaseClassContract; } if (classContract == null) { diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj b/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj index 4978d17e6576e..499fe0bd091bf 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj @@ -26,7 +26,7 @@ System.Runtime.Serialization.Schema.XsdDataContractImporter - + diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs index d6639aefc5bc7..cb9ae0f641d07 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs @@ -51,7 +51,7 @@ internal CodeExporter(DataContractSet dataContractSet, ImportOptions? options, C foreach (KeyValuePair pair in dataContractSet) { DataContract dataContract = pair.Value; - if (!(dataContract.IsBuiltInDataContract || dataContract is CollectionDataContract)) + if (!(dataContract.IsBuiltInDataContract || dataContract.Is(DataContractType.ClassDataContract))) { ContractCodeDomInfo contractCodeDomInfo = GetContractCodeDomInfo(dataContract); if (contractCodeDomInfo.IsProcessed && !contractCodeDomInfo.UsesWildcardNamespace) @@ -219,21 +219,27 @@ internal void Export() ContractCodeDomInfo contractCodeDomInfo = GetContractCodeDomInfo(dataContract); if (!contractCodeDomInfo.IsProcessed) { - if (dataContract is ClassDataContract classDataContract) + switch (dataContract.GetContractType()) { - if (classDataContract.IsISerializable) - ExportISerializableDataContract(classDataContract, contractCodeDomInfo); - else - ExportClassDataContractHierarchy(classDataContract.StableName, classDataContract, contractCodeDomInfo, new Dictionary()); - } - else if (dataContract is CollectionDataContract) - ExportCollectionDataContract((CollectionDataContract)dataContract, contractCodeDomInfo); - else if (dataContract is EnumDataContract) - ExportEnumDataContract((EnumDataContract)dataContract, contractCodeDomInfo); - else if (dataContract is XmlDataContract) - ExportXmlDataContract((XmlDataContract)dataContract, contractCodeDomInfo); - else - throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.UnexpectedContractType, GetClrTypeFullName(dataContract.GetType()), GetClrTypeFullName(dataContract.UnderlyingType)))); + case DataContractType.ClassDataContract: + if (dataContract.IsISerializable) + ExportISerializableDataContract(dataContract, contractCodeDomInfo); + else + ExportClassDataContractHierarchy(dataContract.StableName, dataContract, contractCodeDomInfo, new Dictionary()); + break; + case DataContractType.CollectionDataContract: + ExportCollectionDataContract(dataContract, contractCodeDomInfo); + break; + case DataContractType.EnumDataContract: + ExportEnumDataContract(dataContract, contractCodeDomInfo); + break; + default: + if (dataContract is XmlDataContract xmlDataContract) + ExportXmlDataContract(xmlDataContract, contractCodeDomInfo); + else + throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.UnexpectedContractType, GetClrTypeFullName(dataContract.GetType()), GetClrTypeFullName(dataContract.UnderlyingType)))); + break; + }; contractCodeDomInfo.IsProcessed = true; } } @@ -253,13 +259,15 @@ internal void Export() } [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - private void ExportClassDataContractHierarchy(XmlQualifiedName typeName, ClassDataContract classContract, ContractCodeDomInfo contractCodeDomInfo, Dictionary contractNamesInHierarchy) + private void ExportClassDataContractHierarchy(XmlQualifiedName typeName, DataContract classContract, ContractCodeDomInfo contractCodeDomInfo, Dictionary contractNamesInHierarchy) { + Debug.Assert(classContract.Is(DataContractType.ClassDataContract)); + if (contractNamesInHierarchy.ContainsKey(classContract.StableName)) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.TypeCannotBeImported, typeName.Name, typeName.Namespace, SR.Format(SR.CircularTypeReference, classContract.StableName.Name, classContract.StableName.Namespace)))); contractNamesInHierarchy.Add(classContract.StableName, null); - ClassDataContract? baseContract = classContract.BaseContract; + DataContract? baseContract = classContract.BaseContract; if (baseContract != null) { ContractCodeDomInfo baseContractCodeDomInfo = GetContractCodeDomInfo(baseContract); @@ -333,10 +341,10 @@ private XmlQualifiedName GenericListName get { return DataContract.GetStableName(typeof(List<>)); } } - private CollectionDataContract GenericListContract + private DataContract GenericListContract { [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - get { return (_dataContractSet.GetDataContract(typeof(List<>)) as CollectionDataContract)!; } + get { return _dataContractSet.GetDataContract(typeof(List<>)); } } [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Part of a logical set of properties, some of which are not static. May not remain static with future implementation updates.")] @@ -346,10 +354,10 @@ private XmlQualifiedName GenericDictionaryName get { return DataContract.GetStableName(typeof(Dictionary<,>)); } } - private CollectionDataContract GenericDictionaryContract + private DataContract GenericDictionaryContract { [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - get { return (_dataContractSet.GetDataContract(typeof(Dictionary<,>)) as CollectionDataContract)!; } + get { return _dataContractSet.GetDataContract(typeof(Dictionary<,>)); } } private ContractCodeDomInfo GetContractCodeDomInfo(DataContract dataContract) @@ -484,7 +492,7 @@ private static CodeTypeDeclaration CreateTypeDeclaration(string typeName, DataCo // System.Diagnostics.DebuggerStepThroughAttribute not allowed on enums // ensure that the attribute is only generated on types that are not enums - if (dataContract is not EnumDataContract) + if (!dataContract.Is(DataContractType.EnumDataContract)) { typeDecl.CustomAttributes.Add(debuggerStepThroughAttribute); } @@ -502,11 +510,10 @@ private static CodeTypeDeclaration CreateTypeDeclaration(string typeName, DataCo if (_dataContractSet.TryGetReferencedType(dataContract.StableName, dataContract, out Type? type) && !type.IsGenericTypeDefinition && !type.ContainsGenericParameters) { - if (dataContract is XmlDataContract) + if (dataContract is XmlDataContract xmlContract) { if (typeof(IXmlSerializable).IsAssignableFrom(type)) { - XmlDataContract xmlContract = (XmlDataContract)dataContract; if (xmlContract.IsTypeDefinedOnImport) { if (!xmlContract.Equals(_dataContractSet.GetDataContract(type))) @@ -514,7 +521,7 @@ private static CodeTypeDeclaration CreateTypeDeclaration(string typeName, DataCo } else { - xmlContract.IsValueType = type.IsValueType; + xmlContract.SetIsValueType(type.IsValueType); xmlContract.IsTypeDefinedOnImport = true; } return GetCodeTypeReference(type); @@ -553,26 +560,29 @@ private static CodeTypeDeclaration CreateTypeDeclaration(string typeName, DataCo return typeReference; } - return GetReferencedCollectionType(dataContract as CollectionDataContract); + return GetReferencedCollectionType(dataContract.As(DataContractType.CollectionDataContract)); } [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - private CodeTypeReference? GetReferencedCollectionType(CollectionDataContract? collectionContract) + private CodeTypeReference? GetReferencedCollectionType(DataContract? collectionContract) { if (collectionContract == null) return null; + Debug.Assert(collectionContract.Is(DataContractType.CollectionDataContract)); + if (HasDefaultCollectionNames(collectionContract)) { CodeTypeReference? typeReference; if (!TryGetReferencedDictionaryType(collectionContract, out typeReference)) { - DataContract itemContract = collectionContract.ItemContract; - if (collectionContract.IsDictionary) + // ItemContract - aka BaseContract - is never null for CollectionDataContract + DataContract itemContract = collectionContract.BaseContract!; + if (collectionContract.IsKeyValue(out _, out _, out _)) { - GenerateKeyValueType(itemContract as ClassDataContract); + GenerateKeyValueType(itemContract.As(DataContractType.ClassDataContract)); } - bool isItemTypeNullable = collectionContract.IsItemTypeNullable; + bool isItemTypeNullable = collectionContract.IsItemTypeNullable(); if (!TryGetReferencedListType(itemContract, isItemTypeNullable, out typeReference)) { CodeTypeReference? elementTypeReference = GetElementTypeReference(itemContract, isItemTypeNullable); @@ -586,32 +596,38 @@ private static CodeTypeDeclaration CreateTypeDeclaration(string typeName, DataCo } [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - private static bool HasDefaultCollectionNames(CollectionDataContract collectionContract) + private static bool HasDefaultCollectionNames(DataContract collectionContract) { - DataContract itemContract = collectionContract.ItemContract; - if (collectionContract.ItemName != itemContract.StableName.Name) + Debug.Assert(collectionContract.Is(DataContractType.CollectionDataContract)); + + // ItemContract - aka BaseContract - is never null for CollectionDataContract + DataContract itemContract = collectionContract.BaseContract!; + bool isDictionary = collectionContract.IsKeyValue(out string? keyName, out string? valueName, out string? itemName); + if (itemName != itemContract.StableName.Name) return false; - if (collectionContract.IsDictionary && - (collectionContract.KeyName != Globals.KeyLocalName || collectionContract.ValueName != Globals.ValueLocalName)) + if (isDictionary && (keyName != Globals.KeyLocalName || valueName != Globals.ValueLocalName)) return false; - XmlQualifiedName expectedType = itemContract.GetArrayTypeName(collectionContract.IsItemTypeNullable); + XmlQualifiedName expectedType = itemContract.GetArrayTypeName(collectionContract.IsItemTypeNullable()); return (collectionContract.StableName.Name == expectedType.Name && collectionContract.StableName.Namespace == expectedType.Namespace); } [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - private bool TryGetReferencedDictionaryType(CollectionDataContract collectionContract, [NotNullWhen(true)] out CodeTypeReference? typeReference) + private bool TryGetReferencedDictionaryType(DataContract collectionContract, [NotNullWhen(true)] out CodeTypeReference? typeReference) { + Debug.Assert(collectionContract.Is(DataContractType.CollectionDataContract)); + // Check if it is a dictionary and use referenced dictionary type if present - if (collectionContract.IsDictionary + if (collectionContract.IsKeyValue(out _, out _, out _) && SupportsGenericTypeReference) { Type? type; if (!_dataContractSet.TryGetReferencedType(GenericDictionaryName, GenericDictionaryContract, out type)) type = typeof(Dictionary<,>); - ClassDataContract? itemContract = collectionContract.ItemContract as ClassDataContract; + // ItemContract - aka BaseContract - is never null for CollectionDataContract + DataContract? itemContract = collectionContract.BaseContract!.As(DataContractType.ClassDataContract); // A dictionary should have a Key/Value item contract that has at least two members: key and value. Debug.Assert(itemContract != null); @@ -647,7 +663,7 @@ private bool TryGetReferencedListType(DataContract itemContract, bool isItemType return false; } - [RequiresUnreferencedCode("TODO smolloy - better string here")] + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] private CodeTypeReference? GetSurrogatedTypeReference(DataContract dataContract) { Type? type = _dataContractSet.GetReferencedTypeOnImport(dataContract); @@ -658,26 +674,6 @@ private bool TryGetReferencedListType(DataContract itemContract, bool isItemType return typeReference; } return null; - - // TODO smolloy - the stuff above replaces the stuff below completely. The stuff below - // is left here as a reference for when DCSet gets fleshed out with this logic. - - //ISerializationExtendedSurrogateProvider? dataContractSurrogate = _dataContractSet.SerializationExtendedSurrogateProvider; - //if (dataContractSurrogate != null) - //{ - // Type? type = DataContractSurrogateCaller.GetReferencedTypeOnImport( - // dataContractSurrogate, - // dataContract.StableName.Name, - // dataContract.StableName.Namespace, - // _dataContractSet.GetSurrogateData(dataContract)); - // if (type != null) - // { - // CodeTypeReference typeReference = GetCodeTypeReference(type); - // typeReference.UserData.Add(s_codeUserDataActualTypeKey, type); - // return typeReference; - // } - //} - //return null; } [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] @@ -797,8 +793,10 @@ private void AddSerializableAttribute(bool generateSerializable, CodeTypeDeclara } [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - private void ExportClassDataContract(ClassDataContract classDataContract, ContractCodeDomInfo contractCodeDomInfo) + private void ExportClassDataContract(DataContract classDataContract, ContractCodeDomInfo contractCodeDomInfo) { + Debug.Assert(classDataContract.Is(DataContractType.ClassDataContract)); + GenerateType(classDataContract, contractCodeDomInfo); if (contractCodeDomInfo.ReferencedTypeExists) return; @@ -940,71 +938,78 @@ private static bool NeedsExplicitNamespace(string dataContractNamespace, string { return _dataContractSet.KnownTypesForObject; } - else if (dataContract is ClassDataContract) + else if (dataContract.Is(DataContractType.ClassDataContract)) { ContractCodeDomInfo contractCodeDomInfo = GetContractCodeDomInfo(dataContract); if (!contractCodeDomInfo.IsProcessed) GenerateType(dataContract, contractCodeDomInfo); if (contractCodeDomInfo.ReferencedTypeExists) - return GetKnownTypeContracts((ClassDataContract)dataContract, new Dictionary()); + return GetKnownTypeContracts(dataContract, new Dictionary()); } return null; } [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - private DataContractDictionary? GetKnownTypeContracts(ClassDataContract dataContract, Dictionary handledContracts) + private DataContractDictionary? GetKnownTypeContracts(DataContract classDataContract, Dictionary handledContracts) { - if (handledContracts.ContainsKey(dataContract)) - return dataContract.KnownDataContracts; + Debug.Assert(classDataContract.Is(DataContractType.ClassDataContract)); + + // TODO smolloy - This is still not public + if (handledContracts.ContainsKey(classDataContract)) + return classDataContract.KnownDataContracts; - handledContracts.Add(dataContract, null); - if (dataContract.Members != null) + handledContracts.Add(classDataContract, null); + if (classDataContract.Members != null) { bool objectMemberHandled = false; - foreach (DataMember dataMember in dataContract.Members) + foreach (DataMember dataMember in classDataContract.Members) { DataContract memberContract = dataMember.MemberTypeContract; if (!objectMemberHandled && _dataContractSet.KnownTypesForObject != null && IsObjectContract(memberContract)) { - AddKnownTypeContracts(dataContract, _dataContractSet.KnownTypesForObject); + AddKnownTypeContracts(classDataContract, _dataContractSet.KnownTypesForObject); objectMemberHandled = true; } - else if (memberContract is ClassDataContract) + else if (memberContract.Is(DataContractType.ClassDataContract)) { ContractCodeDomInfo memberCodeDomInfo = GetContractCodeDomInfo(memberContract); if (!memberCodeDomInfo.IsProcessed) GenerateType(memberContract, memberCodeDomInfo); if (memberCodeDomInfo.ReferencedTypeExists) { - AddKnownTypeContracts(dataContract, GetKnownTypeContracts((ClassDataContract)memberContract, handledContracts)); + AddKnownTypeContracts(classDataContract, GetKnownTypeContracts(memberContract, handledContracts)); } } } } - return dataContract.KnownDataContracts; + return classDataContract.KnownDataContracts; } [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - private static void AddKnownTypeContracts(ClassDataContract dataContract, DataContractDictionary? knownContracts) + private static void AddKnownTypeContracts(DataContract classDataContract, DataContractDictionary? knownContracts) { if (knownContracts == null || knownContracts.Count == 0) return; - if (dataContract.KnownDataContracts == null) - dataContract.KnownDataContracts = new DataContractDictionary(); + Debug.Assert(classDataContract.Is(DataContractType.ClassDataContract)); + + if (classDataContract.KnownDataContracts == null) + classDataContract.KnownDataContracts = new DataContractDictionary(); foreach (KeyValuePair pair in knownContracts) { - if (dataContract.StableName != pair.Key && !dataContract.KnownDataContracts.ContainsKey(pair.Key) && !pair.Value.IsBuiltInDataContract) - dataContract.KnownDataContracts.Add(pair.Key, pair.Value); + if (classDataContract.StableName != pair.Key && !classDataContract.KnownDataContracts.ContainsKey(pair.Key) && !pair.Value.IsBuiltInDataContract) + classDataContract.KnownDataContracts.Add(pair.Key, pair.Value); } } [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - private void AddKnownTypes(ClassDataContract dataContract, ContractCodeDomInfo contractCodeDomInfo) + private void AddKnownTypes(DataContract classDataContract, ContractCodeDomInfo contractCodeDomInfo) { - DataContractDictionary? knownContractDictionary = GetKnownTypeContracts(dataContract, new Dictionary()); + Debug.Assert(classDataContract.Is(DataContractType.ClassDataContract)); + + DataContractDictionary? knownContractDictionary = GetKnownTypeContracts(classDataContract, new Dictionary()); if (knownContractDictionary == null || knownContractDictionary.Count == 0) return; @@ -1075,8 +1080,10 @@ private static void ThrowIfReferencedBaseTypeSealed(Type baseType, DataContract } [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - private void ExportEnumDataContract(EnumDataContract enumDataContract, ContractCodeDomInfo contractCodeDomInfo) + private void ExportEnumDataContract(DataContract enumDataContract, ContractCodeDomInfo contractCodeDomInfo) { + Debug.Assert(enumDataContract.Is(DataContractType.EnumDataContract)); + GenerateType(enumDataContract, contractCodeDomInfo); if (contractCodeDomInfo.ReferencedTypeExists) return; @@ -1085,9 +1092,11 @@ private void ExportEnumDataContract(EnumDataContract enumDataContract, ContractC Debug.Assert(contractCodeDomInfo.TypeDeclaration != null); CodeTypeDeclaration type = contractCodeDomInfo.TypeDeclaration; + // BaseContract is never null for EnumDataContract + Type baseType = enumDataContract.BaseContract!.UnderlyingType; type.IsEnum = true; - type.BaseTypes.Add(EnumDataContract.GetBaseType(enumDataContract.BaseContractName)); - if (enumDataContract.IsFlags) + type.BaseTypes.Add(baseType); + if (baseType.IsDefined(typeof(FlagsAttribute), false)) { type.CustomAttributes.Add(new CodeAttributeDeclaration(GetClrTypeFullName(typeof(FlagsAttribute)))); AddImportStatement(typeof(FlagsAttribute).Namespace, contractCodeDomInfo.CodeNamespace); @@ -1105,11 +1114,11 @@ private void ExportEnumDataContract(EnumDataContract enumDataContract, ContractC for (int i = 0; i < enumDataContract.Members.Count; i++) { string stringValue = enumDataContract.Members[i].Name; - long longValue = enumDataContract.Values![i]; // Members[] and Values[] go hand in hand. + long longValue = enumDataContract.Members[i].Order; // Members[] and Values[] go hand in hand. CodeMemberField enumMember = new CodeMemberField(); - if (enumDataContract.IsULong) - enumMember.InitExpression = new CodeSnippetExpression(enumDataContract.GetStringFromEnumValue(longValue)); + if (baseType == typeof(ulong)) + enumMember.InitExpression = new CodeSnippetExpression(XmlConvert.ToString((ulong)longValue)); else enumMember.InitExpression = new CodePrimitiveExpression(longValue); enumMember.Name = GetMemberName(stringValue, contractCodeDomInfo); @@ -1123,16 +1132,18 @@ private void ExportEnumDataContract(EnumDataContract enumDataContract, ContractC } [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - private void ExportISerializableDataContract(ClassDataContract dataContract, ContractCodeDomInfo contractCodeDomInfo) + private void ExportISerializableDataContract(DataContract classDataContract, ContractCodeDomInfo contractCodeDomInfo) { - GenerateType(dataContract, contractCodeDomInfo); + Debug.Assert(classDataContract.Is(DataContractType.ClassDataContract)); + + GenerateType(classDataContract, contractCodeDomInfo); if (contractCodeDomInfo.ReferencedTypeExists) return; - if (SchemaHelper.GetDefaultStableNamespace(contractCodeDomInfo.ClrNamespace) != dataContract.StableName.Namespace) - throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidClrNamespaceGeneratedForISerializable, dataContract.StableName.Name, dataContract.StableName.Namespace, SchemaHelper.GetDataContractNamespaceFromUri(dataContract.StableName.Namespace), contractCodeDomInfo.ClrNamespace))); + if (SchemaHelper.GetDefaultStableNamespace(contractCodeDomInfo.ClrNamespace) != classDataContract.StableName.Namespace) + throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidClrNamespaceGeneratedForISerializable, classDataContract.StableName.Name, classDataContract.StableName.Namespace, SchemaHelper.GetDataContractNamespaceFromUri(classDataContract.StableName.Namespace), contractCodeDomInfo.ClrNamespace))); - string dataContractName = GetNameForAttribute(dataContract.StableName.Name); + string dataContractName = GetNameForAttribute(classDataContract.StableName.Name); int nestedTypeIndex = dataContractName.LastIndexOf('.'); string expectedName = (nestedTypeIndex <= 0 || nestedTypeIndex == dataContractName.Length - 1) ? dataContractName : dataContractName.Substring(nestedTypeIndex + 1); @@ -1140,21 +1151,21 @@ private void ExportISerializableDataContract(ClassDataContract dataContract, Con Debug.Assert(contractCodeDomInfo.TypeDeclaration != null); if (contractCodeDomInfo.TypeDeclaration.Name != expectedName) - throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidClrNameGeneratedForISerializable, dataContract.StableName.Name, dataContract.StableName.Namespace, contractCodeDomInfo.TypeDeclaration.Name))); + throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidClrNameGeneratedForISerializable, classDataContract.StableName.Name, classDataContract.StableName.Namespace, contractCodeDomInfo.TypeDeclaration.Name))); CodeTypeDeclaration type = contractCodeDomInfo.TypeDeclaration; if (SupportsPartialTypes) type.IsPartial = true; - if (dataContract.IsValueType && SupportsDeclareValueTypes) + if (classDataContract.IsValueType && SupportsDeclareValueTypes) type.IsStruct = true; else type.IsClass = true; AddSerializableAttribute(true /*generateSerializable*/, type, contractCodeDomInfo); - AddKnownTypes(dataContract, contractCodeDomInfo); + AddKnownTypes(classDataContract, contractCodeDomInfo); - if (dataContract.BaseContract == null) + if (classDataContract.BaseContract == null) { if (!type.IsStruct) type.BaseTypes.Add(typeof(object)); @@ -1167,22 +1178,24 @@ private void ExportISerializableDataContract(ClassDataContract dataContract, Con } else { - ContractCodeDomInfo baseContractCodeDomInfo = GetContractCodeDomInfo(dataContract.BaseContract); - GenerateType(dataContract.BaseContract, baseContractCodeDomInfo); + ContractCodeDomInfo baseContractCodeDomInfo = GetContractCodeDomInfo(classDataContract.BaseContract); + GenerateType(classDataContract.BaseContract, baseContractCodeDomInfo); type.BaseTypes.Add(baseContractCodeDomInfo.TypeReference); if (baseContractCodeDomInfo.ReferencedTypeExists) { Type? actualType = (Type?)baseContractCodeDomInfo.TypeReference?.UserData[s_codeUserDataActualTypeKey]; Debug.Assert(actualType != null); // If we're in this if condition, then we should be able to get a Type - ThrowIfReferencedBaseTypeSealed(actualType, dataContract); + ThrowIfReferencedBaseTypeSealed(actualType, classDataContract); } type.Members.Add(ISerializableDerivedConstructor); } } [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - private void GenerateKeyValueType(ClassDataContract? keyValueContract) + private void GenerateKeyValueType(DataContract? keyValueContract) { + Debug.Assert(keyValueContract == null || keyValueContract.Is(DataContractType.ClassDataContract)); + // Add code for KeyValue item type in the case where its usage is limited to dictionary // and dictionary is not found in referenced types if (keyValueContract != null && _dataContractSet.GetDataContract(keyValueContract.StableName) == null) @@ -1201,8 +1214,10 @@ private void GenerateKeyValueType(ClassDataContract? keyValueContract) } [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - private void ExportCollectionDataContract(CollectionDataContract collectionContract, ContractCodeDomInfo contractCodeDomInfo) + private void ExportCollectionDataContract(DataContract collectionContract, ContractCodeDomInfo contractCodeDomInfo) { + Debug.Assert(collectionContract.Is(DataContractType.CollectionDataContract)); + GenerateType(collectionContract, contractCodeDomInfo); if (contractCodeDomInfo.ReferencedTypeExists) return; @@ -1215,16 +1230,18 @@ private void ExportCollectionDataContract(CollectionDataContract collectionContr SR.Format(SR.CannotUseGenericTypeAsBase, dataContractName, collectionContract.StableName.Namespace))); - DataContract itemContract = collectionContract.ItemContract; - bool isItemTypeNullable = collectionContract.IsItemTypeNullable; + // ItemContract - aka BaseContract - is never null for CollectionDataContract + DataContract itemContract = collectionContract.BaseContract!; + bool isItemTypeNullable = collectionContract.IsItemTypeNullable(); + bool isDictionary = collectionContract.IsKeyValue(out string? keyName, out string? valueName, out string? itemName); CodeTypeReference? baseTypeReference; bool foundDictionaryBase = TryGetReferencedDictionaryType(collectionContract, out baseTypeReference); if (!foundDictionaryBase) { - if (collectionContract.IsDictionary) + if (isDictionary) { - GenerateKeyValueType(collectionContract.ItemContract as ClassDataContract); + GenerateKeyValueType(itemContract.As(DataContractType.ClassDataContract)); } if (!TryGetReferencedListType(itemContract, isItemTypeNullable, out baseTypeReference)) { @@ -1254,14 +1271,14 @@ private void ExportCollectionDataContract(CollectionDataContract collectionContr collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.NamespaceProperty, new CodePrimitiveExpression(collectionContract.StableName.Namespace))); if (collectionContract.IsReference != Globals.DefaultIsReference) collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.IsReferenceProperty, new CodePrimitiveExpression(collectionContract.IsReference))); - collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.ItemNameProperty, new CodePrimitiveExpression(GetNameForAttribute(collectionContract.ItemName)))); + collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.ItemNameProperty, new CodePrimitiveExpression(GetNameForAttribute(itemName!)))); // ItemName is never null for Collection contracts. if (foundDictionaryBase) { // These are not null if we are working with a dictionary. See CollectionDataContract.IsDictionary - Debug.Assert(collectionContract.KeyName != null); - Debug.Assert(collectionContract.ValueName != null); - collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.KeyNameProperty, new CodePrimitiveExpression(GetNameForAttribute(collectionContract.KeyName)))); - collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.ValueNameProperty, new CodePrimitiveExpression(GetNameForAttribute(collectionContract.ValueName)))); + Debug.Assert(keyName != null); + Debug.Assert(valueName != null); + collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.KeyNameProperty, new CodePrimitiveExpression(GetNameForAttribute(keyName)))); + collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.ValueNameProperty, new CodePrimitiveExpression(GetNameForAttribute(valueName)))); } generatedType.CustomAttributes.Add(collectionContractAttribute); AddImportStatement(typeof(CollectionDataContractAttribute).Namespace, contractCodeDomInfo.CodeNamespace); @@ -1617,22 +1634,22 @@ private static void AddNamespaceFragment(StringBuilder builder, int fragmentOffs fragments.Add(nsFragment, null); } - [RequiresUnreferencedCode("TODO smolloy - Placeholder")] - internal static bool IsObjectContract(DataContract dataContract) + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + internal static bool IsObjectContract(DataContract? dataContract) { Dictionary previousCollectionTypes = new Dictionary(); - while (dataContract is CollectionDataContract) + while (dataContract != null && dataContract.Is(DataContractType.CollectionDataContract)) { if (dataContract.OriginalUnderlyingType == null) { - dataContract = ((CollectionDataContract)dataContract).ItemContract; + dataContract = dataContract.BaseContract; continue; } if (!previousCollectionTypes.ContainsKey(dataContract.OriginalUnderlyingType)) { previousCollectionTypes.Add(dataContract.OriginalUnderlyingType, dataContract.OriginalUnderlyingType); - dataContract = ((CollectionDataContract)dataContract).ItemContract; + dataContract = dataContract.BaseContract; } else { @@ -1640,7 +1657,7 @@ internal static bool IsObjectContract(DataContract dataContract) } } - return dataContract is PrimitiveDataContract && ((PrimitiveDataContract)dataContract).UnderlyingType == typeof(object); + return dataContract != null && dataContract.Is(DataContractType.PrimitiveDataContract) && dataContract.UnderlyingType == typeof(object); } private static bool IsValidStart(char c) diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaHelper.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaHelper.cs index b5ad415321b2b..3215f4cb57ab4 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaHelper.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaHelper.cs @@ -3,8 +3,61 @@ namespace System.Runtime.Serialization.Schema { + internal enum DataContractType + { + ClassDataContract, + CollectionDataContract, + EnumDataContract, + PrimitiveDataContract, + XmlDataContract, + Unknown = -1 + } + + internal static class DataContractExtensions + { + internal static DataContractType GetContractType(this DataContract dataContract) => dataContract.ContractType switch + { + "ClassDataContract" => Schema.DataContractType.ClassDataContract, + "CollectionDataContract" => Schema.DataContractType.CollectionDataContract, + "EnumDataContract" => Schema.DataContractType.EnumDataContract, + "PrimitiveDataContract" => Schema.DataContractType.PrimitiveDataContract, + "XmlDataContract" => Schema.DataContractType.XmlDataContract, + _ => Schema.DataContractType.Unknown + }; + + internal static bool Is(this DataContract dataContract, DataContractType dcType) + { + return (dataContract.GetContractType() == dcType); + } + + internal static DataContract? As(this DataContract dataContract, DataContractType dcType) + { + if (dataContract.GetContractType() == dcType) + return dataContract; + return null; + } + + internal static bool IsItemTypeNullable(this DataContract collectionDataContract) + { + if (collectionDataContract.GetContractType() == DataContractType.CollectionDataContract) + { + // ItemContract - aka BaseContract - is never null for CollectionDataContract + return SchemaHelper.IsTypeNullable(collectionDataContract.BaseContract!.UnderlyingType); + } + + return false; + } + } + internal static class SchemaHelper { + internal static bool IsTypeNullable(Type type) + { + return !type.IsValueType || + (type.IsGenericType && + type.GetGenericTypeDefinition() == typeof(Nullable<>)); + } + internal static string GetCollectionNamespace(string elementNs) { return IsBuiltInNamespace(elementNs) ? Globals.CollectionsNamespace : elementNs; diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs index 532fd9c629c74..51424344e873a 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs @@ -157,8 +157,7 @@ public XmlQualifiedName GetSchemaTypeName(Type type) type = GetSurrogatedType(type); DataContract dataContract = DataContract.GetDataContract(type); EnsureTypeNotGeneric(dataContract.UnderlyingType); - XmlDataContract? xmlDataContract = dataContract as XmlDataContract; - if (xmlDataContract != null && xmlDataContract.IsAnonymous) + if (dataContract is XmlDataContract xmlDataContract && xmlDataContract.IsAnonymous) return XmlQualifiedName.Empty; return dataContract.StableName; } @@ -171,9 +170,8 @@ public XmlQualifiedName GetSchemaTypeName(Type type) type = GetSurrogatedType(type); DataContract dataContract = DataContract.GetDataContract(type); EnsureTypeNotGeneric(dataContract.UnderlyingType); - XmlDataContract? xmlDataContract = dataContract as XmlDataContract; - if (xmlDataContract != null && xmlDataContract.IsAnonymous) - return dataContract.XsdType; + if (dataContract is XmlDataContract xmlDataContract && xmlDataContract.IsAnonymous) + return xmlDataContract.XsdType; return null; } diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/_Stubs.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/_Stubs.cs index f864eb893337b..7a16b139652e5 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/_Stubs.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/_Stubs.cs @@ -114,18 +114,13 @@ public class DataContract public class ClassDataContract : DataContract { // BaseContract - // *IsISerializable - // *IsReference - // *IsValueType - // *KnownDataContracts // Members } public class CollectionDataContract : DataContract { - // IsCollection() static - This could be on base DataContract + // IsCollection() static - This could be on base DataContract? // IsDictionary // IsItemTypeNullable - // *IsReference // ItemContract // ItemName // KeyName @@ -136,7 +131,7 @@ public class EnumDataContract : DataContract // BaseContractName // GetBaseType << and ^^ can be combined into one Type GetType() - // GetStringFromEnumValue() This is the one non-data item. Should we bring an enum-specific function up to DCBase? or perhaps this and IsUlong can go away if Values just returns int[] or string[] appropriately + // GetStringFromEnumValue() This is the one non-data item. Should we bring an enum-specific function up to DataContract? or perhaps this and IsUlong can go away if Values just returns int[] or string[] appropriately // IsULong // IsFlags // Members @@ -148,12 +143,6 @@ public class XmlDataContract : DataContract // IsAnonymous // IsTopLevelElementNullable // IsTypeDefinedOnImport - // *IsValueType // XsdType - - // These three are actually on DC itself. We worked around with a new API in one case. Can we use that for all cases? - // *HasRoot - // *TopLevelElementName - // *TopLevelElementNamespace } } diff --git a/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs b/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs index 5becb86120c30..706625b147b48 100644 --- a/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs +++ b/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs @@ -8,8 +8,10 @@ namespace System.Runtime.Serialization { public abstract partial class DataContract { + public DataContract? BaseContract { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public DataContract BindGenericParameters(DataContract[] paramContracts, System.Collections.Generic.Dictionary boundContracts) { throw null; } + public string? ContractType { get { throw null; } } internal DataContract(DataContractCriticalHelper helper) { } internal const System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes DataContractPreserveMemberTypes = System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods | @@ -33,10 +35,13 @@ internal DataContract(DataContractCriticalHelper helper) { } public bool HasRoot { get { throw null; } } public bool IsBuiltInDataContract { get { throw null; } } public bool IsISerializable { get { throw null; } } + public bool IsKeyValue(out string? keyName, out string? valueName, out string? itemName) { throw null; } public bool IsReference { get { throw null; } } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public static bool IsTypeSerializable(Type type) { throw null; } public bool IsValueType { get { throw null; } } + public virtual System.Collections.Generic.Dictionary? KnownDataContracts { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } set { throw null; } } + public System.Collections.Generic.List? Members { get { throw null; } } public Type OriginalUnderlyingType { get { throw null; } } public System.Xml.XmlQualifiedName StableName { get { throw null; } } [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(DataContract.DataContractPreserveMemberTypes)] @@ -147,7 +152,7 @@ internal DataMember() { } public bool IsRequired { get { throw null; } } public DataContract MemberTypeContract { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } } public string Name { get { throw null; } } - public int Order { get { throw null; } } + public long Order { get { throw null; } } } public partial class ExportOptions { @@ -170,6 +175,16 @@ public partial interface IExtensibleDataObject { System.Runtime.Serialization.ExtensionDataObject? ExtensionData { get; set; } } + public sealed partial class XmlDataContract : DataContract + { + public bool IsAnonymous { get { throw null; } } + public bool IsTopLevelElementNullable { get { throw null; } } + public bool IsTypeDefinedOnImport { get { throw null; } set { throw null; } } + public void SetIsValueType(bool isValueType) { throw null; } + internal XmlDataContract(Type type) : base(new XmlDataContractCriticalHelper()) { } + public System.Xml.Schema.XmlSchemaType? XsdType { get { throw null; } } + } + internal sealed partial class XmlDataContractCriticalHelper : DataContractCriticalHelper { } public abstract partial class XmlObjectSerializer { protected XmlObjectSerializer() { } From 4eb08fba0caa5ce72f0e88ea0fcf408dc95ec97d Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Wed, 6 Jul 2022 23:42:36 -0700 Subject: [PATCH 06/33] Cleanup. --- .../Runtime/Serialization/DataContractSet.cs | 20 +- .../Runtime/Serialization/EnumDataContract.cs | 4 +- .../System/Runtime/Serialization/Globals.cs | 1 - .../Runtime/Serialization/SchemaImporter.cs | 2 +- .../System.Runtime.Serialization.Schema.cs | 72 + ...System.Runtime.Serialization.Schema.csproj | 8 + .../src/Resources/Strings.resx | 1350 ----------------- ...System.Runtime.Serialization.Schema.csproj | 10 +- .../Serialization/Schema/CodeExporter.cs | 7 +- .../Schema/ContractCodeDomInfo.cs | 2 +- .../Serialization/Schema/DiagnosticUtility.cs | 64 - .../Serialization/Schema/ExportOptions.cs | 15 +- .../Runtime/Serialization/Schema/Globals.cs | 459 ------ .../Serialization/Schema/ImportOptions.cs | 4 +- .../Schema/XsdDataContractExporter.cs | 21 +- .../Schema/XsdDataContractImporter.cs | 38 +- .../Runtime/Serialization/Schema/_Stubs.cs | 148 -- .../ref/System.Runtime.Serialization.Xml.cs | 2 +- 18 files changed, 127 insertions(+), 2100 deletions(-) delete mode 100644 src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/_Stubs.cs diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs index 06fee1988e97b..789cc31a19e20 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs @@ -16,17 +16,19 @@ public sealed class DataContractSet { private DataContractDictionary? _contracts; private Dictionary? _processedContracts; + private readonly ISerializationSurrogateProvider? _surrogateProvider; private readonly ISerializationExtendedSurrogateProvider? _extendedSurrogateProvider; private Hashtable? _surrogateDataTable; private DataContractDictionary? _knownTypesForObject; private readonly ICollection? _referencedTypes; private readonly ICollection? _referencedCollectionTypes; - public DataContractSet(ISerializationExtendedSurrogateProvider? dataContractExtendedSurrogate, ICollection? referencedTypes, ICollection? referencedCollectionTypes) + public DataContractSet(ISerializationSurrogateProvider? dataContractSurrogate, ICollection? referencedTypes, ICollection? referencedCollectionTypes) { _referencedTypes = referencedTypes; _referencedCollectionTypes = referencedCollectionTypes; - _extendedSurrogateProvider = dataContractExtendedSurrogate; + _surrogateProvider = dataContractSurrogate; + _extendedSurrogateProvider = dataContractSurrogate as ISerializationExtendedSurrogateProvider; } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -201,9 +203,9 @@ private void AddKnownDataContracts(DataContractDictionary? knownDataContracts) [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal XmlQualifiedName GetStableName(Type clrType) { - if (_extendedSurrogateProvider != null) + if (_surrogateProvider != null) { - Type dcType = DataContractSurrogateCaller.GetDataContractType(_extendedSurrogateProvider, clrType); + Type dcType = DataContractSurrogateCaller.GetDataContractType(_surrogateProvider, clrType); return DataContract.GetStableName(dcType); } return DataContract.GetStableName(clrType); @@ -212,16 +214,16 @@ internal XmlQualifiedName GetStableName(Type clrType) [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] public DataContract GetDataContract(Type type) { - if (_extendedSurrogateProvider == null) + if (_surrogateProvider == null) return DataContract.GetDataContract(type); DataContract? dataContract = DataContract.GetBuiltInDataContract(type); if (dataContract != null) return dataContract; - Type dcType = DataContractSurrogateCaller.GetDataContractType(_extendedSurrogateProvider, type); + Type dcType = DataContractSurrogateCaller.GetDataContractType(_surrogateProvider, type); dataContract = DataContract.GetDataContract(dcType); - if (!SurrogateDataTable.Contains(dataContract)) + if (_extendedSurrogateProvider != null && !SurrogateDataTable.Contains(dataContract)) { object? customData = DataContractSurrogateCaller.GetCustomDataToExport(_extendedSurrogateProvider, type, dcType); if (customData != null) @@ -248,9 +250,9 @@ internal DataContract GetMemberTypeDataContract(DataMember dataMember) Type dataMemberType = dataMember.MemberType; if (dataMember.IsGetOnlyCollection) { - if (_extendedSurrogateProvider != null) + if (_surrogateProvider != null) { - Type dcType = DataContractSurrogateCaller.GetDataContractType(_extendedSurrogateProvider, dataMemberType); + Type dcType = DataContractSurrogateCaller.GetDataContractType(_surrogateProvider, dataMemberType); if (dcType != dataMemberType) { throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.SurrogatesWithGetOnlyCollectionsNotSupported, diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs index cab5cf7b03106..1835f807a41a4 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs @@ -123,7 +123,7 @@ internal EnumDataContractCriticalHelper( Type baseType = Enum.GetUnderlyingType(type); XmlQualifiedName baseTypeName = GetBaseContractName(baseType); _baseContract = DataContract.GetBuiltInDataContract(baseTypeName.Name, baseTypeName.Namespace)!; - // TODO smolloy - Setting StableName might be redundant. But I don't want to miss an edge case. + // NOTE TODO smolloy - Setting StableName might be redundant. But I don't want to miss an edge case. _baseContract.StableName = baseTypeName; ImportBaseType(baseType); IsFlags = type.IsDefined(Globals.TypeOfFlagsAttribute, false); @@ -164,7 +164,7 @@ internal XmlQualifiedName BaseContractName SR.Format(SR.InvalidEnumBaseType, value.Name, value.Namespace, StableName.Name, StableName.Namespace)); ImportBaseType(baseType); _baseContract = DataContract.GetBuiltInDataContract(value.Name, value.Namespace)!; - // TODO smolloy - Setting StableName might be redundant. But I don't want to miss an edge case. + // NOTE TODO smolloy - Setting StableName might be redundant. But I don't want to miss an edge case. _baseContract.StableName = value; } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs index a433e8ade6d0a..c10db1641eb12 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs @@ -319,7 +319,6 @@ internal static Type TypeOfHashtable internal static Type TypeOfSchemaDefinedType => s_typeOfSchemaDefinedType ??= typeof(SchemaDefinedType); - // TODO smolloy - change name inline with new name from SchemaHelper private static MemberInfo? s_schemaMemberInfoPlaceholder; internal static MemberInfo SchemaMemberInfoPlaceholder => s_schemaMemberInfoPlaceholder ??= TypeOfSchemaDefinedType.GetField("_stableName", BindingFlags.NonPublic | BindingFlags.Instance)!; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs index 559c89462151a..1aad19d755598 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs @@ -707,7 +707,7 @@ private DataContract ImportXmlDataType(XmlQualifiedName typeName, XmlSchemaType } else { - // TODO smolloy - I think this might be dead code. It doesn't appear like xsdType can be null in this method. + // NOTE TODO smolloy - I think this might be dead code. It doesn't appear like xsdType can be null in this method. //Value type can be used by both nillable and non-nillable elements but reference type cannot be used by non nillable elements xmlDataContract.IsValueType = true; xmlDataContract.IsTypeDefinedOnImport = false; diff --git a/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.cs b/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.cs index bd1d054ff3fb7..008a0544fc205 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.cs @@ -6,4 +6,76 @@ namespace System.Runtime.Serialization.Schema { + public sealed partial class ExportOptions + { + public System.Collections.ObjectModel.Collection KnownTypes { get { throw null; } } + public ISerializationSurrogateProvider? SurrogateProvider { get { throw null; } set { throw null; } } + } + public sealed partial class ImportOptions + { + public System.CodeDom.Compiler.CodeDomProvider? CodeProvider { get { throw null; } set { throw null; } } + public bool EnableDataBinding { get { throw null; } set { throw null; } } + public ISerializationSurrogateProvider? SurrogateProvider { get { throw null; } set { throw null; } } + public bool GenerateInternal { get { throw null; } set { throw null; } } + public bool GenerateSerializable { get { throw null; } set { throw null; } } + public bool ImportXmlType { get { throw null; } set { throw null; } } + public System.Collections.Generic.IDictionary Namespaces { get { throw null; } } + public Func? ProcessImportedType; + public System.Collections.Generic.ICollection ReferencedCollectionTypes { get { throw null; } } + public System.Collections.Generic.ICollection ReferencedTypes { get { throw null; } } + } + public sealed class XsdDataContractExporter + { + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public bool CanExport(System.Collections.Generic.ICollection assemblies) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public bool CanExport(System.Collections.Generic.ICollection types) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public bool CanExport(Type type) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public void Export(System.Collections.Generic.ICollection assemblies) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public void Export(System.Collections.Generic.ICollection types) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public void Export(Type type) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public System.Xml.XmlQualifiedName? GetRootElementName(Type type) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public System.Xml.Schema.XmlSchemaType? GetSchemaType(Type type) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public System.Xml.XmlQualifiedName GetSchemaTypeName(Type type) { throw null; } + public ExportOptions? Options { get { throw null; } set { throw null; } } + public System.Xml.Schema.XmlSchemaSet Schemas { get { throw null; } } + public XsdDataContractExporter() { throw null; } + public XsdDataContractExporter(System.Xml.Schema.XmlSchemaSet? schemas) { throw null; } + } + public sealed partial class XsdDataContractImporter + { + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public bool CanImport(System.Xml.Schema.XmlSchemaSet schemas) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public bool CanImport(System.Xml.Schema.XmlSchemaSet schemas, System.Collections.Generic.ICollection typeNames) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public bool CanImport(System.Xml.Schema.XmlSchemaSet schemas, System.Xml.XmlQualifiedName typeName) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public bool CanImport(System.Xml.Schema.XmlSchemaSet schemas, System.Xml.Schema.XmlSchemaElement element) { throw null; } + public System.CodeDom.CodeCompileUnit CodeCompileUnit { get { throw null; } } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public System.CodeDom.CodeTypeReference GetCodeTypeReference(System.Xml.XmlQualifiedName typeName) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public System.CodeDom.CodeTypeReference GetCodeTypeReference(System.Xml.XmlQualifiedName typeName, System.Xml.Schema.XmlSchemaElement element) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public System.Collections.Generic.ICollection? GetKnownTypeReferences(System.Xml.XmlQualifiedName typeName) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public void Import(System.Xml.Schema.XmlSchemaSet schemas) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public void Import(System.Xml.Schema.XmlSchemaSet schemas, System.Collections.Generic.ICollection typeNames) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public void Import(System.Xml.Schema.XmlSchemaSet schemas, System.Xml.XmlQualifiedName typeName) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public System.Xml.XmlQualifiedName? Import(System.Xml.Schema.XmlSchemaSet schemas, System.Xml.Schema.XmlSchemaElement element) { throw null; } + public ImportOptions? Options { get { throw null; } set { throw null; } } + public XsdDataContractImporter() { throw null; } + public XsdDataContractImporter(System.CodeDom.CodeCompileUnit codeCompileUnit) { throw null; } + } } diff --git a/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.csproj b/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.csproj index 8c84ddc8702b2..d2e83b9b09982 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.csproj +++ b/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.csproj @@ -6,4 +6,12 @@ + + + + + \ No newline at end of file diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/Resources/Strings.resx b/src/libraries/System.Runtime.Serialization.Schema/src/Resources/Strings.resx index e1037028d6fb5..b9b843b480875 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/Resources/Strings.resx +++ b/src/libraries/System.Runtime.Serialization.Schema/src/Resources/Strings.resx @@ -181,1354 +181,4 @@ An internal error has occurred. Unexpected contract type '{0}' for type '{1}' encountered. - - - - - diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj b/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj index 499fe0bd091bf..558c94b312d7c 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj @@ -6,12 +6,9 @@ $(NoWarn);1634;1691;649 Microsoft - - false - false - false @@ -26,7 +23,6 @@ System.Runtime.Serialization.Schema.XsdDataContractImporter - @@ -35,11 +31,9 @@ System.Runtime.Serialization.Schema.XsdDataContractImporter - diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs index cb9ae0f641d07..fbb3467ea73a3 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs @@ -547,9 +547,9 @@ private static CodeTypeDeclaration CreateTypeDeclaration(string typeName, DataCo typeReference = GetReferencedGenericType(dataContract.GenericInfo, out referencedContract); if (referencedContract != null && !referencedContract.Equals(dataContract)) { - // NOTE TODO smolloy - Is this right? Looking at 'GetReferenceGenericType()' it is possible to get a non-null referencedContract, but a null typeReference. Is that supposed to happen? - // Are we supposed to only check the dataContract if we did not fail to get a typeReference? Should GetReferenceGenericType() be consistent with the two return parameters? - // For now... assert to get out of the way of compilation. But come revisit this. + // NOTE TODO smolloy - This is the 4.8 code... but feels like a bug? Looking at 'GetReferenceGenericType()' it is possible to get return + // a non-null 'referencedContract', but also null 'typeReference'. + // For now... assert to get out of the way of compilation. But should we add a check here? Debug.Assert(typeReference != null); type = (Type?)typeReference.UserData[s_codeUserDataActualTypeKey]; throw ExceptionUtil.ThrowHelperError(new InvalidOperationException(SR.Format(SR.ReferencedTypeDoesNotMatch, @@ -954,7 +954,6 @@ private static bool NeedsExplicitNamespace(string dataContractNamespace, string { Debug.Assert(classDataContract.Is(DataContractType.ClassDataContract)); - // TODO smolloy - This is still not public if (handledContracts.ContainsKey(classDataContract)) return classDataContract.KnownDataContracts; diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs index 943376b1e3153..5872baa78c1c5 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs @@ -14,7 +14,7 @@ namespace System.Runtime.Serialization.Schema internal sealed class ContractCodeDomInfo { private string? _clrNamespace; - // TODO smolloy - This was a Dictionary previously, so adding a duplicate entry would throw an exception. + // NOTE TODO smolloy - This was a Dictionary previously, so adding a duplicate entry would throw an exception. // HashSet does not allow duplicates either, but it just returns false instead of throwing. I think it's safe to not // throw in that case here, so long as we don't add duplicates. It's just a string list. private HashSet? _memberNames; diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/DiagnosticUtility.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/DiagnosticUtility.cs index 1a89968bfa62d..2cb5317fae40c 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/DiagnosticUtility.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/DiagnosticUtility.cs @@ -48,68 +48,4 @@ internal static Exception ThrowHelperCallback(Exception e) } } } - - - // TODO smolloy - same deal as other places. Code below is original from DCS. Copy what we need up above. - // remove this code when done. -#if unused - internal static class Fx - { - [Conditional("DEBUG")] - public static void Assert([DoesNotReturnIf(false)] bool condition, string message) - { - System.Diagnostics.Debug.Assert(condition, message); - } - - [Conditional("DEBUG")] - [DoesNotReturn] - public static void Assert(string message) - { - Assert(false, message); - } - } - - internal static class DiagnosticUtility - { - [Conditional("DEBUG")] - [DoesNotReturn] - public static void DebugAssert(string message) - { - DebugAssert(false, message); - } - - [Conditional("DEBUG")] - public static void DebugAssert([DoesNotReturnIf(false)] bool condition, string message) - { - Debug.Assert(condition, message); - } - - internal static class ExceptionUtility - { - public static Exception ThrowHelperArgumentNull(string message) - { - return new ArgumentNullException(message); - } - - public static Exception ThrowHelperError(Exception e) - { - return e; - } - - public static Exception ThrowHelperArgument(string message) - { - return new ArgumentException(message); - } - - internal static Exception ThrowHelperFatal(string message, Exception innerException) - { - return ThrowHelperError(new Exception(message, innerException)); - } - internal static Exception ThrowHelperCallback(Exception e) - { - return ThrowHelperError(e); - } - } - } -#endif } diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ExportOptions.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ExportOptions.cs index c6e41b4b87677..eb760948b5580 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ExportOptions.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ExportOptions.cs @@ -5,18 +5,15 @@ namespace System.Runtime.Serialization.Schema { - // TODO smolloy - should we rename this to avoid confusion with Sys.RT.Ser.ExportOptions? Rename ImportOptions to match. - // Do we even need this class? It is not a different signature than the in-box one. Should we just use that? - // Actually, that's not quite right. This _would be_ the same signature if export supported surrogates in box. - // But it doesn't, so the surrogate provider is not there. We could add it. Or just use this class. Depends on which - // is the more likely "pit of success" I guess. - public class ExportOptions + // NOTE TODO smolloy - ExportOptions, ImportOptions, XsdDataContractExporter, XsdDataContractImporter... they all have the same + // names in this library as they did in 4.8... and as the two 'Export' classes currently have in Core. The namespace is + // different here so there isn't a collision. But should we consider using different names for these classes? + // (The 'SurrogateProvider' property is named differently from previous versions. Should we align that property with whatever + // decision we make on the class names?) + public sealed class ExportOptions { - // TODO smolloy - this is named differently than the in-box version of the options. public ISerializationSurrogateProvider? SurrogateProvider { get; set; } - // TODO smolloy - This was used in core already. Since the idea is to shift this export functionality out here, this - // existing piece should come along with us. Which is to say, we probably still need this. private Collection? _knownTypes; public Collection KnownTypes => _knownTypes ??= new Collection(); } diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/Globals.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/Globals.cs index cd7b0cb1b83e9..755dbec7fdcaa 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/Globals.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/Globals.cs @@ -2,13 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.IO; -using System.Reflection; -using System.Text.RegularExpressions; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; @@ -159,457 +152,5 @@ internal static class Globals "; - - // TODO smolloy - All of this came from Sys.Priv.DCS... here for easy copy/paste of the things we need. Delete when done. -#if unused - /// - /// Review - changes to const could affect code generation logic; any changes should be reviewed. - /// - internal const BindingFlags ScanAllMembers = BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public; - - private static XmlQualifiedName? s_idQualifiedName; - internal static XmlQualifiedName IdQualifiedName => - s_idQualifiedName ??= new XmlQualifiedName(Globals.IdLocalName, Globals.SerializationNamespace); - - private static XmlQualifiedName? s_refQualifiedName; - internal static XmlQualifiedName RefQualifiedName => - s_refQualifiedName ??= new XmlQualifiedName(Globals.RefLocalName, Globals.SerializationNamespace); - - private static Type? s_typeOfObject; - internal static Type TypeOfObject => - s_typeOfObject ??= typeof(object); - - private static Type? s_typeOfValueType; - internal static Type TypeOfValueType => - s_typeOfValueType ??= typeof(ValueType); - - private static Type? s_typeOfArray; - internal static Type TypeOfArray => - s_typeOfArray ??= typeof(Array); - - private static Type? s_typeOfString; - internal static Type TypeOfString => - s_typeOfString ??= typeof(string); - - private static Type? s_typeOfInt; - internal static Type TypeOfInt => - s_typeOfInt ??= typeof(int); - - private static Type? s_typeOfULong; - internal static Type TypeOfULong => - s_typeOfULong ??= typeof(ulong); - - private static Type? s_typeOfVoid; - internal static Type TypeOfVoid => - s_typeOfVoid ??= typeof(void); - - private static Type? s_typeOfByteArray; - internal static Type TypeOfByteArray => - s_typeOfByteArray ??= typeof(byte[]); - - private static Type? s_typeOfTimeSpan; - internal static Type TypeOfTimeSpan => - s_typeOfTimeSpan ??= typeof(TimeSpan); - - private static Type? s_typeOfGuid; - internal static Type TypeOfGuid => - s_typeOfGuid ??= typeof(Guid); - - private static Type? s_typeOfDateTimeOffset; - internal static Type TypeOfDateTimeOffset => - s_typeOfDateTimeOffset ??= typeof(DateTimeOffset); - - private static Type? s_typeOfDateTimeOffsetAdapter; - internal static Type TypeOfDateTimeOffsetAdapter => - s_typeOfDateTimeOffsetAdapter ??= typeof(DateTimeOffsetAdapter); - - private static Type? s_typeOfMemoryStream; - internal static Type TypeOfMemoryStream => - s_typeOfMemoryStream ??= typeof(MemoryStream); - - private static Type? s_typeOfMemoryStreamAdapter; - internal static Type TypeOfMemoryStreamAdapter => - s_typeOfMemoryStreamAdapter ??= typeof(MemoryStreamAdapter); - - private static Type? s_typeOfUri; - internal static Type TypeOfUri => - s_typeOfUri ??= typeof(Uri); - - private static Type? s_typeOfTypeEnumerable; - internal static Type TypeOfTypeEnumerable => - s_typeOfTypeEnumerable ??= typeof(IEnumerable); - - private static Type? s_typeOfStreamingContext; - internal static Type TypeOfStreamingContext => - s_typeOfStreamingContext ??= typeof(StreamingContext); - - private static Type? s_typeOfISerializable; - internal static Type TypeOfISerializable => - s_typeOfISerializable ??= typeof(ISerializable); - - private static Type? s_typeOfIDeserializationCallback; - internal static Type TypeOfIDeserializationCallback => - s_typeOfIDeserializationCallback ??= typeof(IDeserializationCallback); - - private static Type? s_typeOfIObjectReference; - internal static Type TypeOfIObjectReference => - s_typeOfIObjectReference ??= typeof(IObjectReference); - - private static Type? s_typeOfXmlFormatClassWriterDelegate; - internal static Type TypeOfXmlFormatClassWriterDelegate => - s_typeOfXmlFormatClassWriterDelegate ??= typeof(XmlFormatClassWriterDelegate); - - private static Type? s_typeOfXmlFormatCollectionWriterDelegate; - internal static Type TypeOfXmlFormatCollectionWriterDelegate => - s_typeOfXmlFormatCollectionWriterDelegate ??= typeof(XmlFormatCollectionWriterDelegate); - - private static Type? s_typeOfXmlFormatClassReaderDelegate; - internal static Type TypeOfXmlFormatClassReaderDelegate => - s_typeOfXmlFormatClassReaderDelegate ??= typeof(XmlFormatClassReaderDelegate); - - private static Type? s_typeOfXmlFormatCollectionReaderDelegate; - internal static Type TypeOfXmlFormatCollectionReaderDelegate => - s_typeOfXmlFormatCollectionReaderDelegate ??= typeof(XmlFormatCollectionReaderDelegate); - - private static Type? s_typeOfXmlFormatGetOnlyCollectionReaderDelegate; - internal static Type TypeOfXmlFormatGetOnlyCollectionReaderDelegate => - s_typeOfXmlFormatGetOnlyCollectionReaderDelegate ??= typeof(XmlFormatGetOnlyCollectionReaderDelegate); - - private static Type? s_typeOfKnownTypeAttribute; - internal static Type TypeOfKnownTypeAttribute => - s_typeOfKnownTypeAttribute ??= typeof(KnownTypeAttribute); - - private static Type? s_typeOfDataContractAttribute; - internal static Type TypeOfDataContractAttribute => - s_typeOfDataContractAttribute ??= typeof(DataContractAttribute); - - private static Type? s_typeOfDataMemberAttribute; - internal static Type TypeOfDataMemberAttribute => - s_typeOfDataMemberAttribute ??= typeof(DataMemberAttribute); - - private static Type? s_typeOfEnumMemberAttribute; - internal static Type TypeOfEnumMemberAttribute => - s_typeOfEnumMemberAttribute ??= typeof(EnumMemberAttribute); - - private static Type? s_typeOfCollectionDataContractAttribute; - internal static Type TypeOfCollectionDataContractAttribute => - s_typeOfCollectionDataContractAttribute ??= typeof(CollectionDataContractAttribute); - - private static Type? s_typeOfOptionalFieldAttribute; - internal static Type TypeOfOptionalFieldAttribute => - s_typeOfOptionalFieldAttribute ??= typeof(OptionalFieldAttribute); - - private static Type? s_typeOfObjectArray; - internal static Type TypeOfObjectArray => - s_typeOfObjectArray ??= typeof(object[]); - - private static Type? s_typeOfOnSerializingAttribute; - internal static Type TypeOfOnSerializingAttribute => - s_typeOfOnSerializingAttribute ??= typeof(OnSerializingAttribute); - - private static Type? s_typeOfOnSerializedAttribute; - internal static Type TypeOfOnSerializedAttribute => - s_typeOfOnSerializedAttribute ??= typeof(OnSerializedAttribute); - - private static Type? s_typeOfOnDeserializingAttribute; - internal static Type TypeOfOnDeserializingAttribute => - s_typeOfOnDeserializingAttribute ??= typeof(OnDeserializingAttribute); - - private static Type? s_typeOfOnDeserializedAttribute; - internal static Type TypeOfOnDeserializedAttribute => - s_typeOfOnDeserializedAttribute ??= typeof(OnDeserializedAttribute); - - private static Type? s_typeOfFlagsAttribute; - internal static Type TypeOfFlagsAttribute => - s_typeOfFlagsAttribute ??= typeof(FlagsAttribute); - - private static Type? s_typeOfIXmlSerializable; - internal static Type TypeOfIXmlSerializable => - s_typeOfIXmlSerializable ??= typeof(IXmlSerializable); - - private static Type? s_typeOfXmlSchemaProviderAttribute; - internal static Type TypeOfXmlSchemaProviderAttribute => - s_typeOfXmlSchemaProviderAttribute ??= typeof(XmlSchemaProviderAttribute); - - private static Type? s_typeOfXmlRootAttribute; - internal static Type TypeOfXmlRootAttribute => - s_typeOfXmlRootAttribute ??= typeof(XmlRootAttribute); - - private static Type? s_typeOfXmlQualifiedName; - internal static Type TypeOfXmlQualifiedName => - s_typeOfXmlQualifiedName ??= typeof(XmlQualifiedName); - - private static Type? s_typeOfXmlSchemaType; - internal static Type TypeOfXmlSchemaType => - s_typeOfXmlSchemaType ??= typeof(XmlSchemaType); - - private static Type? s_typeOfIExtensibleDataObject; - internal static Type TypeOfIExtensibleDataObject => - s_typeOfIExtensibleDataObject ??= typeof(IExtensibleDataObject); - - private static Type? s_typeOfExtensionDataObject; - internal static Type TypeOfExtensionDataObject => - s_typeOfExtensionDataObject ??= typeof(ExtensionDataObject); - - private static Type? s_typeOfISerializableDataNode; - internal static Type TypeOfISerializableDataNode => - s_typeOfISerializableDataNode ??= typeof(ISerializableDataNode); - - private static Type? s_typeOfClassDataNode; - internal static Type TypeOfClassDataNode => - s_typeOfClassDataNode ??= typeof(ClassDataNode); - - private static Type? s_typeOfCollectionDataNode; - internal static Type TypeOfCollectionDataNode => - s_typeOfCollectionDataNode ??= typeof(CollectionDataNode); - - private static Type? s_typeOfXmlDataNode; - internal static Type TypeOfXmlDataNode => - s_typeOfXmlDataNode ??= typeof(XmlDataNode); - - private static Type? s_typeOfNullable; - internal static Type TypeOfNullable => - s_typeOfNullable ??= typeof(Nullable<>); - - private static Type? s_typeOfReflectionPointer; - internal static Type TypeOfReflectionPointer => - s_typeOfReflectionPointer ??= typeof(System.Reflection.Pointer); - - private static Type? s_typeOfIDictionaryGeneric; - internal static Type TypeOfIDictionaryGeneric => - s_typeOfIDictionaryGeneric ??= typeof(IDictionary<,>); - - private static Type? s_typeOfIDictionary; - internal static Type TypeOfIDictionary => - s_typeOfIDictionary ??= typeof(IDictionary); - - private static Type? s_typeOfIListGeneric; - internal static Type TypeOfIListGeneric => - s_typeOfIListGeneric ??= typeof(IList<>); - - private static Type? s_typeOfIList; - internal static Type TypeOfIList => - s_typeOfIList ??= typeof(IList); - - private static Type? s_typeOfICollectionGeneric; - internal static Type TypeOfICollectionGeneric => - s_typeOfICollectionGeneric ??= typeof(ICollection<>); - - private static Type? s_typeOfICollection; - internal static Type TypeOfICollection => - s_typeOfICollection ??= typeof(ICollection); - - private static Type? s_typeOfIEnumerableGeneric; - internal static Type TypeOfIEnumerableGeneric => - s_typeOfIEnumerableGeneric ??= typeof(IEnumerable<>); - - private static Type? s_typeOfIEnumerable; - internal static Type TypeOfIEnumerable => - s_typeOfIEnumerable ??= typeof(IEnumerable); - - private static Type? s_typeOfIEnumeratorGeneric; - internal static Type TypeOfIEnumeratorGeneric => - s_typeOfIEnumeratorGeneric ??= typeof(IEnumerator<>); - - private static Type? s_typeOfIEnumerator; - internal static Type TypeOfIEnumerator => - s_typeOfIEnumerator ??= typeof(IEnumerator); - - private static Type? s_typeOfKeyValuePair; - internal static Type TypeOfKeyValuePair => - s_typeOfKeyValuePair ??= typeof(KeyValuePair<,>); - - private static Type? s_typeOfKeyValue; - internal static Type TypeOfKeyValue => - s_typeOfKeyValue ??= typeof(KeyValue<,>); - - private static Type? s_typeOfIDictionaryEnumerator; - internal static Type TypeOfIDictionaryEnumerator => - s_typeOfIDictionaryEnumerator ??= typeof(IDictionaryEnumerator); - - private static Type? s_typeOfDictionaryEnumerator; - internal static Type TypeOfDictionaryEnumerator => - s_typeOfDictionaryEnumerator ??= typeof(CollectionDataContract.DictionaryEnumerator); - - private static Type? s_typeOfGenericDictionaryEnumerator; - internal static Type TypeOfGenericDictionaryEnumerator => - s_typeOfGenericDictionaryEnumerator ??= typeof(CollectionDataContract.GenericDictionaryEnumerator<,>); - - private static Type? s_typeOfDictionaryGeneric; - internal static Type TypeOfDictionaryGeneric => - s_typeOfDictionaryGeneric ??= typeof(Dictionary<,>); - - private static Type? s_typeOfHashtable; - internal static Type TypeOfHashtable - { - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - get => s_typeOfHashtable ??= TypeOfDictionaryGeneric.MakeGenericType(TypeOfObject, TypeOfObject); - } - - private static Type? s_typeOfXmlElement; - internal static Type TypeOfXmlElement => - s_typeOfXmlElement ??= typeof(XmlElement); - - private static Type? s_typeOfXmlNodeArray; - internal static Type TypeOfXmlNodeArray => - s_typeOfXmlNodeArray ??= typeof(XmlNode[]); - - private static Type? s_typeOfDBNull; - internal static Type TypeOfDBNull => - s_typeOfDBNull ??= typeof(DBNull); - - private static Uri? s_dataContractXsdBaseNamespaceUri; - internal static Uri DataContractXsdBaseNamespaceUri => - s_dataContractXsdBaseNamespaceUri ??= new Uri(DataContractXsdBaseNamespace); - - public const bool DefaultIsRequired = false; - public const bool DefaultEmitDefaultValue = true; - public const int DefaultOrder = 0; - public const bool DefaultIsReference = false; - // The value string.Empty aids comparisons (can do simple length checks - // instead of string comparison method calls in IL.) - public static readonly string NewObjectId = string.Empty; - public const string NullObjectId = null; - public const string FullSRSInternalsVisiblePattern = @"^[\s]*System\.Runtime\.Serialization[\s]*,[\s]*PublicKey[\s]*=[\s]*(?i:00240000048000009400000006020000002400005253413100040000010001008d56c76f9e8649383049f383c44be0ec204181822a6c31cf5eb7ef486944d032188ea1d3920763712ccb12d75fb77e9811149e6148e5d32fbaab37611c1878ddc19e20ef135d0cb2cff2bfec3d115810c3d9069638fe4be215dbf795861920e5ab6f7db2e2ceef136ac23d5dd2bf031700aec232f6c6b1c785b4305c123b37ab)[\s]*$"; - [RegexGenerator(FullSRSInternalsVisiblePattern)] - public static partial Regex FullSRSInternalsVisibleRegex(); - public const char SpaceChar = ' '; - public const char OpenBracketChar = '['; - public const char CloseBracketChar = ']'; - public const char CommaChar = ','; - public const string Space = " "; - public const string XsiPrefix = "i"; - public const string XsdPrefix = "x"; - public const string SerPrefix = "z"; - public const string SerPrefixForSchema = "ser"; - public const string ElementPrefix = "q"; - public const string DataContractXsdBaseNamespace = "http://schemas.datacontract.org/2004/07/"; - public const string DataContractXmlNamespace = DataContractXsdBaseNamespace + "System.Xml"; - public const string SchemaInstanceNamespace = "http://www.w3.org/2001/XMLSchema-instance"; - public const string SchemaNamespace = "http://www.w3.org/2001/XMLSchema"; - public const string XsiNilLocalName = "nil"; - public const string XsiTypeLocalName = "type"; - public const string TnsPrefix = "tns"; - public const string OccursUnbounded = "unbounded"; - public const string AnyTypeLocalName = "anyType"; - public const string StringLocalName = "string"; - public const string IntLocalName = "int"; - public const string True = "true"; - public const string False = "false"; - public const string ArrayPrefix = "ArrayOf"; - public const string XmlnsNamespace = "http://www.w3.org/2000/xmlns/"; - public const string XmlnsPrefix = "xmlns"; - public const string SchemaLocalName = "schema"; - public const string CollectionsNamespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays"; - public const string DefaultClrNamespace = "GeneratedNamespace"; - public const string DefaultTypeName = "GeneratedType"; - public const string DefaultGeneratedMember = "GeneratedMember"; - public const string DefaultFieldSuffix = "Field"; - public const string DefaultPropertySuffix = "Property"; - public const string DefaultMemberSuffix = "Member"; - public const string NameProperty = "Name"; - public const string NamespaceProperty = "Namespace"; - public const string OrderProperty = "Order"; - public const string IsReferenceProperty = "IsReference"; - public const string IsRequiredProperty = "IsRequired"; - public const string EmitDefaultValueProperty = "EmitDefaultValue"; - public const string ClrNamespaceProperty = "ClrNamespace"; - public const string ItemNameProperty = "ItemName"; - public const string KeyNameProperty = "KeyName"; - public const string ValueNameProperty = "ValueName"; - public const string SerializationInfoPropertyName = "SerializationInfo"; - public const string SerializationInfoFieldName = "info"; - public const string NodeArrayPropertyName = "Nodes"; - public const string NodeArrayFieldName = "nodesField"; - public const string ExportSchemaMethod = "ExportSchema"; - public const string IsAnyProperty = "IsAny"; - public const string ContextFieldName = "context"; - public const string GetObjectDataMethodName = "GetObjectData"; - public const string GetEnumeratorMethodName = "GetEnumerator"; - public const string MoveNextMethodName = "MoveNext"; - public const string AddValueMethodName = "AddValue"; - public const string CurrentPropertyName = "Current"; - public const string ValueProperty = "Value"; - public const string EnumeratorFieldName = "enumerator"; - public const string SerializationEntryFieldName = "entry"; - public const string ExtensionDataSetMethod = "set_ExtensionData"; - public const string ExtensionDataSetExplicitMethod = "System.Runtime.Serialization.IExtensibleDataObject.set_ExtensionData"; - public const string ExtensionDataObjectPropertyName = "ExtensionData"; - public const string ExtensionDataObjectFieldName = "extensionDataField"; - public const string AddMethodName = "Add"; - public const string GetCurrentMethodName = "get_Current"; - // NOTE: These values are used in schema below. If you modify any value, please make the same change in the schema. - public const string SerializationNamespace = "http://schemas.microsoft.com/2003/10/Serialization/"; - public const string ClrTypeLocalName = "Type"; - public const string ClrAssemblyLocalName = "Assembly"; - public const string IsValueTypeLocalName = "IsValueType"; - public const string EnumerationValueLocalName = "EnumerationValue"; - public const string SurrogateDataLocalName = "Surrogate"; - public const string GenericTypeLocalName = "GenericType"; - public const string GenericParameterLocalName = "GenericParameter"; - public const string GenericNameAttribute = "Name"; - public const string GenericNamespaceAttribute = "Namespace"; - public const string GenericParameterNestedLevelAttribute = "NestedLevel"; - public const string IsDictionaryLocalName = "IsDictionary"; - public const string ActualTypeLocalName = "ActualType"; - public const string ActualTypeNameAttribute = "Name"; - public const string ActualTypeNamespaceAttribute = "Namespace"; - public const string DefaultValueLocalName = "DefaultValue"; - public const string EmitDefaultValueAttribute = "EmitDefaultValue"; - public const string IdLocalName = "Id"; - public const string RefLocalName = "Ref"; - public const string ArraySizeLocalName = "Size"; - public const string KeyLocalName = "Key"; - public const string ValueLocalName = "Value"; - public const string MscorlibAssemblyName = "0"; - public const string ParseMethodName = "Parse"; - public const string SafeSerializationManagerName = "SafeSerializationManager"; - public const string SafeSerializationManagerNamespace = "http://schemas.datacontract.org/2004/07/System.Runtime.Serialization"; - public const string ISerializableFactoryTypeLocalName = "FactoryType"; - public const string SerializationSchema = @" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"; - -#endif } } diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ImportOptions.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ImportOptions.cs index 706c9fd3efeaa..a86df32ba3bf3 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ImportOptions.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ImportOptions.cs @@ -9,7 +9,7 @@ namespace System.Runtime.Serialization.Schema { - public class ImportOptions + public sealed class ImportOptions { private ICollection? _referencedTypes; private ICollection? _referencedCollectionTypes; @@ -19,7 +19,7 @@ public class ImportOptions public bool EnableDataBinding { get; set; } - public ISerializationExtendedSurrogateProvider? ExtendedSurrogateProvider { get; set; } + public ISerializationSurrogateProvider? SurrogateProvider { get; set; } public bool GenerateInternal { get; set; } diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs index 51424344e873a..b23a62cec13aa 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs @@ -13,7 +13,7 @@ namespace System.Runtime.Serialization.Schema { - public class XsdDataContractExporter + public sealed class XsdDataContractExporter { private ExportOptions? _options; private XmlSchemaSet? _schemas; @@ -39,10 +39,6 @@ public XmlSchemaSet Schemas get { XmlSchemaSet schemaSet = GetSchemaSet(); - // TODO smolloy - what to do. Looks like this particular method can live easily anywhere we want. But... - // the home of SchemaImporter is yet to be determined. If it lives externally here, then use it like this. - // If it lives internally... which is probably preferred if possible... then we will need to duplicate this - // method out here, or find a way to call into it over there. DataContractSet.CompileSchemaSet(schemaSet); return schemaSet; } @@ -64,11 +60,7 @@ private DataContractSet DataContractSet { if (_dataContractSet == null) { - // TODO smolloy - This used to pass the surrogate to DCSet in 4.8. We can't do that here. We need to pair - // the two somehow. For now, just pass nulls and see where down the line we need to resurface the surrogate provider - // so we can best figure how to pair these. - // _dataContractSet = new DataContractSet(Options?.GetSurrogate(), null, null); - _dataContractSet = new DataContractSet(null, null, null); + _dataContractSet = new DataContractSet(Options?.SurrogateProvider, null, null); } return _dataContractSet; } @@ -187,11 +179,6 @@ public XmlQualifiedName GetSchemaTypeName(Type type) { return new XmlQualifiedName(dataContract.TopLevelElementName!.Value, dataContract.TopLevelElementNamespace!.Value); } - // TODO smolloy - the above is now done with the new API below. - //if (dataContract.GetRootElementName(out XmlQualifiedName? root)) - //{ - // return root; - //} else { return null; @@ -201,7 +188,6 @@ public XmlQualifiedName GetSchemaTypeName(Type type) [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] private Type GetSurrogatedType(Type type) { - // TODO smolloy - This is the DCS surrogate, not the extended one. Hmmmmm... guess inheritence is still the way to go. ISerializationSurrogateProvider? surrogate = Options?.SurrogateProvider; if (surrogate != null) type = DataContract.GetSurrogateType(surrogate, type); @@ -227,9 +213,6 @@ private void Export() { AddKnownTypes(); DataContractSet.ExportSchemaSet(GetSchemaSet()); - // TODO smolloy - done with the new API above. Keeps SchemaExporter internal. - //SchemaExporter schemaExporter = new SchemaExporter(GetSchemaSet(), DataContractSet); - //schemaExporter.Export(); } [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs index c9dea9112dc5c..1eeab709c599a 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs @@ -12,7 +12,7 @@ namespace System.Runtime.Serialization.Schema { - public class XsdDataContractImporter + public sealed class XsdDataContractImporter { private CodeCompileUnit _codeCompileUnit = null!; // Not directly referenced. Always lazy initialized by property getter. private DataContractSet? _dataContractSet; @@ -42,13 +42,13 @@ private DataContractSet DataContractSet if (_dataContractSet == null) { _dataContractSet = Options == null ? new DataContractSet(null, null, null) : - new DataContractSet(Options.ExtendedSurrogateProvider, Options.ReferencedTypes, Options.ReferencedCollectionTypes); + new DataContractSet(Options.SurrogateProvider, Options.ReferencedTypes, Options.ReferencedCollectionTypes); } return _dataContractSet; } } - [RequiresUnreferencedCode("Placeholder Warning")] + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public void Import(XmlSchemaSet schemas) { if (schemas == null) @@ -57,7 +57,7 @@ public void Import(XmlSchemaSet schemas) InternalImport(schemas, null, s_emptyElementArray, s_emptyTypeNameArray); } - [RequiresUnreferencedCode("Placeholder Warning")] + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public void Import(XmlSchemaSet schemas, ICollection typeNames) { if (schemas == null) @@ -69,7 +69,7 @@ public void Import(XmlSchemaSet schemas, ICollection typeNames InternalImport(schemas, typeNames, s_emptyElementArray, s_emptyTypeNameArray); } - [RequiresUnreferencedCode("Placeholder Warning")] + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public void Import(XmlSchemaSet schemas, XmlQualifiedName typeName) { if (schemas == null) @@ -82,7 +82,7 @@ public void Import(XmlSchemaSet schemas, XmlQualifiedName typeName) InternalImport(schemas, SingleTypeNameArray, s_emptyElementArray, s_emptyTypeNameArray); } - [RequiresUnreferencedCode("Placeholder Warning")] + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public XmlQualifiedName? Import(XmlSchemaSet schemas, XmlSchemaElement element) { if (schemas == null) @@ -96,7 +96,7 @@ public void Import(XmlSchemaSet schemas, XmlQualifiedName typeName) return SingleTypeNameArray[0]; } - [RequiresUnreferencedCode("Placeholder Warning")] + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public bool CanImport(XmlSchemaSet schemas) { if (schemas == null) @@ -105,7 +105,7 @@ public bool CanImport(XmlSchemaSet schemas) return InternalCanImport(schemas, null, s_emptyElementArray, s_emptyTypeNameArray); } - [RequiresUnreferencedCode("Placeholder Warning")] + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public bool CanImport(XmlSchemaSet schemas, ICollection typeNames) { if (schemas == null) @@ -117,7 +117,7 @@ public bool CanImport(XmlSchemaSet schemas, ICollection typeNa return InternalCanImport(schemas, typeNames, s_emptyElementArray, s_emptyTypeNameArray); } - [RequiresUnreferencedCode("Placeholder Warning")] + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public bool CanImport(XmlSchemaSet schemas, XmlQualifiedName typeName) { if (schemas == null) @@ -129,7 +129,7 @@ public bool CanImport(XmlSchemaSet schemas, XmlQualifiedName typeName) return InternalCanImport(schemas, new XmlQualifiedName[] { typeName }, s_emptyElementArray, s_emptyTypeNameArray); } - [RequiresUnreferencedCode("Placeholder Warning")] + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public bool CanImport(XmlSchemaSet schemas, XmlSchemaElement element) { if (schemas == null) @@ -142,7 +142,7 @@ public bool CanImport(XmlSchemaSet schemas, XmlSchemaElement element) return InternalCanImport(schemas, s_emptyTypeNameArray, SingleElementArray, SingleTypeNameArray); } - [RequiresUnreferencedCode("Placeholder Warning")] + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public CodeTypeReference GetCodeTypeReference(XmlQualifiedName typeName) { DataContract dataContract = FindDataContract(typeName); @@ -150,7 +150,7 @@ public CodeTypeReference GetCodeTypeReference(XmlQualifiedName typeName) return codeExporter.GetCodeTypeReference(dataContract); } - [RequiresUnreferencedCode("Placeholder Warning")] + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public CodeTypeReference GetCodeTypeReference(XmlQualifiedName typeName, XmlSchemaElement element) { if (element == null) @@ -162,7 +162,7 @@ public CodeTypeReference GetCodeTypeReference(XmlQualifiedName typeName, XmlSche return codeExporter.GetElementTypeReference(dataContract, element.IsNillable); } - [RequiresUnreferencedCode("Placeholder Warning")] + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] internal DataContract FindDataContract(XmlQualifiedName typeName) { if (typeName == null) @@ -178,7 +178,7 @@ internal DataContract FindDataContract(XmlQualifiedName typeName) return dataContract; } - [RequiresUnreferencedCode("Placeholder Warning")] + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public ICollection? GetKnownTypeReferences(XmlQualifiedName typeName) { if (typeName == null) @@ -216,16 +216,13 @@ private XmlSchemaElement[] SingleElementArray } } - [RequiresUnreferencedCode("Placeholder Warning")] + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] private void InternalImport(XmlSchemaSet schemas, ICollection? typeNames, ICollection elements, XmlQualifiedName[] elementTypeNames/*filled on return*/) { DataContractSet? oldValue = (_dataContractSet == null) ? null : new DataContractSet(_dataContractSet); try { DataContractSet.ImportSchemaSet(schemas, typeNames, elements, elementTypeNames/*filled on return*/, ImportXmlDataType); - // TODO smolloy - The above used to be done as below... but to keep SchemaImporter internal it is now done as above. - //SchemaImporter schemaImporter = new SchemaImporter(schemas, typeNames, elements, elementTypeNames/*filled on return*/, DataContractSet, ImportXmlDataType); - //schemaImporter.Import(); CodeExporter codeExporter = new CodeExporter(DataContractSet, Options, CodeCompileUnit); codeExporter.Export(); @@ -245,16 +242,13 @@ private bool ImportXmlDataType } } - [RequiresUnreferencedCode("Placeholder Warning")] + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] private bool InternalCanImport(XmlSchemaSet schemas, ICollection? typeNames, ICollection elements, XmlQualifiedName[] elementTypeNames) { DataContractSet? oldValue = (_dataContractSet == null) ? null : new DataContractSet(_dataContractSet); try { DataContractSet.ImportSchemaSet(schemas, typeNames, elements, elementTypeNames/*filled on return*/, ImportXmlDataType); - // TODO smolloy - The above used to be done as below... but to keep SchemaImporter internal it is now done as above. - //SchemaImporter schemaImporter = new SchemaImporter(schemas, typeNames, elements, elementTypeNames, DataContractSet, ImportXmlDataType); - //schemaImporter.Import(); return true; } catch (ArgumentException) diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/_Stubs.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/_Stubs.cs deleted file mode 100644 index 7a16b139652e5..0000000000000 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/_Stubs.cs +++ /dev/null @@ -1,148 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// TODO smolloy - stubs. remove once API is determined. - -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Xml; -using System.Xml.Schema; - -using DataContractDictionary = System.Collections.Generic.Dictionary; - -namespace System.Runtime.Serialization.HideStubs -{ - public sealed class DataContractSet - { - // ======================================================================================================= - // These existed internal in Core - public DataContractSet(DataContractSet copySet) { } - public void Add(Type type) { } - public DataContract GetDataContract(Type type) { return new DataContract(); } - public IEnumerator> GetEnumerator() { return new Dictionary().GetEnumerator(); } - public Dictionary ProcessedContracts => new Dictionary(); - - - // ======================================================================================================= - // These existed internal in 4.8 and are brought back for schema support - public DataContractSet(object? a, object? b, object? c) { } - public DataContract? GetDataContract(XmlQualifiedName qname) { return null; } // Technically new. This was a this[] indexer in 4.8. - public DataContractDictionary? KnownTypesForObject { get; /*internal still OK for set, SchemaImporter.cs is the only writer.*/ } - - - // ======================================================================================================= - // These are new API's, internal or otherwise. All of them are simple wrappers or a gateway to an existing internal method - // on an internal type, except for the last. [GetReferencedTypeOnImport] - - // Forward to SchemaImporter.cs - public static void CompileSchemaSet(XmlSchemaSet schemaSet) { } - // Forward to SchemaExporter.cs - public void ExportSchemaSet(XmlSchemaSet schemaSet) { } - // Forward to SchemaImporter.cs - public void ImportSchemaSet(XmlSchemaSet schemaSet, ICollection? typeNames, ICollection elements, XmlQualifiedName[] elementTypeNames /*filled on return*/, bool importXmlDataType) { } - // Wrapper around a trio of internal methods of the same name with a dash of logic that was in but does not need to live in CodeExporter. - // Using this wrapper exposes one method instead of 3. - public bool TryGetReferencedType(XmlQualifiedName stableName, DataContract? dataContract, [NotNullWhen(true)] out Type? type) { type = null; return false; } - // Wrapper around GetSurrogateData - which is internal brought back for schema support. The wrapper allows us to keep knowledge/logic of - // surrogate providers internal to DataContractSet. - public bool TryGetSurrogateData(object key, out object? value) { value = null; return false; } - // This is new. Pushing surrogate functionality into DCSet so we don't have to manage surrogates externally. (Since ExtendedSurrogate is internal.) - public Type? GetReferencedTypeOnImport(DataContract dataContract) { return null; } // See the commented code in CodeExporter.cs for what this is supposed to do. - } - - public class DataMember - { - // ======================================================================================================= - // All were existing internal properties. - public bool EmitDefaultValue; - public bool IsNullable; - public bool IsRequired; - public DataContract MemberTypeContract = null!; // ** It isn't used externally, but MemberType kind of goes hand in logical hand here as well, no? - public string Name = string.Empty; - public int Order; - } - - public class GenericInfo - { - // ======================================================================================================= - // This entire class existed in 4.8 and was brought back for schema support. All API's here existed internal in 4.8. - public IList? Parameters => null; - public XmlQualifiedName StableName => XmlQualifiedName.Empty; // Can these stable names return null? - public XmlQualifiedName GetExpandedStableName() { return StableName; } - } - - public class DataContract - { - // ======================================================================================================= - // These existed internal in Core - public Type UnderlyingType => typeof(DataContract); - public Type OriginalUnderlyingType => UnderlyingType; - public XmlQualifiedName StableName { get => XmlQualifiedName.Empty; internal set { } } - public bool HasRoot { get; internal set; } - public bool IsBuiltInDataContract { get; } - public bool IsISerializable { get; internal set; } - public bool IsReference { get; internal set; } - public bool IsValueType { get; internal set; } - public XmlDictionaryString? TopLevelElementName { get; internal set; } - public XmlDictionaryString? TopLevelElementNamespace { get; internal set; } - public static bool IsTypeSerializable(Type type) { return false; } - public static DataContract GetDataContract(Type type) { return new DataContract(); } - public static DataContract? GetBuiltInDataContract(string name, string ns) { return null; } - public static XmlQualifiedName GetStableName(Type type) { return XmlQualifiedName.Empty; } - // This API exists and is used internally. It can easily be copied externally if we want to reduce the API surface here. - // But it's also a semi-logical exposure of a DC-intended static utility function. It makes sense to just expose and re-use it. - public static string EncodeLocalName(string localName) { return "string"; } - public XmlQualifiedName GetArrayTypeName(bool isNullable) { return XmlQualifiedName.Empty; } - - - // ======================================================================================================= - // These existed internal in 4.8 and are brought back for schema support - public GenericInfo? GenericInfo => null; - public DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) { return new DataContract(); } - - - // ======================================================================================================= - // These are new API's, internal or otherwise. - - // This one - similar to a couple DCSet API's - allows us to keep surrogate execution logic internal to DC/DCSet. - // Basically and entry to [surrogate_caller.GetDataContractType()] - public static Type GetSurrogateType(ISerializationSurrogateProvider surrogateProvider, Type type) { return type; } - } - - - - public class ClassDataContract : DataContract - { - // BaseContract - // Members - } - public class CollectionDataContract : DataContract - { - // IsCollection() static - This could be on base DataContract? - // IsDictionary - // IsItemTypeNullable - // ItemContract - // ItemName - // KeyName - // ValueName - } - public class EnumDataContract : DataContract - { - // BaseContractName - // GetBaseType << and ^^ can be combined into one Type GetType() - - // GetStringFromEnumValue() This is the one non-data item. Should we bring an enum-specific function up to DataContract? or perhaps this and IsUlong can go away if Values just returns int[] or string[] appropriately - // IsULong - // IsFlags - // Members - // Values - } - public class PrimitiveDataContract : DataContract { } - public class XmlDataContract : DataContract - { - // IsAnonymous - // IsTopLevelElementNullable - // IsTypeDefinedOnImport - // XsdType - } -} diff --git a/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs b/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs index 706625b147b48..844fcef928779 100644 --- a/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs +++ b/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs @@ -124,7 +124,7 @@ public sealed partial class DataContractSet [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public void Add(Type type) { throw null; } public static void CompileSchemaSet(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; } - public DataContractSet(ISerializationExtendedSurrogateProvider? dataContractExtendedSurrogate, System.Collections.Generic.ICollection? referencedTypes, System.Collections.Generic.ICollection? referencedCollectionTypes) { throw null; } + public DataContractSet(ISerializationSurrogateProvider? dataContractSurrogate, System.Collections.Generic.ICollection? referencedTypes, System.Collections.Generic.ICollection? referencedCollectionTypes) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public DataContractSet(DataContractSet dataContractSet) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] From ec2518dc1552ac653092f7acac220ac89b13bada Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Fri, 8 Jul 2022 15:22:10 -0700 Subject: [PATCH 07/33] Addressed some nits and PR feedback on API. --- .../Serialization/ClassDataContract.cs | 40 ++++------------ .../Serialization/CollectionDataContract.cs | 6 +-- .../Runtime/Serialization/DataContract.cs | 8 ++-- .../Serialization/DataContractSerializer.cs | 2 +- .../Runtime/Serialization/DataContractSet.cs | 10 ++-- .../Runtime/Serialization/DataMember.cs | 2 +- .../Runtime/Serialization/EnumDataContract.cs | 2 +- .../GenericParameterDataContract.cs | 2 +- .../Json/DataContractJsonSerializer.cs | 3 +- .../Serialization/Json/JsonXmlDataContract.cs | 6 ++- .../Serialization/PrimitiveDataContract.cs | 2 +- .../Runtime/Serialization/SchemaHelper.cs | 2 +- .../Runtime/Serialization/SchemaImporter.cs | 8 ++-- .../Runtime/Serialization/ScopedKnownTypes.cs | 2 +- .../Runtime/Serialization/XmlDataContract.cs | 10 ++-- .../Serialization/XmlObjectSerializer.cs | 2 +- .../XmlObjectSerializerContext.cs | 4 +- .../XmlObjectSerializerReadContext.cs | 2 +- .../System.Runtime.Serialization.Schema.cs | 2 +- .../Serialization/Schema/CodeExporter.cs | 10 ++-- .../ref/System.Runtime.Serialization.Xml.cs | 47 +++++++++---------- src/libraries/oob.proj | 2 +- 22 files changed, 78 insertions(+), 96 deletions(-) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs index bad42886f0708..e276d83da065a 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs @@ -11,13 +11,13 @@ using System.Threading; using System.Xml; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.IDictionary; namespace System.Runtime.Serialization { internal sealed class ClassDataContract : DataContract { - internal const string ContractTypeString = "ClassDataContract"; + internal const string ContractTypeString = nameof(ClassDataContract); public override string? ContractType => ContractTypeString; public XmlDictionaryString[]? ContractNamespaces; @@ -121,7 +121,7 @@ public override bool IsISerializable internal bool HasExtensionData => _helper.HasExtensionData; - internal string? SerialiazationExceptionMessage => _helper.SerializationExceptionMessage; + internal string? SerializationExceptionMessage => _helper.SerializationExceptionMessage; internal string? DeserializationExceptionMessage => _helper.DeserializationExceptionMessage; internal bool IsReadOnlyContract => DeserializationExceptionMessage != null; @@ -599,10 +599,6 @@ private sealed class ClassDataContractCriticalHelper : DataContract.DataContract private bool _hasDataContract; private bool _hasExtensionData; - private XmlDictionaryString?[]? _childElementNamespaces; - private XmlFormatClassReaderDelegate? _xmlFormatReaderDelegate; - private XmlFormatClassWriterDelegate? _xmlFormatWriterDelegate; - public XmlDictionaryString[]? ContractNamespaces; public XmlDictionaryString[]? MemberNames; public XmlDictionaryString[]? MemberNamespaces; @@ -688,7 +684,7 @@ internal ClassDataContractCriticalHelper([DynamicallyAccessedMembers(DataContrac { if (BaseClassContract.IsReadOnlyContract) { - _serializationExceptionMessage = BaseClassContract.SerialiazationExceptionMessage; + _serializationExceptionMessage = BaseClassContract.SerializationExceptionMessage; } baseMemberCount = BaseClassContract.MemberNames!.Length; MemberNames = new XmlDictionaryString[Members.Count + baseMemberCount]; @@ -1193,14 +1189,6 @@ internal override DataContractDictionary? KnownDataContracts [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get { - // NOTE TODO smolloy - Oddly, this shortcut was not here in NetFx. I'm not sure this was added strictly as a perf-optimization though. - // See https://github.com/dotnet/runtime/commit/5d2dba7ffcc4ad6a11a570f5bd8d1964000099ea - // This shouldn't change between invocations though, right? So seems like a good thing to leave in. - if (_knownDataContracts != null) - { - return _knownDataContracts; - } - if (!_isKnownTypeAttributeChecked && UnderlyingType != null) { lock (this) @@ -1264,23 +1252,11 @@ internal override bool IsISerializable return ctor; } - internal XmlFormatClassWriterDelegate? XmlFormatWriterDelegate - { - get => _xmlFormatWriterDelegate; - set => _xmlFormatWriterDelegate = value; - } + internal XmlFormatClassWriterDelegate? XmlFormatWriterDelegate { get; set; } - internal XmlFormatClassReaderDelegate? XmlFormatReaderDelegate - { - get => _xmlFormatReaderDelegate; - set => _xmlFormatReaderDelegate = value; - } + internal XmlFormatClassReaderDelegate? XmlFormatReaderDelegate { get; set; } - public XmlDictionaryString?[]? ChildElementNamespaces - { - get => _childElementNamespaces; - set => _childElementNamespaces = value; - } + public XmlDictionaryString?[]? ChildElementNamespaces { get; set; } private static Type[] SerInfoCtorArgs => s_serInfoCtorArgs ??= new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }; @@ -1317,7 +1293,7 @@ public int Compare(Member x, Member y) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) + public override DataContract BindGenericParameters(DataContract[] paramContracts, IDictionary boundContracts) { Type type = UnderlyingType; if (!type.IsGenericType || !type.ContainsGenericParameters) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs index 320e73d52d2f1..c67bd94ceb6f7 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs @@ -12,7 +12,7 @@ using System.Threading; using System.Xml; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.IDictionary; namespace System.Runtime.Serialization { @@ -77,7 +77,7 @@ internal enum CollectionKind : byte internal sealed class CollectionDataContract : DataContract { - internal const string ContractTypeString = "CollectionDataContract"; + internal const string ContractTypeString = nameof(CollectionDataContract); public override string? ContractType => ContractTypeString; private XmlDictionaryString _collectionItemName; @@ -1339,7 +1339,7 @@ private static bool IsKnownInterface(Type type) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) + public override DataContract BindGenericParameters(DataContract[] paramContracts, IDictionary boundContracts) { DataContract boundContract; if (boundContracts.TryGetValue(this, out boundContract!)) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs index c3d7f653c8f86..9e903cb007f4e 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs @@ -14,7 +14,7 @@ using System.Text; using System.Xml; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.IDictionary; namespace System.Runtime.Serialization { @@ -274,7 +274,7 @@ internal virtual void WriteRootElement(XmlWriterDelegator writer, XmlDictionaryS } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public virtual DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) + public virtual DataContract BindGenericParameters(DataContract[] paramContracts, IDictionary boundContracts) { return this; } @@ -2026,7 +2026,7 @@ private static void ImportKnownTypeAttributes(Type? type, Dictionary collectionDataContract.ItemType.GetGenericTypeDefinition() == Globals.TypeOfKeyValue) { DataContract itemDataContract = DataContract.GetDataContract(Globals.TypeOfKeyValuePair.MakeGenericType(collectionDataContract.ItemType.GetGenericArguments())); - knownDataContracts ??= new DataContractDictionary(); + knownDataContracts ??= new Dictionary(); knownDataContracts.TryAdd(itemDataContract.StableName, itemDataContract); } @@ -2050,7 +2050,7 @@ internal static void CheckAndAdd(Type type, Dictionary typesChecked, DataContract dataContract = DataContract.GetDataContract(type); if (nameToDataContractTable == null) { - nameToDataContractTable = new DataContractDictionary(); + nameToDataContractTable = new Dictionary(); } else if (nameToDataContractTable.TryGetValue(dataContract.StableName, out DataContract? alreadyExistingContract)) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs index c0d6cfec922d8..80bf0f84ec834 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs @@ -8,7 +8,7 @@ using System.Runtime.CompilerServices; using System.Xml; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.IDictionary; namespace System.Runtime.Serialization { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs index 789cc31a19e20..dd9d3222f4b51 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs @@ -8,7 +8,7 @@ using System.Text; using System.Xml.Schema; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.IDictionary; namespace System.Runtime.Serialization { @@ -54,10 +54,10 @@ public DataContractSet(DataContractSet dataContractSet) } } - internal DataContractDictionary Contracts => - _contracts ??= new DataContractDictionary(); + public DataContractDictionary Contracts => + _contracts ??= new Dictionary(); - public Dictionary ProcessedContracts => + public IDictionary ProcessedContracts => _processedContracts ??= new Dictionary(); private Hashtable SurrogateDataTable => _surrogateDataTable ??= new Hashtable(); @@ -515,7 +515,7 @@ internal void SetContractProcessed(DataContract dataContract) ProcessedContracts.Add(dataContract, dataContract); } - public IEnumerator> GetEnumerator() + internal IEnumerator> GetEnumerator() { return Contracts.GetEnumerator(); } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs index 15971d3a8845a..d612ba2254d83 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs @@ -283,7 +283,7 @@ internal bool RequiresMemberAccessForSet() } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal DataMember BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) + internal DataMember BindGenericParameters(DataContract[] paramContracts, IDictionary boundContracts) { DataContract memberTypeContract = MemberTypeContract.BindGenericParameters(paramContracts, boundContracts); DataMember boundDataMember = new DataMember(memberTypeContract, diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs index 1835f807a41a4..75793ed29c275 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs @@ -14,7 +14,7 @@ namespace System.Runtime.Serialization { internal sealed class EnumDataContract : DataContract { - internal const string ContractTypeString = "EnumDataContract"; + internal const string ContractTypeString = nameof(EnumDataContract); public override string? ContractType => ContractTypeString; private readonly EnumDataContractCriticalHelper _helper; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs index 2c355c8118161..fa99733df7699 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs @@ -40,7 +40,7 @@ internal GenericParameterDataContractCriticalHelper( } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary boundContracts) + public override DataContract BindGenericParameters(DataContract[] paramContracts, IDictionary boundContracts) { return paramContracts[ParameterPosition]; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs index 4c033708d591b..d4b7963940365 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs @@ -13,7 +13,8 @@ using System.Security; using System.Text; using System.Xml; -using DataContractDictionary = System.Collections.Generic.Dictionary; + +using DataContractDictionary = System.Collections.Generic.IDictionary; namespace System.Runtime.Serialization.Json { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonXmlDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonXmlDataContract.cs index c38615a5ab805..9b292431b5bb6 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonXmlDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonXmlDataContract.cs @@ -7,6 +7,8 @@ using System.Text; using System.Xml; +using DataContractDictionary = System.Collections.Generic.IDictionary; + namespace System.Runtime.Serialization.Json { internal sealed class JsonXmlDataContract : JsonDataContract @@ -62,12 +64,12 @@ private static List GetKnownTypesFromContext(XmlObjectSerializerContext? c if (context != null) { List stableNames = new List(); - Dictionary[] entries = context.scopedKnownTypes.dataContractDictionaries; + DataContractDictionary[] entries = context.scopedKnownTypes.dataContractDictionaries; if (entries != null) { for (int i = 0; i < entries.Length; i++) { - Dictionary entry = entries[i]; + DataContractDictionary entry = entries[i]; if (entry != null) { foreach (KeyValuePair pair in entry) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs index b6a305f376da9..098927687e433 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs @@ -13,7 +13,7 @@ namespace System.Runtime.Serialization { internal abstract class PrimitiveDataContract : DataContract { - internal const string ContractTypeString = "PrimitiveDataContract"; + internal const string ContractTypeString = nameof(PrimitiveDataContract); public override string? ContractType => ContractTypeString; internal static readonly PrimitiveDataContract NullContract = new NullPrimitiveDataContract(); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs index 9c0f606d0542d..5884ce28ca95e 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs @@ -7,7 +7,7 @@ using System.Collections; using System.Collections.Generic; -using SchemaObjectDictionary = System.Collections.Generic.Dictionary; +using SchemaObjectDictionary = System.Collections.Generic.IDictionary; namespace System.Runtime.Serialization { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs index 1aad19d755598..3df05396f910d 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs @@ -12,8 +12,8 @@ using System.Xml; using System.Xml.Schema; -using DataContractDictionary = System.Collections.Generic.Dictionary; -using SchemaObjectDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.IDictionary; +using SchemaObjectDictionary = System.Collections.Generic.IDictionary; namespace System.Runtime.Serialization { @@ -236,7 +236,7 @@ private void ImportKnownTypesForObject() internal SchemaObjectDictionary CreateSchemaObjects() { - SchemaObjectDictionary schemaObjects = new SchemaObjectDictionary(); + SchemaObjectDictionary schemaObjects = new Dictionary(); ICollection schemaList = _schemaSet.Schemas(); List knownTypesForObject = new List(); schemaObjects.Add(SchemaExporter.AnytypeQualifiedName, new SchemaObjectInfo(null, null, null, knownTypesForObject)); @@ -907,7 +907,7 @@ private void ImportBaseContract(XmlQualifiedName baseTypeName, ClassDataContract DataContractDictionary? knownDataContracts = ancestorDataContract.KnownDataContracts; if (knownDataContracts == null) { - knownDataContracts = new DataContractDictionary(); + knownDataContracts = new Dictionary(); ancestorDataContract.KnownDataContracts = knownDataContracts; } knownDataContracts.Add(dataContract.StableName, dataContract); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ScopedKnownTypes.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ScopedKnownTypes.cs index 727fc4e6c4953..2bc716206d5d2 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ScopedKnownTypes.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ScopedKnownTypes.cs @@ -3,7 +3,7 @@ using System; using System.Xml; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.IDictionary; namespace System.Runtime.Serialization { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs index 9e4e6921e284c..a2fd225957163 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs @@ -12,14 +12,14 @@ using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.IDictionary; namespace System.Runtime.Serialization { internal delegate IXmlSerializable CreateXmlSerializableDelegate(); public sealed class XmlDataContract : DataContract { - internal const string ContractTypeString = "XmlDataContract"; + internal const string ContractTypeString = nameof(XmlDataContract); public override string? ContractType => ContractTypeString; private readonly XmlDataContractCriticalHelper _helper; @@ -48,7 +48,11 @@ public bool IsAnonymous get => _helper.IsAnonymous; } - public void SetIsValueType(bool isValueType) => IsValueType = isValueType; + public new bool IsValueType + { + get => _helper.IsValueType; + set => _helper.IsValueType = value; + } public override bool HasRoot { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializer.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializer.cs index c42bc3bb61893..7eebd5560e6de 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializer.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializer.cs @@ -10,7 +10,7 @@ using System.Security; using System.Text; using System.Xml; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.IDictionary; namespace System.Runtime.Serialization { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs index b0de63121dd22..79802e6cf99ce 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs @@ -8,7 +8,7 @@ using System.Reflection; using System.Security; using System.Xml; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.IDictionary; namespace System.Runtime.Serialization { @@ -177,7 +177,7 @@ internal virtual DataContractDictionary? SerializerKnownDataContracts internal static DataContractDictionary? GetDataContractsForKnownTypes(IList knownTypeList) { if (knownTypeList == null) return null; - DataContractDictionary dataContracts = new DataContractDictionary(); + DataContractDictionary dataContracts = new Dictionary(); Dictionary typesChecked = new Dictionary(); for (int i = 0; i < knownTypeList.Count; i++) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContext.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContext.cs index 628640e4d1e19..b7206cf298983 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContext.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContext.cs @@ -10,7 +10,7 @@ using System.Text; using System.Xml; using System.Xml.Serialization; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.IDictionary; namespace System.Runtime.Serialization { diff --git a/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.cs b/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.cs index 008a0544fc205..2316e6b0677c5 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.cs @@ -24,7 +24,7 @@ public sealed partial class ImportOptions public System.Collections.Generic.ICollection ReferencedCollectionTypes { get { throw null; } } public System.Collections.Generic.ICollection ReferencedTypes { get { throw null; } } } - public sealed class XsdDataContractExporter + public sealed partial class XsdDataContractExporter { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public bool CanExport(System.Collections.Generic.ICollection assemblies) { throw null; } diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs index fbb3467ea73a3..3bfac8cf86a73 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs @@ -18,7 +18,7 @@ using System.Xml.Schema; using System.Xml.Serialization; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.IDictionary; using ExceptionUtil = System.Runtime.Serialization.Schema.DiagnosticUtility.ExceptionUtility; namespace System.Runtime.Serialization.Schema @@ -48,7 +48,7 @@ internal CodeExporter(DataContractSet dataContractSet, ImportOptions? options, C _clrNamespaces = new Dictionary(StringComparer.OrdinalIgnoreCase); // Update namespace tables for DataContract(s) that are already processed - foreach (KeyValuePair pair in dataContractSet) + foreach (KeyValuePair pair in dataContractSet.Contracts) { DataContract dataContract = pair.Value; if (!(dataContract.IsBuiltInDataContract || dataContract.Is(DataContractType.ClassDataContract))) @@ -210,7 +210,7 @@ internal void Export() { try { - foreach (KeyValuePair pair in _dataContractSet) + foreach (KeyValuePair pair in _dataContractSet.Contracts) { DataContract dataContract = pair.Value; if (dataContract.IsBuiltInDataContract) @@ -521,7 +521,7 @@ private static CodeTypeDeclaration CreateTypeDeclaration(string typeName, DataCo } else { - xmlContract.SetIsValueType(type.IsValueType); + xmlContract.IsValueType = type.IsValueType; xmlContract.IsTypeDefinedOnImport = true; } return GetCodeTypeReference(type); @@ -994,7 +994,7 @@ private static void AddKnownTypeContracts(DataContract classDataContract, DataCo Debug.Assert(classDataContract.Is(DataContractType.ClassDataContract)); if (classDataContract.KnownDataContracts == null) - classDataContract.KnownDataContracts = new DataContractDictionary(); + classDataContract.KnownDataContracts = new Dictionary(); foreach (KeyValuePair pair in knownContracts) { diff --git a/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs b/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs index 844fcef928779..0542fbc6867b5 100644 --- a/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs +++ b/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs @@ -8,10 +8,10 @@ namespace System.Runtime.Serialization { public abstract partial class DataContract { - public DataContract? BaseContract { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } } + public virtual DataContract? BaseContract { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public DataContract BindGenericParameters(DataContract[] paramContracts, System.Collections.Generic.Dictionary boundContracts) { throw null; } - public string? ContractType { get { throw null; } } + public virtual DataContract BindGenericParameters(DataContract[] paramContracts, System.Collections.Generic.IDictionary boundContracts) { throw null; } + public virtual string? ContractType { get { throw null; } } internal DataContract(DataContractCriticalHelper helper) { } internal const System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes DataContractPreserveMemberTypes = System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods | @@ -21,9 +21,9 @@ internal DataContract(DataContractCriticalHelper helper) { } System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties; public static string EncodeLocalName(string localName) { throw null; } - public GenericInfo? GenericInfo { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } } + public virtual GenericInfo? GenericInfo { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public System.Xml.XmlQualifiedName GetArrayTypeName(bool isNullable) { throw null; } + public virtual System.Xml.XmlQualifiedName GetArrayTypeName(bool isNullable) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public static DataContract? GetBuiltInDataContract(string name, string ns) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] @@ -32,22 +32,22 @@ internal DataContract(DataContractCriticalHelper helper) { } public static System.Xml.XmlQualifiedName GetStableName(Type type) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public static Type GetSurrogateType(ISerializationSurrogateProvider surrogateProvider, Type type) { throw null; } - public bool HasRoot { get { throw null; } } - public bool IsBuiltInDataContract { get { throw null; } } - public bool IsISerializable { get { throw null; } } - public bool IsKeyValue(out string? keyName, out string? valueName, out string? itemName) { throw null; } - public bool IsReference { get { throw null; } } + public virtual bool HasRoot { get { throw null; } } + public virtual bool IsBuiltInDataContract { get { throw null; } } + public virtual bool IsISerializable { get { throw null; } } + public virtual bool IsKeyValue(out string? keyName, out string? valueName, out string? itemName) { throw null; } + public virtual bool IsReference { get { throw null; } } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public static bool IsTypeSerializable(Type type) { throw null; } - public bool IsValueType { get { throw null; } } - public virtual System.Collections.Generic.Dictionary? KnownDataContracts { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } set { throw null; } } - public System.Collections.Generic.List? Members { get { throw null; } } - public Type OriginalUnderlyingType { get { throw null; } } - public System.Xml.XmlQualifiedName StableName { get { throw null; } } + public virtual bool IsValueType { get { throw null; } } + public virtual System.Collections.Generic.IDictionary? KnownDataContracts { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } set { throw null; } } + public virtual System.Collections.Generic.List? Members { get { throw null; } } + public virtual Type OriginalUnderlyingType { get { throw null; } } + public virtual System.Xml.XmlQualifiedName StableName { get { throw null; } } [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(DataContract.DataContractPreserveMemberTypes)] - public Type UnderlyingType { get { throw null; } } - public System.Xml.XmlDictionaryString? TopLevelElementName { get { throw null; } } - public System.Xml.XmlDictionaryString? TopLevelElementNamespace { get { throw null; } } + public virtual Type UnderlyingType { get { throw null; } } + public virtual System.Xml.XmlDictionaryString? TopLevelElementName { get { throw null; } } + public virtual System.Xml.XmlDictionaryString? TopLevelElementNamespace { get { throw null; } } } internal abstract partial class DataContractCriticalHelper { } public abstract partial class DataContractResolver @@ -124,6 +124,7 @@ public sealed partial class DataContractSet [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public void Add(Type type) { throw null; } public static void CompileSchemaSet(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; } + public System.Collections.Generic.IDictionary Contracts { get { throw null; } } public DataContractSet(ISerializationSurrogateProvider? dataContractSurrogate, System.Collections.Generic.ICollection? referencedTypes, System.Collections.Generic.ICollection? referencedCollectionTypes) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public DataContractSet(DataContractSet dataContractSet) { throw null; } @@ -133,13 +134,12 @@ public sealed partial class DataContractSet public DataContract GetDataContract(Type type) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public DataContract? GetDataContract(System.Xml.XmlQualifiedName key) { throw null; } - public System.Collections.Generic.IEnumerator> GetEnumerator() { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public Type? GetReferencedTypeOnImport(DataContract dataContract) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public void ImportSchemaSet(System.Xml.Schema.XmlSchemaSet schemaSet, System.Collections.Generic.ICollection? typeNames, System.Collections.Generic.ICollection elements, System.Xml.XmlQualifiedName[] elementTypeNames, bool importXmlDataType) { throw null; } - public System.Collections.Generic.Dictionary? KnownTypesForObject { get { throw null; } } - public System.Collections.Generic.Dictionary ProcessedContracts { get { throw null; } } + public System.Collections.Generic.IDictionary? KnownTypesForObject { get { throw null; } } + public System.Collections.Generic.IDictionary ProcessedContracts { get { throw null; } } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public bool TryGetReferencedType(System.Xml.XmlQualifiedName stableName, DataContract? dataContract, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out Type? type) { throw null; } public bool TryGetSurrogateData(object key, out object? value) { throw null; } @@ -180,11 +180,10 @@ public sealed partial class XmlDataContract : DataContract public bool IsAnonymous { get { throw null; } } public bool IsTopLevelElementNullable { get { throw null; } } public bool IsTypeDefinedOnImport { get { throw null; } set { throw null; } } - public void SetIsValueType(bool isValueType) { throw null; } - internal XmlDataContract(Type type) : base(new XmlDataContractCriticalHelper()) { } + public new bool IsValueType { get { throw null; } set { throw null; } } + internal XmlDataContract(Type type) : base(default) { } public System.Xml.Schema.XmlSchemaType? XsdType { get { throw null; } } } - internal sealed partial class XmlDataContractCriticalHelper : DataContractCriticalHelper { } public abstract partial class XmlObjectSerializer { protected XmlObjectSerializer() { } diff --git a/src/libraries/oob.proj b/src/libraries/oob.proj index 954a8671c0807..1a719a265cc9d 100644 --- a/src/libraries/oob.proj +++ b/src/libraries/oob.proj @@ -55,7 +55,7 @@ System.Composition.Runtime; System.Composition.TypedParts; System.Configuration.ConfigurationManager; - System.Runtime.Serialization.Schema; + System.Runtime.Serialization.Schema; System.Speech; Microsoft.Extensions.DependencyInjection.Specification.Tests" /> From 1183287be3bc47efd71ec01d732c602777ae74c2 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Sat, 9 Jul 2022 17:40:54 -0700 Subject: [PATCH 08/33] API nit, more PR feedback. --- .../Runtime/Serialization/ClassDataContract.cs | 7 +++---- .../Runtime/Serialization/CodeGenerator.cs | 17 ++--------------- .../Runtime/Serialization/DataContract.cs | 13 ++++--------- .../Runtime/Serialization/EnumDataContract.cs | 12 ++++++------ .../Json/JsonFormatReaderGenerator.cs | 2 +- .../Serialization/ReflectionXmlFormatReader.cs | 2 +- .../Serialization/ReflectionXmlFormatWriter.cs | 2 +- .../Runtime/Serialization/XmlDataContract.cs | 2 +- .../Serialization/XmlFormatReaderGenerator.cs | 2 +- .../Serialization/XmlFormatWriterGenerator.cs | 2 +- .../Schema/XsdDataContractExporter.cs | 2 +- .../ref/System.Runtime.Serialization.Xml.cs | 4 ++-- 12 files changed, 24 insertions(+), 43 deletions(-) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs index e276d83da065a..97c0a62f178e1 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs @@ -63,7 +63,7 @@ internal ClassDataContract? BaseClassContract set => _helper.BaseClassContract = value; } - public override List? Members + public override IList? Members { get => _helper.Members; internal set => _helper.Members = value; @@ -578,7 +578,7 @@ private sealed class ClassDataContractCriticalHelper : DataContract.DataContract private static Type[]? s_serInfoCtorArgs; private ClassDataContract? _baseContract; - private List? _members; + private IList? _members; private MethodInfo? _onSerializing, _onSerialized; private MethodInfo? _onDeserializing, _onDeserialized; private MethodInfo? _extensionDataSetMethod; @@ -1132,7 +1132,7 @@ internal ClassDataContract? BaseClassContract } } - internal List? Members + internal IList? Members { get => _members; set => _members = value; @@ -1185,7 +1185,6 @@ internal MethodInfo? ExtensionDataSetMethod internal override DataContractDictionary? KnownDataContracts { - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs index 9ea98fc9862d9..16f055759ca30 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs @@ -194,10 +194,10 @@ internal LocalBuilder DeclareLocal(Type type, string name, object initialValue) internal LocalBuilder DeclareLocal(Type type, string name) { - return DeclareLocal(type, name, false); + return DeclareLocal(type, false); } - internal LocalBuilder DeclareLocal(Type type, string name, bool isPinned) + internal LocalBuilder DeclareLocal(Type type, bool isPinned) { return _ilGen.DeclareLocal(type, isPinned); } @@ -596,7 +596,6 @@ internal Type LoadMember(MemberInfo memberInfo) else throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.CannotLoadMemberType, "Unknown", memberInfo.DeclaringType, memberInfo.Name))); - EmitStackTop(memberType); return memberType; } @@ -901,19 +900,16 @@ internal void LdlocAddress(LocalBuilder localBuilder) internal void Ldloc(LocalBuilder localBuilder) { _ilGen.Emit(OpCodes.Ldloc, localBuilder); - EmitStackTop(localBuilder.LocalType); } internal void Stloc(LocalBuilder local) { - EmitStackTop(local.LocalType); _ilGen.Emit(OpCodes.Stloc, local); } internal void Ldloca(LocalBuilder localBuilder) { _ilGen.Emit(OpCodes.Ldloca, localBuilder); - EmitStackTop(localBuilder.LocalType); } internal void LdargAddress(ArgBuilder argBuilder) @@ -992,15 +988,12 @@ internal void Ldelem(Type arrayElementType) if (opCode.Equals(OpCodes.Nop)) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ArrayTypeIsNotSupported_GeneratingCode, DataContract.GetClrTypeFullName(arrayElementType)))); _ilGen.Emit(opCode); - EmitStackTop(arrayElementType); } } internal void Ldelema(Type arrayElementType) { OpCode opCode = OpCodes.Ldelema; _ilGen.Emit(opCode, arrayElementType); - - EmitStackTop(arrayElementType); } private static OpCode GetStelemOpCode(TypeCode typeCode) => @@ -1033,7 +1026,6 @@ internal void Stelem(Type arrayElementType) if (opCode.Equals(OpCodes.Nop)) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ArrayTypeIsNotSupported_GeneratingCode, DataContract.GetClrTypeFullName(arrayElementType)))); - EmitStackTop(arrayElementType); _ilGen.Emit(opCode); } } @@ -1214,11 +1206,6 @@ private static void ThrowMismatchException(object expected) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.ExpectingEnd, expected.ToString()))); } - internal static void EmitStackTop(Type stackTopType) - { - return; - } - internal Label[] Switch(int labelCount) { SwitchState switchState = new SwitchState(DefineLabel(), DefineLabel()); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs index 0d873c1c62329..006da602378d7 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs @@ -231,10 +231,10 @@ public virtual bool IsISerializable internal virtual XmlDictionaryString Namespace => _ns; - public virtual bool HasRoot + internal virtual bool HasRoot { get => true; - internal set { } + set { } } public virtual XmlDictionaryString? TopLevelElementName @@ -259,7 +259,7 @@ public virtual bool IsKeyValue(out string? keyName, out string? valueName, out s return false; } - public virtual List? Members + public virtual IList? Members { get => null; internal set { } @@ -313,7 +313,6 @@ internal class DataContractCriticalHelper [DynamicallyAccessedMembers(ClassDataContract.DataContractPreserveMemberTypes)] private readonly Type _underlyingType; private Type? _originalUnderlyingType; - private bool _isReference; private bool _isValueType; private GenericInfo? _genericInfo; private XmlQualifiedName _stableName = null!; // StableName is always set in concrete ctors set except for the "invalid" CollectionDataContract @@ -1005,11 +1004,7 @@ private void SetTypeForInitialization(Type classType) } } - internal bool IsReference - { - get => _isReference; - set => _isReference = value; - } + internal bool IsReference { get; set; } internal bool IsValueType { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs index ebc4096891323..8d5f79b0e94e8 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs @@ -44,13 +44,13 @@ public XmlQualifiedName BaseContractName } [NotNull] - public override List? Members + public override IList? Members { get => _helper.Members; internal set => _helper.Members = value!; } - public List? Values + public IList? Values { get => _helper.Values; set => _helper.Values = value; @@ -74,8 +74,8 @@ private sealed class EnumDataContractCriticalHelper : DataContract.DataContractC private static readonly Dictionary s_nameToType = new Dictionary(); private DataContract _baseContract; - private List _members; - private List? _values; + private IList _members; + private IList? _values; private bool _isULong; private bool _isFlags; private readonly bool _hasDataContract; @@ -169,13 +169,13 @@ internal XmlQualifiedName BaseContractName } } - internal List Members + internal IList Members { get => _members; set => _members = value; } - internal List? Values + internal IList? Values { get => _values; set => _values = value; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs index 177aba2e87060..cf34c9ba85d1c 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs @@ -411,7 +411,7 @@ private int SetRequiredElements(ClassDataContract contract, byte[] requiredEleme { int memberCount = (contract.BaseClassContract == null) ? 0 : SetRequiredElements(contract.BaseClassContract, requiredElements); - List members = contract.Members!; + IList members = contract.Members!; for (int i = 0; i < members.Count; i++, memberCount++) { if (members[i].IsRequired) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatReader.cs index 63572bd37dc26..c0b7b2ab98a98 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatReader.cs @@ -136,7 +136,7 @@ private bool[] GetRequiredMembers(ClassDataContract contract, out int firstRequi private int GetRequiredMembers(ClassDataContract contract, bool[] requiredMembers) { int memberCount = (contract.BaseClassContract == null) ? 0 : GetRequiredMembers(contract.BaseClassContract, requiredMembers); - List members = contract.Members!; + IList members = contract.Members!; for (int i = 0; i < members.Count; i++, memberCount++) { requiredMembers[memberCount] = members[i].IsRequired; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatWriter.cs index 204d4cb8c15fb..98998a262d419 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatWriter.cs @@ -236,7 +236,7 @@ private static bool CheckIfMemberHasConflict(DataMember member, ClassDataContrac { if (ns == currentContract.StableName.Namespace) { - List members = currentContract.Members!; + IList members = currentContract.Members!; for (int j = 0; j < members.Count; j++) { if (name == members[j].Name) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs index a2fd225957163..6a68a654c23e3 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs @@ -54,7 +54,7 @@ public bool IsAnonymous set => _helper.IsValueType = value; } - public override bool HasRoot + public new bool HasRoot { get => _helper.HasRoot; internal set => _helper.HasRoot = value; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs index eab43fba40bde..d176eb6f5ceb7 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs @@ -462,7 +462,7 @@ private bool[] GetRequiredMembers(ClassDataContract contract, out int firstRequi private int GetRequiredMembers(ClassDataContract contract, bool[] requiredMembers) { int memberCount = (contract.BaseClassContract == null) ? 0 : GetRequiredMembers(contract.BaseClassContract, requiredMembers); - List members = contract.Members!; + IList members = contract.Members!; for (int i = 0; i < members.Count; i++, memberCount++) { requiredMembers[memberCount] = members[i].IsRequired; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs index 0e984e1a3adb3..3676ceb9879b1 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs @@ -787,7 +787,7 @@ private static bool CheckIfMemberHasConflict(DataMember member, ClassDataContrac { if (ns == currentContract.StableName.Namespace) { - List members = currentContract.Members!; + IList members = currentContract.Members!; for (int j = 0; j < members.Count; j++) { if (name == members[j].Name) diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs index b23a62cec13aa..b882782e9f32f 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs @@ -175,7 +175,7 @@ public XmlQualifiedName GetSchemaTypeName(Type type) type = GetSurrogatedType(type); DataContract dataContract = DataContract.GetDataContract(type); EnsureTypeNotGeneric(dataContract.UnderlyingType); - if (dataContract.HasRoot) + if (dataContract is not XmlDataContract xdc || xdc.HasRoot) // All non-XmlDataContracts "have root". { return new XmlQualifiedName(dataContract.TopLevelElementName!.Value, dataContract.TopLevelElementNamespace!.Value); } diff --git a/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs b/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs index 0542fbc6867b5..239377f1ee237 100644 --- a/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs +++ b/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs @@ -32,7 +32,6 @@ internal DataContract(DataContractCriticalHelper helper) { } public static System.Xml.XmlQualifiedName GetStableName(Type type) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public static Type GetSurrogateType(ISerializationSurrogateProvider surrogateProvider, Type type) { throw null; } - public virtual bool HasRoot { get { throw null; } } public virtual bool IsBuiltInDataContract { get { throw null; } } public virtual bool IsISerializable { get { throw null; } } public virtual bool IsKeyValue(out string? keyName, out string? valueName, out string? itemName) { throw null; } @@ -41,7 +40,7 @@ internal DataContract(DataContractCriticalHelper helper) { } public static bool IsTypeSerializable(Type type) { throw null; } public virtual bool IsValueType { get { throw null; } } public virtual System.Collections.Generic.IDictionary? KnownDataContracts { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } set { throw null; } } - public virtual System.Collections.Generic.List? Members { get { throw null; } } + public virtual System.Collections.Generic.IList? Members { get { throw null; } } public virtual Type OriginalUnderlyingType { get { throw null; } } public virtual System.Xml.XmlQualifiedName StableName { get { throw null; } } [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(DataContract.DataContractPreserveMemberTypes)] @@ -177,6 +176,7 @@ public partial interface IExtensibleDataObject } public sealed partial class XmlDataContract : DataContract { + public bool HasRoot { get { throw null; } } public bool IsAnonymous { get { throw null; } } public bool IsTopLevelElementNullable { get { throw null; } } public bool IsTypeDefinedOnImport { get { throw null; } set { throw null; } } From 92b1d63a78e1513a107878febdb7d277437e3c47 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Sun, 10 Jul 2022 18:16:46 -0700 Subject: [PATCH 09/33] Fix HasRoot hiding issue. --- .../Runtime/Serialization/DataContract.cs | 10 +++------- .../Runtime/Serialization/XmlDataContract.cs | 17 +++++------------ 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs index 006da602378d7..d7adaf0fbf470 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs @@ -233,8 +233,8 @@ public virtual bool IsISerializable internal virtual bool HasRoot { - get => true; - set { } + get => _helper.HasRoot; + set => _helper.HasRoot = value; } public virtual XmlDictionaryString? TopLevelElementName @@ -1049,11 +1049,7 @@ internal XmlDictionaryString Namespace set => _ns = value; } - internal virtual bool HasRoot - { - get => true; - set { } - } + internal virtual bool HasRoot { get; set; } = true; internal virtual XmlDictionaryString? TopLevelElementName { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs index 6a68a654c23e3..d81e61c952d23 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs @@ -124,7 +124,6 @@ private sealed class XmlDataContractCriticalHelper : DataContract.DataContractCr private XmlDictionaryString? _topLevelElementNamespace; private bool _isTopLevelElementNullable; private bool _isTypeDefinedOnImport; - private bool _hasRoot; private CreateXmlSerializableDelegate? _createXmlSerializable; private XmlSchemaType? _xsdType; @@ -141,12 +140,12 @@ internal XmlDataContractCriticalHelper( XmlSchemaType? xsdType; XmlQualifiedName stableName; SchemaExporter.GetXmlTypeInfo(type, out stableName, out xsdType, out hasRoot); - this.StableName = stableName; - this.XsdType = xsdType; - this.HasRoot = hasRoot; + StableName = stableName; + XsdType = xsdType; + HasRoot = hasRoot; XmlDictionary dictionary = new XmlDictionary(); - this.Name = dictionary.Add(StableName.Name); - this.Namespace = dictionary.Add(StableName.Namespace); + Name = dictionary.Add(StableName.Name); + Namespace = dictionary.Add(StableName.Namespace); object[]? xmlRootAttributes = UnderlyingType?.GetCustomAttributes(Globals.TypeOfXmlRootAttribute, false).ToArray(); if (xmlRootAttributes == null || xmlRootAttributes.Length == 0) { @@ -207,12 +206,6 @@ internal XmlSchemaType? XsdType internal bool IsAnonymous => _xsdType != null; - internal override bool HasRoot - { - get => _hasRoot; - set => _hasRoot = value; - } - internal override XmlDictionaryString? TopLevelElementName { get => _topLevelElementName; From 79da1a7b373ca76ca110d58cb13eac9f4ed22f02 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Mon, 11 Jul 2022 17:25:10 -0700 Subject: [PATCH 10/33] Add basic schema tests. Fix DataMember bug. --- .../Runtime/Serialization/DataContractSet.cs | 32 ++++--- .../Runtime/Serialization/DataMember.cs | 4 +- .../tests/Expected.ImportedType.cs | 86 +++++++++++++++++++ ....Runtime.Serialization.Schema.Tests.csproj | 17 +++- .../Runtime/Serialization/Schema/Contracts.cs | 32 +++++++ .../Runtime/Serialization/Schema/Export.cs | 47 ++++++++++ .../Runtime/Serialization/Schema/Import.cs | 57 ++++++++++++ .../Runtime/Serialization/Schema/Importer.cs | 16 ---- 8 files changed, 258 insertions(+), 33 deletions(-) create mode 100644 src/libraries/System.Runtime.Serialization.Schema/tests/Expected.ImportedType.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Contracts.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Export.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import.cs delete mode 100644 src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Importer.cs diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs index dd9d3222f4b51..1ce8f522da0d1 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs @@ -247,26 +247,30 @@ public DataContract GetDataContract(Type type) [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal DataContract GetMemberTypeDataContract(DataMember dataMember) { - Type dataMemberType = dataMember.MemberType; - if (dataMember.IsGetOnlyCollection) + if (dataMember.MemberInfo is not Type) { - if (_surrogateProvider != null) + Type dataMemberType = dataMember.MemberType; + if (dataMember.IsGetOnlyCollection) { - Type dcType = DataContractSurrogateCaller.GetDataContractType(_surrogateProvider, dataMemberType); - if (dcType != dataMemberType) + if (_surrogateProvider != null) { - throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.SurrogatesWithGetOnlyCollectionsNotSupported, - DataContract.GetClrTypeFullName(dataMemberType), - (dataMember.MemberInfo.DeclaringType != null) ? DataContract.GetClrTypeFullName(dataMember.MemberInfo.DeclaringType) : dataMember.MemberInfo.DeclaringType, - dataMember.MemberInfo.Name))); + Type dcType = DataContractSurrogateCaller.GetDataContractType(_surrogateProvider, dataMemberType); + if (dcType != dataMemberType) + { + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.SurrogatesWithGetOnlyCollectionsNotSupported, + DataContract.GetClrTypeFullName(dataMemberType), + (dataMember.MemberInfo.DeclaringType != null) ? DataContract.GetClrTypeFullName(dataMember.MemberInfo.DeclaringType) : dataMember.MemberInfo.DeclaringType, + dataMember.MemberInfo.Name))); + } } + return DataContract.GetGetOnlyCollectionDataContract(DataContract.GetId(dataMemberType.TypeHandle), dataMemberType.TypeHandle, dataMemberType); + } + else + { + return GetDataContract(dataMemberType); } - return DataContract.GetGetOnlyCollectionDataContract(DataContract.GetId(dataMemberType.TypeHandle), dataMemberType.TypeHandle, dataMemberType); - } - else - { - return GetDataContract(dataMemberType); } + return dataMember.MemberTypeContract; } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs index d612ba2254d83..879ada66bc034 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs @@ -170,8 +170,10 @@ internal Type MemberType { if (MemberInfo is FieldInfo field) _memberType = field.FieldType; + else if (MemberInfo is PropertyInfo prop) + _memberType = prop.PropertyType; else - _memberType = ((PropertyInfo)MemberInfo).PropertyType; + _memberType = (Type)MemberInfo!; } return _memberType; diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/Expected.ImportedType.cs b/src/libraries/System.Runtime.Serialization.Schema/tests/Expected.ImportedType.cs new file mode 100644 index 0000000000000..636f23927e195 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/tests/Expected.ImportedType.cs @@ -0,0 +1,86 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +[assembly: System.Runtime.Serialization.ContractNamespaceAttribute("www.Contoso.com/Examples/", ClrNamespace="www.Contoso.com.Examples")] + +namespace www.Contoso.com.Examples +{ + using System.Runtime.Serialization; + + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization.Schema", "7.0.0.0")] + [System.Runtime.Serialization.DataContractAttribute(Name="Employee", Namespace="www.Contoso.com/Examples/")] + internal partial class Employee : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged + { + + private System.Runtime.Serialization.ExtensionDataObject extensionDataField; + + private string EmployeeNameField; + + private string IDField; + + public System.Runtime.Serialization.ExtensionDataObject ExtensionData + { + get + { + return this.extensionDataField; + } + set + { + this.extensionDataField = value; + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + internal string EmployeeName + { + get + { + return this.EmployeeNameField; + } + set + { + if ((object.ReferenceEquals(this.EmployeeNameField, value) != true)) + { + this.EmployeeNameField = value; + this.RaisePropertyChanged("EmployeeName"); + } + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + internal string ID + { + get + { + return this.IDField; + } + set + { + if ((object.ReferenceEquals(this.IDField, value) != true)) + { + this.IDField = value; + this.RaisePropertyChanged("ID"); + } + } + } + + public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; + + protected void RaisePropertyChanged(string propertyName) + { + System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged; + if ((propertyChanged != null)) + { + propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); + } + } + } +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/System.Runtime.Serialization.Schema.Tests.csproj b/src/libraries/System.Runtime.Serialization.Schema/tests/System.Runtime.Serialization.Schema.Tests.csproj index 45b5bf3b22ee7..117d85f44ea29 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/tests/System.Runtime.Serialization.Schema.Tests.csproj +++ b/src/libraries/System.Runtime.Serialization.Schema/tests/System.Runtime.Serialization.Schema.Tests.csproj @@ -4,9 +4,22 @@ $(NetCoreAppCurrent) - + + + - + + + Always + + + + + + diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Contracts.cs b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Contracts.cs new file mode 100644 index 0000000000000..78fe56f0b5e4a --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Contracts.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Runtime.Serialization.Schema.Tests +{ + internal class ContractUtils + { + internal const string ExpectedImportedTypeFile = "Expected.ImportedType.cs"; + internal const string TestNamespace = "www.Contoso.com/Examples/"; + internal const string ExpectedEmployeeSchema = @" + + + + + + + + +"; + } + +#pragma warning disable CS0169, IDE0051, IDE1006 + [DataContract(Namespace = ContractUtils.TestNamespace)] + public class Employee + { + [DataMember] + public string EmployeeName; + [DataMember] + private string ID; + } +#pragma warning restore CS0169, IDE0051, IDE1006 +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Export.cs b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Export.cs new file mode 100644 index 0000000000000..a57540c967bda --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Export.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.IO; +using System.Runtime.Serialization.Schema; +using System.Xml; +using System.Xml.Schema; +using Xunit; + +namespace System.Runtime.Serialization.Schema.Tests +{ + public class ExportTests + { + [Fact] + static void ExportXSD() + { + XsdDataContractExporter exporter = new XsdDataContractExporter(); + Assert.True(exporter.CanExport(typeof(Employee))); + exporter.Export(typeof(Employee)); + Assert.Equal(3, exporter.Schemas.Count); + + XmlSchemaSet mySchemas = exporter.Schemas; + XmlQualifiedName XmlNameValue = exporter.GetRootElementName(typeof(Employee)); + string EmployeeNameSpace = XmlNameValue.Namespace; + Assert.Equal(ContractUtils.TestNamespace, EmployeeNameSpace); + + var employeeSchemas = mySchemas.Schemas(EmployeeNameSpace); + Assert.Single(employeeSchemas); + foreach (XmlSchema schema in employeeSchemas) + { + StringWriter sw = new StringWriter(); + schema.Write(sw); + Assert.Equal(ContractUtils.ExpectedEmployeeSchema, sw.ToString()); + } + } + + [Fact] + static void GetXmlElementName() + { + XsdDataContractExporter myExporter = new XsdDataContractExporter(); + XmlQualifiedName xmlElementName = myExporter.GetRootElementName(typeof(Employee)); + Assert.False(xmlElementName.IsEmpty); + Assert.Equal(ContractUtils.TestNamespace, xmlElementName.Namespace); + Assert.Equal("Employee", xmlElementName.Name); + } + } +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import.cs b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import.cs new file mode 100644 index 0000000000000..5d2763666b3ee --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import.cs @@ -0,0 +1,57 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.CodeDom; +using System.CodeDom.Compiler; +using System.Globalization; +using System.IO; +using System.Reflection; +using System.Runtime.Serialization.Schema; +using System.Xml; +using System.Xml.Schema; +using Xunit; + +namespace System.Runtime.Serialization.Schema.Tests +{ + public class ImportTests + { + [Fact] + static void ImportXSD() + { + XsdDataContractExporter exporter = new XsdDataContractExporter(); + exporter.Export(typeof(Employee)); + XmlSchemaSet schemas = exporter.Schemas; + + ImportOptions opts = new ImportOptions() + { + EnableDataBinding = true, + GenerateInternal = true, + }; + XsdDataContractImporter importer = new XsdDataContractImporter() { Options = opts }; + Assert.True(importer.CanImport(schemas)); + importer.Import(schemas); + + CodeCompileUnit ccu = importer.CodeCompileUnit; + Assert.NotNull(ccu); + + string importedTypeCodeCS = CompileCode(ccu, new Microsoft.CSharp.CSharpCodeProvider()); + Assert.Equal(LineEndingsHelper.Normalize(File.ReadAllText(ContractUtils.ExpectedImportedTypeFile)), importedTypeCodeCS); + + //string importedTypeCodeVB = CompileCode(ccu, new Microsoft.VisualBasic.VBCodeProvider()); + } + + + static string CompileCode(CodeCompileUnit ccu, CodeDomProvider provider) + { + CodeGeneratorOptions options = new CodeGeneratorOptions() + { + BlankLinesBetweenMembers = true, + BracingStyle = "C", + }; + + StringWriter sw = new StringWriter(); + provider.GenerateCodeFromCompileUnit(ccu, sw, options); + return sw.ToString(); + } + } +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Importer.cs b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Importer.cs deleted file mode 100644 index 13e424dce9a19..0000000000000 --- a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Importer.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using Xunit; - -namespace System.Runtime.Serialization.Schema.Tests -{ - public class ImporterTests - { - [Fact] - public void Hello() - { - Assert.True(true); - } - } -} From 9a13158aeda806a61d763e40d955272dd3bd1bae Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Mon, 11 Jul 2022 22:28:31 -0700 Subject: [PATCH 11/33] Add /// comments for new schema project. --- .../Serialization/Schema/ExportOptions.cs | 14 +++ .../Serialization/Schema/ImportOptions.cs | 40 +++++++++ .../Schema/XsdDataContractExporter.cs | 70 +++++++++++++++ .../Schema/XsdDataContractImporter.cs | 86 +++++++++++++++++++ 4 files changed, 210 insertions(+) diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ExportOptions.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ExportOptions.cs index eb760948b5580..beacbdbbf04fa 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ExportOptions.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ExportOptions.cs @@ -10,11 +10,25 @@ namespace System.Runtime.Serialization.Schema // different here so there isn't a collision. But should we consider using different names for these classes? // (The 'SurrogateProvider' property is named differently from previous versions. Should we align that property with whatever // decision we make on the class names?) + /// + /// Represents the options that can be set for an . + /// + /// + /// The is used to generate XSD schemas from a type or assembly. You can also use the to generate .NET Framework code from a schema document. + /// + /// The property is used by the to include types that can be read in an object graph. + /// public sealed class ExportOptions { + /// + /// Gets or sets a serialization surrogate provider. + /// public ISerializationSurrogateProvider? SurrogateProvider { get; set; } private Collection? _knownTypes; + /// + /// Gets the collection of types that may be encountered during serialization or deserialization. + /// public Collection KnownTypes => _knownTypes ??= new Collection(); } } diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ImportOptions.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ImportOptions.cs index a86df32ba3bf3..1497a64117325 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ImportOptions.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ImportOptions.cs @@ -9,30 +9,70 @@ namespace System.Runtime.Serialization.Schema { + /// + /// Represents the options that can be set on an . + /// + /// + /// The is used to generate code from XML schema using the .NET CodeDOM. To generate an XML schema from an assembly, use the . + /// public sealed class ImportOptions { private ICollection? _referencedTypes; private ICollection? _referencedCollectionTypes; private IDictionary? _namespaces; + /// + /// Gets or sets a instance that provides the means to check whether particular options for a target language are supported. + /// public CodeDomProvider? CodeProvider { get; set; } + /// + /// Gets or sets a value that specifies whether types in generated code should implement the interface. + /// public bool EnableDataBinding { get; set; } + /// + /// Gets or sets a data contract surrogate provider that can be used to modify the code generated during an import operation. + /// + /// + /// The interface type for this option is ISerializationSurrogateProvider, but to take full advantage of the imported code modification + /// abilities, using an ISerializationExtendedSurrogateProvider is recommended. + /// public ISerializationSurrogateProvider? SurrogateProvider { get; set; } + /// + /// Gets or sets a value that specifies whether generated code will be marked internal or public. + /// public bool GenerateInternal { get; set; } + /// + /// Gets or sets a value that specifies whether generated data contract classes will be marked with the attribute in addition to the attribute. + /// public bool GenerateSerializable { get; set; } + /// + /// Gets or sets a value that determines whether all XML schema types, even those that do not conform to a data contract schema, will be imported. + /// public bool ImportXmlType { get; set; } + /// + /// Gets a dictionary that contains the mapping of data contract namespaces to the CLR namespaces that must be used to generate code during an import operation. + /// public IDictionary Namespaces => _namespaces ??= new Dictionary(); + /// + /// Gets a collection of types that represents data contract collections that should be referenced when generating code for collections, such as lists or dictionaries of items. + /// public ICollection ReferencedCollectionTypes => _referencedCollectionTypes ??= new List(); + /// + /// Gets a containing types referenced in generated code. + /// public ICollection ReferencedTypes => _referencedTypes ??= new List(); + /// + /// A Func to processes the type that has been generated from the imported schema. + /// public Func? ProcessImportedType; } } diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs index b882782e9f32f..e9d91a0c8f651 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs @@ -13,27 +13,55 @@ namespace System.Runtime.Serialization.Schema { + /// + /// Allows the transformation of a set of .NET types that are used in data contracts into an XML schema file (.xsd). + /// + /// + /// Use the class when you have created a Web service that incorporates data represented by + /// common language runtime (CLR) types and when you need to export XML schemas for each type to be consumed by other Web services. + /// That is, transforms a set of CLR types into XML schemas. The schemas can then be exposed + /// through a Web Services Description Language (WSDL) document for use by others who need to interoperate with your service. + /// + /// Conversely, if you are creating a Web service that must interoperate with an existing Web service, use the + /// to transform XML schemas and create the CLR types that represent the data in a selected programming language. + /// + /// The generates an object that contains the collection of schemas. + /// Access the set of schemas through the property. + /// public sealed class XsdDataContractExporter { private ExportOptions? _options; private XmlSchemaSet? _schemas; private DataContractSet? _dataContractSet; + /// + /// Initializes a new instance of the class. + /// public XsdDataContractExporter() { } + /// + /// Initializes a new instance of the class with the specified set of schemas. + /// + /// An that contains the schemas to be exported. public XsdDataContractExporter(XmlSchemaSet? schemas) { this._schemas = schemas; } + /// + /// Gets or sets an that contains options that can be set for the export operation. + /// public ExportOptions? Options { get { return _options; } set { _options = value; } } + /// + /// Gets the collection of exported XML schemas. + /// public XmlSchemaSet Schemas { get @@ -72,6 +100,10 @@ private static void EnsureTypeNotGeneric(Type type) throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericTypeNotExportable, type))); } + /// + /// Transforms the types contained in the specified collection of assemblies. + /// + /// A (of ) that contains the types to export. [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public void Export(ICollection assemblies) { @@ -99,6 +131,10 @@ public void Export(ICollection assemblies) } } + /// + /// Transforms the types contained in the ICollection passed to this method. + /// + /// A (of ) that contains the types to export. [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public void Export(ICollection types) { @@ -123,6 +159,10 @@ public void Export(ICollection types) } } + /// + /// Transforms the specified .NET Framework type into an XML schema definition language (XSD) schema. + /// + /// The to transform into an XML schema. [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public void Export(Type type) { @@ -141,6 +181,11 @@ public void Export(Type type) } } + /// + /// Returns the contract name and contract namespace for the . + /// + /// The that was exported. + /// An that represents the contract name of the type and its namespace. [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public XmlQualifiedName GetSchemaTypeName(Type type) { @@ -154,6 +199,11 @@ public XmlQualifiedName GetSchemaTypeName(Type type) return dataContract.StableName; } + /// + /// Returns the XML schema type for the specified type. + /// + /// The type to return a schema for. + /// An that contains the XML schema. [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public XmlSchemaType? GetSchemaType(Type type) { @@ -167,6 +217,11 @@ public XmlQualifiedName GetSchemaTypeName(Type type) return null; } + /// + /// Returns the top-level name and namespace for the . + /// + /// The to query. + /// The that represents the top-level name and namespace for this Type, which is written to the stream when writing this object. [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public XmlQualifiedName? GetRootElementName(Type type) { @@ -235,6 +290,11 @@ private void AddKnownTypes() } } + /// + /// Gets a value that indicates whether the set of .common language runtime (CLR) types contained in a set of assemblies can be exported. + /// + /// A of that contains the assemblies with the types to export. + /// true if the types can be exported; otherwise, false. [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public bool CanExport(ICollection assemblies) { @@ -267,6 +327,11 @@ public bool CanExport(ICollection assemblies) } } + /// + /// Gets a value that indicates whether the set of .common language runtime (CLR) types contained in a can be exported. + /// + /// A that contains the specified types to export. + /// true if the types can be exported; otherwise, false. [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public bool CanExport(ICollection types) { @@ -296,6 +361,11 @@ public bool CanExport(ICollection types) } } + /// + /// Gets a value that indicates whether the specified common language runtime (CLR) type can be exported. + /// + /// The to export. + /// true if the type can be exported; otherwise, false. [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public bool CanExport(Type type) { diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs index 1eeab709c599a..26c33ddda3775 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs @@ -12,6 +12,19 @@ namespace System.Runtime.Serialization.Schema { + /// + /// Allows the transformation of a set of XML schema files (.xsd) into common language runtime (CLR) types. + /// + /// + /// Use the if you are creating a Web service that must interoperate with an existing + /// Web service, or to create data contract types from XML schemas. will transform a + /// set of XML schemas and create the .NET Framework types that represent the data contract in a selected programming language. + /// To create the code, use the classes in the namespace. + /// + /// Conversely, use the class when you have created a Web service that incorporates + /// data represented by CLR types and when you need to export XML schemas for each data type to be consumed by other Web + /// services.That is, transforms a set of CLR types into a set of XML schemas. + /// public sealed class XsdDataContractImporter { private CodeCompileUnit _codeCompileUnit = null!; // Not directly referenced. Always lazy initialized by property getter. @@ -22,17 +35,30 @@ public sealed class XsdDataContractImporter private XmlQualifiedName[] _singleTypeNameArray = null!; // Not directly referenced. Always lazy initialized by property getter. private XmlSchemaElement[] _singleElementArray = null!; // Not directly referenced. Always lazy initialized by property getter. + /// + /// Initializes a new instance of the class. + /// public XsdDataContractImporter() { } + /// + /// Initializes a new instance of the class with the that will be used to generate CLR code. + /// + /// The that will be used to store the code. public XsdDataContractImporter(CodeCompileUnit codeCompileUnit) { _codeCompileUnit = codeCompileUnit; } + /// + /// Gets or sets an that contains settable options for the import operation. + /// public ImportOptions? Options { get; set; } + /// + /// Gets a used for storing the CLR types generated. + /// public CodeCompileUnit CodeCompileUnit => _codeCompileUnit ??= new CodeCompileUnit(); private DataContractSet DataContractSet @@ -48,6 +74,10 @@ private DataContractSet DataContractSet } } + /// + /// Transforms the specified set of XML schemas contained in an into a . + /// + /// A that contains the schema representations to generate CLR types for. [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public void Import(XmlSchemaSet schemas) { @@ -57,6 +87,11 @@ public void Import(XmlSchemaSet schemas) InternalImport(schemas, null, s_emptyElementArray, s_emptyTypeNameArray); } + /// + /// Transforms the specified set of schema types contained in an into CLR types generated into a . + /// + /// A that contains the schema representations. + /// A (of ) that represents the set of schema types to import. [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public void Import(XmlSchemaSet schemas, ICollection typeNames) { @@ -69,6 +104,11 @@ public void Import(XmlSchemaSet schemas, ICollection typeNames InternalImport(schemas, typeNames, s_emptyElementArray, s_emptyTypeNameArray); } + /// + /// Transforms the specified XML schema type contained in an into a . + /// + /// A that contains the schema representations. + /// A that represents a specific schema type to import. [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public void Import(XmlSchemaSet schemas, XmlQualifiedName typeName) { @@ -82,6 +122,13 @@ public void Import(XmlSchemaSet schemas, XmlQualifiedName typeName) InternalImport(schemas, SingleTypeNameArray, s_emptyElementArray, s_emptyTypeNameArray); } + /// + /// Transforms the specified schema element in the set of specified XML schemas into a and + /// returns an that represents the data contract name for the specified element. + /// + /// An that contains the schemas to transform. + /// An that represents the specific schema element to transform. + /// An that represents the specified element. [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public XmlQualifiedName? Import(XmlSchemaSet schemas, XmlSchemaElement element) { @@ -96,6 +143,11 @@ public void Import(XmlSchemaSet schemas, XmlQualifiedName typeName) return SingleTypeNameArray[0]; } + /// + /// Gets a value that indicates whether the schemas contained in an can be transformed into a . + /// + /// A that contains the schemas to transform. + /// true if the schemas can be transformed to data contract types; otherwise, false. [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public bool CanImport(XmlSchemaSet schemas) { @@ -105,6 +157,12 @@ public bool CanImport(XmlSchemaSet schemas) return InternalCanImport(schemas, null, s_emptyElementArray, s_emptyTypeNameArray); } + /// + /// Gets a value that indicates whether the specified set of types contained in an can be transformed into CLR types generated into a . + /// + /// A that contains the schemas to transform. + /// An of that represents the set of schema types to import. + /// true if the schemas can be transformed; otherwise, false. [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public bool CanImport(XmlSchemaSet schemas, ICollection typeNames) { @@ -117,6 +175,12 @@ public bool CanImport(XmlSchemaSet schemas, ICollection typeNa return InternalCanImport(schemas, typeNames, s_emptyElementArray, s_emptyTypeNameArray); } + /// + /// Gets a value that indicates whether the schemas contained in an can be transformed into a . + /// + /// A that contains the schema representations. + /// An that specifies the names of the schema types that need to be imported from the . + /// true if the schemas can be transformed to data contract types; otherwise, false. [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public bool CanImport(XmlSchemaSet schemas, XmlQualifiedName typeName) { @@ -129,6 +193,12 @@ public bool CanImport(XmlSchemaSet schemas, XmlQualifiedName typeName) return InternalCanImport(schemas, new XmlQualifiedName[] { typeName }, s_emptyElementArray, s_emptyTypeNameArray); } + /// + /// Gets a value that indicates whether a specific schema element contained in an can be imported. + /// + /// An to import. + /// A specific to check in the set of schemas. + /// true if the element can be imported; otherwise, false. [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public bool CanImport(XmlSchemaSet schemas, XmlSchemaElement element) { @@ -142,6 +212,11 @@ public bool CanImport(XmlSchemaSet schemas, XmlSchemaElement element) return InternalCanImport(schemas, s_emptyTypeNameArray, SingleElementArray, SingleTypeNameArray); } + /// + /// Returns a to the CLR type generated for the schema type with the specified . + /// + /// The that specifies the schema type to look up. + /// A reference to the CLR type generated for the schema type with the typeName specified. [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public CodeTypeReference GetCodeTypeReference(XmlQualifiedName typeName) { @@ -150,6 +225,12 @@ public CodeTypeReference GetCodeTypeReference(XmlQualifiedName typeName) return codeExporter.GetCodeTypeReference(dataContract); } + /// + /// Returns a for the specified XML qualified element and schema element. + /// + /// An that specifies the XML qualified name of the schema type to look up. + /// An that specifies an element in an XML schema. + /// A that represents the type that was generated for the specified schema type. [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public CodeTypeReference GetCodeTypeReference(XmlQualifiedName typeName, XmlSchemaElement element) { @@ -178,6 +259,11 @@ internal DataContract FindDataContract(XmlQualifiedName typeName) return dataContract; } + /// + /// Returns a list of objects that represents the known types generated when generating code for the specified schema type. + /// + /// An that represents the schema type to look up known types for. + /// A collection of type . [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] public ICollection? GetKnownTypeReferences(XmlQualifiedName typeName) { From 3b376ab7c494d83b1ec373f01df536501b359928 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Mon, 11 Jul 2022 22:54:09 -0700 Subject: [PATCH 12/33] Fixing bad format in xml comment. --- .../Runtime/Serialization/Schema/XsdDataContractExporter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs index e9d91a0c8f651..b2dbdc14cbc22 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs @@ -132,7 +132,7 @@ public void Export(ICollection assemblies) } /// - /// Transforms the types contained in the ICollection passed to this method. + /// Transforms the types contained in the passed to this method. /// /// A (of ) that contains the types to export. [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] From 2127ba8338dfc2cc1682ce5034546674930266a0 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Tue, 12 Jul 2022 14:03:26 -0700 Subject: [PATCH 13/33] Skip import test on Wasm. --- .../tests/System/Runtime/Serialization/Schema/Import.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import.cs b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import.cs index 5d2763666b3ee..2fa2ee75c3ae7 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import.cs @@ -16,6 +16,7 @@ namespace System.Runtime.Serialization.Schema.Tests public class ImportTests { [Fact] + [SkipOnPlatform(TestPlatforms.Browser, "ExpectedImportedTypeFile not available in browser.")] static void ImportXSD() { XsdDataContractExporter exporter = new XsdDataContractExporter(); From 4c3417c8bb768748a4d5931bf2ec7086ad3fbd92 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Tue, 12 Jul 2022 14:04:02 -0700 Subject: [PATCH 14/33] Obsolete old half-coded schema exporter. --- .../src/System/Runtime/Serialization/ExportOptions.cs | 1 + .../src/System/Runtime/Serialization/XsdDataContractExporter.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExportOptions.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExportOptions.cs index 88a8a1c148934..48feb880a0da4 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExportOptions.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExportOptions.cs @@ -5,6 +5,7 @@ namespace System.Runtime.Serialization { + [Obsolete("Schema handling abilities has moved to System.Runtime.Serialization.Schema. Please use the classes there.")] public class ExportOptions { private Collection? _knownTypes; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs index 3158b1fd98619..b9183bd3c2c67 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs @@ -11,6 +11,7 @@ namespace System.Runtime.Serialization { + [Obsolete("Schema handling abilities has moved to System.Runtime.Serialization.Schema. Please use the classes there.")] public class XsdDataContractExporter { private ExportOptions? _options; From 54b6b397ac76f2cba0948a50cc39955c1ef4755f Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Tue, 12 Jul 2022 14:57:21 -0700 Subject: [PATCH 15/33] Add obsolete attribute in ref project as well. --- .../ref/System.Runtime.Serialization.Xml.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs b/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs index 239377f1ee237..8e3a5eda9d624 100644 --- a/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs +++ b/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs @@ -153,6 +153,7 @@ internal DataMember() { } public string Name { get { throw null; } } public long Order { get { throw null; } } } + [Obsolete("Schema handling abilities has moved to System.Runtime.Serialization.Schema. Please use the classes there.")] public partial class ExportOptions { public ExportOptions() { } @@ -233,6 +234,7 @@ public static partial class XPathQueryGenerator [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public static string CreateFromDataContractSerializer(System.Type type, System.Reflection.MemberInfo[] pathToMember, out System.Xml.XmlNamespaceManager namespaces) { throw null; } } + [Obsolete("Schema handling abilities has moved to System.Runtime.Serialization.Schema. Please use the classes there.")] public partial class XsdDataContractExporter { public XsdDataContractExporter() { } From 73084705421c76485cbc04e24b0de07e3d192593 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Tue, 12 Jul 2022 19:14:53 -0700 Subject: [PATCH 16/33] Removing obsolete for now, since it appears Syndication depends on old class. --- .../src/System/Runtime/Serialization/ExportOptions.cs | 1 - .../src/System/Runtime/Serialization/XsdDataContractExporter.cs | 1 - .../ref/System.Runtime.Serialization.Xml.cs | 2 -- 3 files changed, 4 deletions(-) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExportOptions.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExportOptions.cs index 48feb880a0da4..88a8a1c148934 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExportOptions.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExportOptions.cs @@ -5,7 +5,6 @@ namespace System.Runtime.Serialization { - [Obsolete("Schema handling abilities has moved to System.Runtime.Serialization.Schema. Please use the classes there.")] public class ExportOptions { private Collection? _knownTypes; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs index b9183bd3c2c67..3158b1fd98619 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs @@ -11,7 +11,6 @@ namespace System.Runtime.Serialization { - [Obsolete("Schema handling abilities has moved to System.Runtime.Serialization.Schema. Please use the classes there.")] public class XsdDataContractExporter { private ExportOptions? _options; diff --git a/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs b/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs index 8e3a5eda9d624..239377f1ee237 100644 --- a/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs +++ b/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs @@ -153,7 +153,6 @@ internal DataMember() { } public string Name { get { throw null; } } public long Order { get { throw null; } } } - [Obsolete("Schema handling abilities has moved to System.Runtime.Serialization.Schema. Please use the classes there.")] public partial class ExportOptions { public ExportOptions() { } @@ -234,7 +233,6 @@ public static partial class XPathQueryGenerator [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public static string CreateFromDataContractSerializer(System.Type type, System.Reflection.MemberInfo[] pathToMember, out System.Xml.XmlNamespaceManager namespaces) { throw null; } } - [Obsolete("Schema handling abilities has moved to System.Runtime.Serialization.Schema. Please use the classes there.")] public partial class XsdDataContractExporter { public XsdDataContractExporter() { } From 6be7bbc9cb6904fa8d160827bd68fc8a27712714 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Tue, 12 Jul 2022 19:39:18 -0700 Subject: [PATCH 17/33] Fix the DCJS ref project. --- .../ref/System.Runtime.Serialization.Json.cs | 5 +++++ .../ref/System.Runtime.Serialization.Json.csproj | 8 +++++--- .../ref/System.Xml.ReaderWriter.csproj | 8 +++++--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Runtime.Serialization.Json/ref/System.Runtime.Serialization.Json.cs b/src/libraries/System.Runtime.Serialization.Json/ref/System.Runtime.Serialization.Json.cs index 014c498f6eace..ba4b193c89311 100644 --- a/src/libraries/System.Runtime.Serialization.Json/ref/System.Runtime.Serialization.Json.cs +++ b/src/libraries/System.Runtime.Serialization.Json/ref/System.Runtime.Serialization.Json.cs @@ -79,6 +79,11 @@ public override void WriteStartObject(System.Xml.XmlDictionaryWriter writer, obj [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public override void WriteStartObject(System.Xml.XmlWriter writer, object? graph) { } } + public static partial class DataContractJsonSerializerExtensions + { + public static System.Runtime.Serialization.ISerializationSurrogateProvider? GetSerializationSurrogateProvider(this System.Runtime.Serialization.Json.DataContractJsonSerializer serializer) { throw null; } + public static void SetSerializationSurrogateProvider(this System.Runtime.Serialization.Json.DataContractJsonSerializer serializer, System.Runtime.Serialization.ISerializationSurrogateProvider? provider) { } + } public partial class DataContractJsonSerializerSettings { public DataContractJsonSerializerSettings() { } diff --git a/src/libraries/System.Runtime.Serialization.Json/ref/System.Runtime.Serialization.Json.csproj b/src/libraries/System.Runtime.Serialization.Json/ref/System.Runtime.Serialization.Json.csproj index 927772e02ceb8..350ad3eebfc99 100644 --- a/src/libraries/System.Runtime.Serialization.Json/ref/System.Runtime.Serialization.Json.csproj +++ b/src/libraries/System.Runtime.Serialization.Json/ref/System.Runtime.Serialization.Json.csproj @@ -2,12 +2,14 @@ $(NetCoreAppCurrent) + + - - - + + + diff --git a/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.csproj b/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.csproj index 243d4766ec96a..cc75876fe686c 100644 --- a/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.csproj +++ b/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.csproj @@ -2,12 +2,14 @@ $(NetCoreAppCurrent) + + - - - + + + From 446c99369d0f14f36f2df1cde45749c762ce2b19 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Thu, 14 Jul 2022 12:18:18 -0700 Subject: [PATCH 18/33] API cleanup. --- .../src/Resources/Strings.resx | 3 + .../Serialization/ClassDataContract.cs | 29 +-- .../Serialization/CollectionDataContract.cs | 21 +- .../Runtime/Serialization/DataContract.cs | 16 +- .../Serialization/DataContractSerializer.cs | 2 +- .../Runtime/Serialization/DataContractSet.cs | 179 ++++++++++++------ .../Runtime/Serialization/DataMember.cs | 2 +- .../Runtime/Serialization/EnumDataContract.cs | 20 +- .../GenericParameterDataContract.cs | 2 +- .../Json/DataContractJsonSerializer.cs | 2 +- .../Serialization/Json/JsonDataContract.cs | 10 +- .../Json/JsonFormatReaderGenerator.cs | 2 +- .../Serialization/Json/JsonXmlDataContract.cs | 2 +- .../ReflectionXmlFormatReader.cs | 2 +- .../ReflectionXmlFormatWriter.cs | 2 +- .../Runtime/Serialization/SchemaHelper.cs | 2 +- .../Runtime/Serialization/SchemaImporter.cs | 44 ++--- .../Runtime/Serialization/ScopedKnownTypes.cs | 3 +- .../Runtime/Serialization/XmlDataContract.cs | 3 +- .../Serialization/XmlFormatReaderGenerator.cs | 2 +- .../Serialization/XmlFormatWriterGenerator.cs | 2 +- .../Serialization/XmlObjectSerializer.cs | 3 +- .../XmlObjectSerializerContext.cs | 5 +- .../XmlObjectSerializerReadContext.cs | 3 +- .../src/Resources/Strings.resx | 3 - .../Serialization/Schema/CodeExporter.cs | 151 +++++++-------- .../Serialization/Schema/SchemaHelper.cs | 20 ++ .../Schema/XsdDataContractExporter.cs | 2 +- .../Schema/XsdDataContractImporter.cs | 38 ++-- .../ref/System.Runtime.Serialization.Xml.cs | 30 +-- 30 files changed, 337 insertions(+), 268 deletions(-) diff --git a/src/libraries/System.Private.DataContractSerialization/src/Resources/Strings.resx b/src/libraries/System.Private.DataContractSerialization/src/Resources/Strings.resx index d2a7b88ce8b30..e0ee506de2bfb 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/Resources/Strings.resx +++ b/src/libraries/System.Private.DataContractSerialization/src/Resources/Strings.resx @@ -1071,6 +1071,9 @@ DataContract for type '{0}' cannot be added to DataContractSet since type '{1}' with the same data contract name '{2}' in namespace '{3}' is already present and the contracts are not equivalent. + + DataContract name '{0}' from namespace '{1}' does not match the generic name '{2}' from namespace '{3}'. + Type '{0}' cannot be exported as a schema type because it is an open generic type. You can only export a generic type if all its generic parameter types are actual types. diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs index 97c0a62f178e1..bd3175ec403a5 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs @@ -11,7 +11,7 @@ using System.Threading; using System.Xml; -using DataContractDictionary = System.Collections.Generic.IDictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization { @@ -20,11 +20,11 @@ internal sealed class ClassDataContract : DataContract internal const string ContractTypeString = nameof(ClassDataContract); public override string? ContractType => ContractTypeString; - public XmlDictionaryString[]? ContractNamespaces; + internal XmlDictionaryString[]? ContractNamespaces; - public XmlDictionaryString[]? MemberNames; + internal XmlDictionaryString[]? MemberNames; - public XmlDictionaryString[]? MemberNamespaces; + internal XmlDictionaryString[]? MemberNamespaces; private XmlDictionaryString?[]? _childElementNamespaces; @@ -63,13 +63,13 @@ internal ClassDataContract? BaseClassContract set => _helper.BaseClassContract = value; } - public override IList? Members + public override List? Members { get => _helper.Members; internal set => _helper.Members = value; } - public XmlDictionaryString?[]? ChildElementNamespaces + internal XmlDictionaryString?[]? ChildElementNamespaces { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get @@ -578,7 +578,7 @@ private sealed class ClassDataContractCriticalHelper : DataContract.DataContract private static Type[]? s_serInfoCtorArgs; private ClassDataContract? _baseContract; - private IList? _members; + private List? _members; private MethodInfo? _onSerializing, _onSerialized; private MethodInfo? _onDeserializing, _onDeserialized; private MethodInfo? _extensionDataSetMethod; @@ -599,9 +599,9 @@ private sealed class ClassDataContractCriticalHelper : DataContract.DataContract private bool _hasDataContract; private bool _hasExtensionData; - public XmlDictionaryString[]? ContractNamespaces; - public XmlDictionaryString[]? MemberNames; - public XmlDictionaryString[]? MemberNamespaces; + internal XmlDictionaryString[]? ContractNamespaces; + internal XmlDictionaryString[]? MemberNames; + internal XmlDictionaryString[]? MemberNamespaces; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal ClassDataContractCriticalHelper([DynamicallyAccessedMembers(DataContractPreserveMemberTypes)] @@ -1132,7 +1132,7 @@ internal ClassDataContract? BaseClassContract } } - internal IList? Members + internal List? Members { get => _members; set => _members = value; @@ -1255,7 +1255,7 @@ internal override bool IsISerializable internal XmlFormatClassReaderDelegate? XmlFormatReaderDelegate { get; set; } - public XmlDictionaryString?[]? ChildElementNamespaces { get; set; } + internal XmlDictionaryString?[]? ChildElementNamespaces { get; set; } private static Type[] SerInfoCtorArgs => s_serInfoCtorArgs ??= new Type[] { typeof(SerializationInfo), typeof(StreamingContext) }; @@ -1292,7 +1292,7 @@ public int Compare(Member x, Member y) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override DataContract BindGenericParameters(DataContract[] paramContracts, IDictionary boundContracts) + internal override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary? boundContracts = null) { Type type = UnderlyingType; if (!type.IsGenericType || !type.ContainsGenericParameters) @@ -1300,7 +1300,7 @@ public override DataContract BindGenericParameters(DataContract[] paramContracts lock (this) { - if (boundContracts.TryGetValue(this, out DataContract? boundContract)) + if (boundContracts != null && boundContracts.TryGetValue(this, out DataContract? boundContract)) return boundContract; XmlQualifiedName stableName; @@ -1341,6 +1341,7 @@ public override DataContract BindGenericParameters(DataContract[] paramContracts boundType = type.MakeGenericType(paramTypes); } ClassDataContract boundClassContract = new ClassDataContract(boundType); + boundContracts ??= new Dictionary(); boundContracts.Add(this, boundClassContract); boundClassContract.StableName = CreateQualifiedName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(stableName.Name), new GenericNameProvider(DataContract.GetClrTypeFullName(UnderlyingType), genericParams)), stableName.Namespace); if (BaseClassContract != null) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs index 03dc1b924c542..0a54659ba532a 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs @@ -12,7 +12,7 @@ using System.Threading; using System.Xml; -using DataContractDictionary = System.Collections.Generic.IDictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization { @@ -153,7 +153,7 @@ private void InitCollectionDataContract(DataContract? sharedTypeContract) internal Type ItemType => _helper.ItemType; - public DataContract ItemContract + internal DataContract ItemContract { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get => _itemContract ?? _helper.ItemContract; @@ -173,7 +173,7 @@ internal string ItemName set => _helper.ItemName = value; } - public XmlDictionaryString CollectionItemName => _collectionItemName; + internal XmlDictionaryString CollectionItemName => _collectionItemName; internal string? KeyName { @@ -203,7 +203,7 @@ public override DataContract BaseContract internal bool IsDictionary => KeyName != null; - public XmlDictionaryString? ChildElementNamespace + internal XmlDictionaryString? ChildElementNamespace { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get @@ -629,7 +629,7 @@ internal bool IsConstructorCheckRequired set => _isConstructorCheckRequired = value; } - public XmlDictionaryString CollectionItemName => _collectionItemName; + internal XmlDictionaryString CollectionItemName => _collectionItemName; internal string? KeyName { @@ -645,11 +645,11 @@ internal string? ValueName internal bool IsDictionary => KeyName != null; - public string? SerializationExceptionMessage => _serializationExceptionMessage; + internal string? SerializationExceptionMessage => _serializationExceptionMessage; - public string? DeserializationExceptionMessage => _deserializationExceptionMessage; + internal string? DeserializationExceptionMessage => _deserializationExceptionMessage; - public XmlDictionaryString? ChildElementNamespace + internal XmlDictionaryString? ChildElementNamespace { get => _childElementNamespace; set => _childElementNamespace = value; @@ -1330,10 +1330,10 @@ private static bool IsKnownInterface(Type type) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override DataContract BindGenericParameters(DataContract[] paramContracts, IDictionary boundContracts) + internal override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary? boundContracts = null) { DataContract boundContract; - if (boundContracts.TryGetValue(this, out boundContract!)) + if (boundContracts != null && boundContracts.TryGetValue(this, out boundContract!)) return boundContract; // NOTE TODO smolloy - this type-binding ('boundType') stuff is new. We did not do this in NetFx. We used to use default constructors and let the @@ -1349,6 +1349,7 @@ public override DataContract BindGenericParameters(DataContract[] paramContracts Type boundType = type.MakeGenericType(paramTypes); CollectionDataContract boundCollectionContract = new CollectionDataContract(boundType); + boundContracts ??= new Dictionary(); boundContracts.Add(this, boundCollectionContract); boundCollectionContract.ItemContract = ItemContract.BindGenericParameters(paramContracts, boundContracts); boundCollectionContract.IsItemTypeNullable = !boundCollectionContract.ItemContract.IsValueType; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs index d7adaf0fbf470..c63bb71000f63 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs @@ -14,7 +14,7 @@ using System.Text; using System.Xml; -using DataContractDictionary = System.Collections.Generic.IDictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization { @@ -207,11 +207,11 @@ public virtual DataContract? BaseContract get => null; } - public virtual GenericInfo? GenericInfo + internal GenericInfo? GenericInfo { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get => _helper.GenericInfo; - internal set => _helper.GenericInfo = value; + set => _helper.GenericInfo = value; } public virtual DataContractDictionary? KnownDataContracts @@ -259,7 +259,7 @@ public virtual bool IsKeyValue(out string? keyName, out string? valueName, out s return false; } - public virtual IList? Members + public virtual List? Members { get => null; internal set { } @@ -274,7 +274,7 @@ internal virtual void WriteRootElement(XmlWriterDelegator writer, XmlDictionaryS } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public virtual DataContract BindGenericParameters(DataContract[] paramContracts, IDictionary boundContracts) + internal virtual DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary? boundContracts = null) { return this; } @@ -2016,7 +2016,7 @@ private static void ImportKnownTypeAttributes(Type? type, Dictionary collectionDataContract.ItemType.GetGenericTypeDefinition() == Globals.TypeOfKeyValue) { DataContract itemDataContract = DataContract.GetDataContract(Globals.TypeOfKeyValuePair.MakeGenericType(collectionDataContract.ItemType.GetGenericArguments())); - knownDataContracts ??= new Dictionary(); + knownDataContracts ??= new DataContractDictionary(); knownDataContracts.TryAdd(itemDataContract.StableName, itemDataContract); } @@ -2040,7 +2040,7 @@ internal static void CheckAndAdd(Type type, Dictionary typesChecked, DataContract dataContract = DataContract.GetDataContract(type); if (nameToDataContractTable == null) { - nameToDataContractTable = new Dictionary(); + nameToDataContractTable = new DataContractDictionary(); } else if (nameToDataContractTable.TryGetValue(dataContract.StableName, out DataContract? alreadyExistingContract)) { @@ -2338,7 +2338,7 @@ private XmlQualifiedName GetStableName(int i) } } - public sealed class GenericInfo : IGenericNameProvider + internal sealed class GenericInfo : IGenericNameProvider { private string? _genericTypeName; private XmlQualifiedName _stableName; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs index 80bf0f84ec834..c0d6cfec922d8 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs @@ -8,7 +8,7 @@ using System.Runtime.CompilerServices; using System.Xml; -using DataContractDictionary = System.Collections.Generic.IDictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs index 1ce8f522da0d1..4b0e82695d13f 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs @@ -8,7 +8,7 @@ using System.Text; using System.Xml.Schema; -using DataContractDictionary = System.Collections.Generic.IDictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization { @@ -18,7 +18,7 @@ public sealed class DataContractSet private Dictionary? _processedContracts; private readonly ISerializationSurrogateProvider? _surrogateProvider; private readonly ISerializationExtendedSurrogateProvider? _extendedSurrogateProvider; - private Hashtable? _surrogateDataTable; + private Hashtable? _surrogateData; private DataContractDictionary? _knownTypesForObject; private readonly ICollection? _referencedTypes; private readonly ICollection? _referencedCollectionTypes; @@ -55,12 +55,12 @@ public DataContractSet(DataContractSet dataContractSet) } public DataContractDictionary Contracts => - _contracts ??= new Dictionary(); + _contracts ??= new DataContractDictionary(); - public IDictionary ProcessedContracts => + public Dictionary ProcessedContracts => _processedContracts ??= new Dictionary(); - private Hashtable SurrogateDataTable => _surrogateDataTable ??= new Hashtable(); + public Hashtable SurrogateData => _surrogateData ??= new Hashtable(); public DataContractDictionary? KnownTypesForObject { @@ -155,7 +155,7 @@ private void AddClassDataContract(ClassDataContract classDataContract) dataMember.MemberInfo, memberDataContract.UnderlyingType); if (customData != null) - SurrogateDataTable.Add(dataMember, customData); + SurrogateData.Add(dataMember, customData); } Add(memberDataContract.StableName, memberDataContract); @@ -223,11 +223,11 @@ public DataContract GetDataContract(Type type) Type dcType = DataContractSurrogateCaller.GetDataContractType(_surrogateProvider, type); dataContract = DataContract.GetDataContract(dcType); - if (_extendedSurrogateProvider != null && !SurrogateDataTable.Contains(dataContract)) + if (_extendedSurrogateProvider != null && !SurrogateData.Contains(dataContract)) { object? customData = DataContractSurrogateCaller.GetCustomDataToExport(_extendedSurrogateProvider, type, dcType); if (customData != null) - SurrogateDataTable.Add(dataContract, customData); + SurrogateData.Add(dataContract, customData); } return dataContract; @@ -406,38 +406,130 @@ private static bool IsTypeReferenceable(Type type) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public bool TryGetReferencedType(XmlQualifiedName stableName, DataContract? dataContract, [NotNullWhen(true)] out Type? type) + public Type? GetReferencedType(XmlQualifiedName stableName, DataContract dataContract, out DataContract? referencedContract, out object[]? genericParameters, bool? supportGenericTypes = null) { + Type? type = GetReferencedTypeInternal(stableName, dataContract); + referencedContract = null; + genericParameters = null; + + if (supportGenericTypes == null) + return type; + + if (type != null && !type.IsGenericTypeDefinition && !type.ContainsGenericParameters) + return type; + + if (dataContract.GenericInfo == null) + return null; + + XmlQualifiedName genericStableName = dataContract.GenericInfo.GetExpandedStableName(); + if (genericStableName != dataContract.StableName) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericTypeNameMismatch, dataContract.StableName.Name, dataContract.StableName.Namespace, genericStableName.Name, genericStableName.Namespace))); + + // This check originally came "here" in the old code. Its tempting to move it up with the GenericInfo check. + if (!supportGenericTypes.Value) + return null; + + type = GetReferencedGenericTypeInternal(dataContract.GenericInfo, out referencedContract, out genericParameters); + return type; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private Type? GetReferencedGenericTypeInternal(GenericInfo genInfo, out DataContract? referencedContract, out object[]? genericParameters) + { + genericParameters = null; + referencedContract = null; + + Type? type = GetReferencedTypeInternal(genInfo.StableName, null); + + if (type == null) + { + if (genInfo.Parameters != null) + return null; + + referencedContract = GetDataContract(genInfo.StableName); + if (referencedContract != null && referencedContract.GenericInfo != null) + referencedContract = null; + + return null; // No type, but maybe we found a suitable referenced contract? + } + + // We've got a type. But its generic. So we need some parameter contracts. + // referencedContract is still null, but will be set if we can verify all parameters. + if (genInfo.Parameters != null) + { + bool enableStructureCheck = (type != Globals.TypeOfNullable); + genericParameters = new object[genInfo.Parameters.Count]; + DataContract[] structureCheckContracts = new DataContract[genInfo.Parameters.Count]; + for (int i = 0; i < genInfo.Parameters.Count; i++) + { + GenericInfo paramInfo = genInfo.Parameters[i]; + XmlQualifiedName paramStableName = paramInfo.GetExpandedStableName(); + DataContract? paramContract = GetDataContract(paramStableName); + + if (paramContract != null) + { + genericParameters[i] = paramContract; + } + else + { + Type? paramType = GetReferencedGenericTypeInternal(paramInfo, out paramContract, out object[]? paramParameters); + if (paramType != null) + { + genericParameters[i] = new Tuple(paramType, paramParameters); + } + else + { + genericParameters[i] = paramContract!; + } + } + + structureCheckContracts[i] = paramContract!; // This is ok. If it's null, we disable the use of this array in the next line. + if (paramContract == null) + enableStructureCheck = false; + } + if (enableStructureCheck) + referencedContract = DataContract.GetDataContract(type).BindGenericParameters(structureCheckContracts); + } + + return type; + } + + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private Type? GetReferencedTypeInternal(XmlQualifiedName stableName, DataContract? dataContract) + { + Type? type; + if (dataContract == null) { if (TryGetReferencedCollectionType(stableName, null, out type)) - return true; - if (TryGetReferencedSingleType(stableName, null, out type)) + return type; + if (TryGetReferencedType(stableName, null, out type)) { // enforce that collection types only be specified via ReferencedCollectionTypes if (CollectionDataContract.IsCollection(type)) - { - type = null; - return false; - } - return true; + return null; + + return type; } - return false; } else if (dataContract is CollectionDataContract) - return TryGetReferencedCollectionType(stableName, dataContract, out type); + { + if (TryGetReferencedCollectionType(stableName, dataContract, out type)) + return type; + } else { if (dataContract is XmlDataContract xmlDataContract && xmlDataContract.IsAnonymous) - { stableName = SchemaImporter.ImportActualType(xmlDataContract.XsdType?.Annotation, stableName, dataContract.StableName); - } - return TryGetReferencedSingleType(stableName, dataContract, out type); + + if (TryGetReferencedType(stableName, dataContract, out type)) + return type; } + return null; } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal bool TryGetReferencedSingleType(XmlQualifiedName stableName, DataContract? dataContract, [NotNullWhen(true)] out Type? type) + internal bool TryGetReferencedType(XmlQualifiedName stableName, DataContract? dataContract, [NotNullWhen(true)] out Type? type) { return TryGetReferencedType(stableName, dataContract, false/*useReferencedCollectionTypes*/, out type); } @@ -501,12 +593,12 @@ private bool TryGetReferencedType(XmlQualifiedName stableName, DataContract? dat internal object? GetSurrogateData(object key) { - return SurrogateDataTable[key]; + return SurrogateData[key]; } internal void SetSurrogateData(object key, object? surrogateData) { - SurrogateDataTable[key] = surrogateData; + SurrogateData[key] = surrogateData; } internal bool IsContractProcessed(DataContract dataContract) @@ -524,11 +616,6 @@ internal IEnumerator> GetEnumerator return Contracts.GetEnumerator(); } - public static void CompileSchemaSet(XmlSchemaSet schemaSet) - { - SchemaImporter.CompileSchemaSet(schemaSet); - } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] public void ExportSchemaSet(XmlSchemaSet schemaSet) { @@ -537,38 +624,18 @@ public void ExportSchemaSet(XmlSchemaSet schemaSet) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public void ImportSchemaSet(XmlSchemaSet schemaSet, ICollection? typeNames, ICollection elements, XmlQualifiedName[] elementTypeNames /*filled on return*/, bool importXmlDataType) + public void ImportSchemaSet(XmlSchemaSet schemaSet, ICollection? typeNames, bool importXmlDataType) { - SchemaImporter importer = new SchemaImporter(schemaSet, typeNames, elements, elementTypeNames, this, importXmlDataType); - importer.Import(); + SchemaImporter importer = new SchemaImporter(schemaSet, typeNames, null, this, importXmlDataType); + importer.Import(out IList _); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public Type? GetReferencedTypeOnImport(DataContract dataContract) - { - ISerializationExtendedSurrogateProvider? dataContractSurrogate = SerializationExtendedSurrogateProvider; - Type? type = null; - if (dataContractSurrogate != null) - { - type = DataContractSurrogateCaller.GetReferencedTypeOnImport( - dataContractSurrogate, - dataContract.StableName.Name, - dataContract.StableName.Namespace, - GetSurrogateData(dataContract)); - } - return type; - } - - public bool TryGetSurrogateData(object key, out object? value) + public IList ImportSchemaSet(XmlSchemaSet schemaSet, ICollection elements, bool importXmlDataType) { - if (SerializationExtendedSurrogateProvider != null) - { - value = GetSurrogateData(key); - return true; - } - - value = null; - return false; + SchemaImporter importer = new SchemaImporter(schemaSet, Array.Empty() /* Needs to be empty, not null for 'elements' to be used. */, elements, this, importXmlDataType); + importer.Import(out IList? elementNames); + return elementNames!; // Not null when we have provided non-null 'typeNames' and 'elements' } } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs index 879ada66bc034..a5abdb176b36a 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs @@ -285,7 +285,7 @@ internal bool RequiresMemberAccessForSet() } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal DataMember BindGenericParameters(DataContract[] paramContracts, IDictionary boundContracts) + internal DataMember BindGenericParameters(DataContract[] paramContracts, Dictionary? boundContracts = null) { DataContract memberTypeContract = MemberTypeContract.BindGenericParameters(paramContracts, boundContracts); DataMember boundDataMember = new DataMember(memberTypeContract, diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs index 8d5f79b0e94e8..197b0cb0cd1a2 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs @@ -36,7 +36,7 @@ public override DataContract BaseContract get => _helper.BaseContract; } - public XmlQualifiedName BaseContractName + internal XmlQualifiedName BaseContractName { get => _helper.BaseContractName; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -44,27 +44,27 @@ public XmlQualifiedName BaseContractName } [NotNull] - public override IList? Members + public override List? Members { get => _helper.Members; internal set => _helper.Members = value!; } - public IList? Values + internal List? Values { get => _helper.Values; set => _helper.Values = value; } - public bool IsFlags + internal bool IsFlags { get => _helper.IsFlags; set => _helper.IsFlags = value; } - public bool IsULong => _helper.IsULong; + internal bool IsULong => _helper.IsULong; - public XmlDictionaryString[]? ChildElementNames => _helper.ChildElementNames; + internal XmlDictionaryString[]? ChildElementNames => _helper.ChildElementNames; internal override bool CanContainReferences => false; @@ -74,8 +74,8 @@ private sealed class EnumDataContractCriticalHelper : DataContract.DataContractC private static readonly Dictionary s_nameToType = new Dictionary(); private DataContract _baseContract; - private IList _members; - private IList? _values; + private List _members; + private List? _values; private bool _isULong; private bool _isFlags; private readonly bool _hasDataContract; @@ -169,13 +169,13 @@ internal XmlQualifiedName BaseContractName } } - internal IList Members + internal List Members { get => _members; set => _members = value; } - internal IList? Values + internal List? Values { get => _values; set => _values = value; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs index fa99733df7699..3f3b87a01b340 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs @@ -40,7 +40,7 @@ internal GenericParameterDataContractCriticalHelper( } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public override DataContract BindGenericParameters(DataContract[] paramContracts, IDictionary boundContracts) + internal override DataContract BindGenericParameters(DataContract[] paramContracts, Dictionary? boundContracts = null) { return paramContracts[ParameterPosition]; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs index d4b7963940365..8b6120b95eaf2 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs @@ -14,7 +14,7 @@ using System.Text; using System.Xml; -using DataContractDictionary = System.Collections.Generic.IDictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization.Json { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonDataContract.cs index 4330703dc3ab8..f33cfa3b9b9eb 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonDataContract.cs @@ -9,6 +9,8 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using DataContractDictionary = System.Collections.Generic.Dictionary; + namespace System.Runtime.Serialization.Json { internal class JsonDataContract @@ -32,7 +34,7 @@ protected JsonDataContract(JsonDataContractCriticalHelper helper) protected DataContract TraditionalDataContract => _helper.TraditionalDataContract; - private Dictionary? KnownDataContracts => _helper.KnownDataContracts; + private DataContractDictionary? KnownDataContracts => _helper.KnownDataContracts; public static JsonReadWriteDelegates? GetGeneratedReadWriteDelegates(DataContract c) { @@ -144,7 +146,7 @@ internal class JsonDataContractCriticalHelper private static readonly TypeHandleRef s_typeHandleRef = new TypeHandleRef(); private static readonly Dictionary s_typeToIDCache = new Dictionary(new TypeHandleRefEqualityComparer()); - private Dictionary? _knownDataContracts; + private DataContractDictionary? _knownDataContracts; private readonly DataContract _traditionalDataContract; private readonly string _typeName; @@ -156,7 +158,7 @@ internal JsonDataContractCriticalHelper(DataContract traditionalDataContract) _typeName = string.IsNullOrEmpty(traditionalDataContract.Namespace.Value) ? traditionalDataContract.Name.Value : string.Concat(traditionalDataContract.Name.Value, JsonGlobals.NameValueSeparatorString, XmlObjectSerializerWriteContextComplexJson.TruncateDefaultDataContractNamespace(traditionalDataContract.Namespace.Value)); } - internal Dictionary? KnownDataContracts => _knownDataContracts; + internal DataContractDictionary? KnownDataContracts => _knownDataContracts; internal DataContract TraditionalDataContract => _traditionalDataContract; @@ -283,7 +285,7 @@ private void AddCollectionItemContractsToKnownDataContracts() while (collectionDataContract != null) { DataContract itemContract = collectionDataContract.ItemContract; - _knownDataContracts ??= new Dictionary(); + _knownDataContracts ??= new DataContractDictionary(); _knownDataContracts.TryAdd(itemContract.StableName, itemContract); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs index cf34c9ba85d1c..177aba2e87060 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs @@ -411,7 +411,7 @@ private int SetRequiredElements(ClassDataContract contract, byte[] requiredEleme { int memberCount = (contract.BaseClassContract == null) ? 0 : SetRequiredElements(contract.BaseClassContract, requiredElements); - IList members = contract.Members!; + List members = contract.Members!; for (int i = 0; i < members.Count; i++, memberCount++) { if (members[i].IsRequired) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonXmlDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonXmlDataContract.cs index 4867129e4e05d..96bef751e97a4 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonXmlDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonXmlDataContract.cs @@ -7,7 +7,7 @@ using System.Text; using System.Xml; -using DataContractDictionary = System.Collections.Generic.IDictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization.Json { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatReader.cs index c0b7b2ab98a98..63572bd37dc26 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatReader.cs @@ -136,7 +136,7 @@ private bool[] GetRequiredMembers(ClassDataContract contract, out int firstRequi private int GetRequiredMembers(ClassDataContract contract, bool[] requiredMembers) { int memberCount = (contract.BaseClassContract == null) ? 0 : GetRequiredMembers(contract.BaseClassContract, requiredMembers); - IList members = contract.Members!; + List members = contract.Members!; for (int i = 0; i < members.Count; i++, memberCount++) { requiredMembers[memberCount] = members[i].IsRequired; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatWriter.cs index 98998a262d419..204d4cb8c15fb 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatWriter.cs @@ -236,7 +236,7 @@ private static bool CheckIfMemberHasConflict(DataMember member, ClassDataContrac { if (ns == currentContract.StableName.Namespace) { - IList members = currentContract.Members!; + List members = currentContract.Members!; for (int j = 0; j < members.Count; j++) { if (name == members[j].Name) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs index 5884ce28ca95e..9c0f606d0542d 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs @@ -7,7 +7,7 @@ using System.Collections; using System.Collections.Generic; -using SchemaObjectDictionary = System.Collections.Generic.IDictionary; +using SchemaObjectDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs index 3df05396f910d..a50a9b35dcd85 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs @@ -12,8 +12,8 @@ using System.Xml; using System.Xml.Schema; -using DataContractDictionary = System.Collections.Generic.IDictionary; -using SchemaObjectDictionary = System.Collections.Generic.IDictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; +using SchemaObjectDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization { @@ -23,8 +23,7 @@ internal sealed class SchemaImporter private DataContractSet _dataContractSet; private XmlSchemaSet _schemaSet; private ICollection? _typeNames; - private ICollection _elements; - private XmlQualifiedName[] _elementTypeNames; + private ICollection? _elements; private bool _importXmlDataType; private SchemaObjectDictionary _schemaObjects = null!; // Not directly referenced. Always lazy initialized by property getter. private List _redefineList = null!; // Not directly referenced. Always lazy initialized by property getter. @@ -32,19 +31,20 @@ internal sealed class SchemaImporter private static Hashtable? s_serializationSchemaElements; - internal SchemaImporter(XmlSchemaSet schemas, ICollection? typeNames, ICollection elements, XmlQualifiedName[] elementTypeNames, DataContractSet dataContractSet, bool importXmlDataType) + internal SchemaImporter(XmlSchemaSet schemas, ICollection? typeNames, ICollection? elements, DataContractSet dataContractSet, bool importXmlDataType) { _dataContractSet = dataContractSet; _schemaSet = schemas; _typeNames = typeNames; _elements = elements; - _elementTypeNames = elementTypeNames; _importXmlDataType = importXmlDataType; } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal void Import() + internal void Import([NotNullIfNotNull("_elements")] out IList? elementTypeNames) { + elementTypeNames = null!; + if (!_schemaSet.Contains(Globals.SerializationNamespace)) { StringReader reader = new StringReader(Globals.SerializationSchema); @@ -97,26 +97,26 @@ internal void Import() ImportType(typeName); } - if (_elements.Count > 0) + if (_elements?.Count > 0) { - int i = 0; + elementTypeNames = new List(); foreach (XmlSchemaElement element in _elements) { XmlQualifiedName typeName = element.SchemaTypeName; if (typeName != null && typeName.Name.Length > 0) { - _elementTypeNames[i++] = ImportType(typeName).StableName; + elementTypeNames.Add(ImportType(typeName).StableName); } else { XmlSchema? schema = SchemaHelper.GetSchemaWithGlobalElementDeclaration(element, _schemaSet); if (schema == null) { - _elementTypeNames[i++] = ImportAnonymousElement(element, element.QualifiedName).StableName; + elementTypeNames.Add(ImportAnonymousElement(element, element.QualifiedName).StableName); } else { - _elementTypeNames[i++] = ImportAnonymousGlobalElement(element, element.QualifiedName, schema.TargetNamespace).StableName; + elementTypeNames.Add(ImportAnonymousGlobalElement(element, element.QualifiedName, schema.TargetNamespace).StableName); } } } @@ -218,7 +218,7 @@ private void ImportKnownTypesForObject() List? knownTypes = schemaObjectInfo._knownTypes; if (knownTypes != null) { - Dictionary knownDataContracts = new Dictionary(); + DataContractDictionary knownDataContracts = new DataContractDictionary(); foreach (XmlSchemaType knownType in knownTypes) { // Expected: will throw exception if schema set contains types that are not supported @@ -236,7 +236,7 @@ private void ImportKnownTypesForObject() internal SchemaObjectDictionary CreateSchemaObjects() { - SchemaObjectDictionary schemaObjects = new Dictionary(); + SchemaObjectDictionary schemaObjects = new SchemaObjectDictionary(); ICollection schemaList = _schemaSet.Schemas(); List knownTypesForObject = new List(); schemaObjects.Add(SchemaExporter.AnytypeQualifiedName, new SchemaObjectInfo(null, null, null, knownTypesForObject)); @@ -494,8 +494,8 @@ private DataContract ImportType(XmlSchemaType type, XmlQualifiedName typeName, b return ImportXmlDataType(typeName, type, isAnonymous); } Type? referencedType; - if (_dataContractSet.TryGetReferencedSingleType(typeName, dataContract, out referencedType) - || (string.IsNullOrEmpty(type.Name) && _dataContractSet.TryGetReferencedSingleType(ImportActualType(type.Annotation, typeName, typeName), dataContract, out referencedType))) + if (_dataContractSet.TryGetReferencedType(typeName, dataContract, out referencedType) + || (string.IsNullOrEmpty(type.Name) && _dataContractSet.TryGetReferencedType(ImportActualType(type.Annotation, typeName, typeName), dataContract, out referencedType))) { if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(referencedType)) { @@ -705,14 +705,6 @@ private DataContract ImportXmlDataType(XmlQualifiedName typeName, XmlSchemaType xmlDataContract.XsdType = isAnonymous ? xsdType : null; xmlDataContract.HasRoot = !IsXmlAnyElementType(xsdType as XmlSchemaComplexType); } - else - { - // NOTE TODO smolloy - I think this might be dead code. It doesn't appear like xsdType can be null in this method. - //Value type can be used by both nillable and non-nillable elements but reference type cannot be used by non nillable elements - xmlDataContract.IsValueType = true; - xmlDataContract.IsTypeDefinedOnImport = false; - xmlDataContract.HasRoot = true; - } if (!isAnonymous) { bool isNullable; @@ -734,7 +726,7 @@ private DataContract ImportXmlDataType(XmlQualifiedName typeName, XmlSchemaType //check if the type is XElement XmlQualifiedName xlinqTypeName = new XmlQualifiedName("XElement", "http://schemas.datacontract.org/2004/07/System.Xml.Linq"); Type? referencedType; - if (_dataContractSet.TryGetReferencedSingleType(xlinqTypeName, null, out referencedType) + if (_dataContractSet.TryGetReferencedType(xlinqTypeName, null, out referencedType) && Globals.TypeOfIXmlSerializable.IsAssignableFrom(referencedType)) { XmlDataContract xmlDataContract = new XmlDataContract(referencedType); @@ -907,7 +899,7 @@ private void ImportBaseContract(XmlQualifiedName baseTypeName, ClassDataContract DataContractDictionary? knownDataContracts = ancestorDataContract.KnownDataContracts; if (knownDataContracts == null) { - knownDataContracts = new Dictionary(); + knownDataContracts = new DataContractDictionary(); ancestorDataContract.KnownDataContracts = knownDataContracts; } knownDataContracts.Add(dataContract.StableName, dataContract); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ScopedKnownTypes.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ScopedKnownTypes.cs index 2bc716206d5d2..ebf0d78e87b59 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ScopedKnownTypes.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ScopedKnownTypes.cs @@ -3,7 +3,8 @@ using System; using System.Xml; -using DataContractDictionary = System.Collections.Generic.IDictionary; + +using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs index d81e61c952d23..d9d66185046e5 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs @@ -12,7 +12,8 @@ using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; -using DataContractDictionary = System.Collections.Generic.IDictionary; + +using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs index d176eb6f5ceb7..eab43fba40bde 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs @@ -462,7 +462,7 @@ private bool[] GetRequiredMembers(ClassDataContract contract, out int firstRequi private int GetRequiredMembers(ClassDataContract contract, bool[] requiredMembers) { int memberCount = (contract.BaseClassContract == null) ? 0 : GetRequiredMembers(contract.BaseClassContract, requiredMembers); - IList members = contract.Members!; + List members = contract.Members!; for (int i = 0; i < members.Count; i++, memberCount++) { requiredMembers[memberCount] = members[i].IsRequired; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs index 3676ceb9879b1..0e984e1a3adb3 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs @@ -787,7 +787,7 @@ private static bool CheckIfMemberHasConflict(DataMember member, ClassDataContrac { if (ns == currentContract.StableName.Namespace) { - IList members = currentContract.Members!; + List members = currentContract.Members!; for (int j = 0; j < members.Count; j++) { if (name == members[j].Name) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializer.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializer.cs index 7eebd5560e6de..9e43885574c57 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializer.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializer.cs @@ -10,7 +10,8 @@ using System.Security; using System.Text; using System.Xml; -using DataContractDictionary = System.Collections.Generic.IDictionary; + +using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs index 79802e6cf99ce..d9bbe2b0d4dff 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs @@ -8,7 +8,8 @@ using System.Reflection; using System.Security; using System.Xml; -using DataContractDictionary = System.Collections.Generic.IDictionary; + +using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization { @@ -177,7 +178,7 @@ internal virtual DataContractDictionary? SerializerKnownDataContracts internal static DataContractDictionary? GetDataContractsForKnownTypes(IList knownTypeList) { if (knownTypeList == null) return null; - DataContractDictionary dataContracts = new Dictionary(); + DataContractDictionary dataContracts = new DataContractDictionary(); Dictionary typesChecked = new Dictionary(); for (int i = 0; i < knownTypeList.Count; i++) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContext.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContext.cs index b7206cf298983..b310d9d075bb5 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContext.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContext.cs @@ -10,7 +10,8 @@ using System.Text; using System.Xml; using System.Xml.Serialization; -using DataContractDictionary = System.Collections.Generic.IDictionary; + +using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization { diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/Resources/Strings.resx b/src/libraries/System.Runtime.Serialization.Schema/src/Resources/Strings.resx index b9b843b480875..54cb0b117a74e 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/Resources/Strings.resx +++ b/src/libraries/System.Runtime.Serialization.Schema/src/Resources/Strings.resx @@ -157,9 +157,6 @@ CLR namespace '{2}' has already been mapped to data contract namespace '{0}'. It cannot be mapped to another data contract namespace '{1}'. - - DataContract name '{0}' from namespace '{1}' does not match the generic name '{2}' from namespace '{3}'. - ISerializable type with data contract name '{0}' in namespace '{1}' cannot be imported. The data contract name cannot be customized for ISerializable type and the generated name '{2}' does not match the expected name '{0}'. Check if the required name has been mapped to a different type or if it is an invalid CLR name which cannot be generated or if the type requires an outer type which is not present. diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs index 3bfac8cf86a73..2989fec643feb 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs @@ -18,7 +18,7 @@ using System.Xml.Schema; using System.Xml.Serialization; -using DataContractDictionary = System.Collections.Generic.IDictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; using ExceptionUtil = System.Runtime.Serialization.Schema.DiagnosticUtility.ExceptionUtility; namespace System.Runtime.Serialization.Schema @@ -325,6 +325,40 @@ private CodeTypeReference GetCodeTypeReference(Type type) return new CodeTypeReference(type); } + private CodeTypeReference? GetCodeTypeReference(Type type, IList? parameters) + { + CodeTypeReference codeTypeReference = GetCodeTypeReference(type); + + if (parameters != null) + { + foreach (var param in parameters) + { + CodeTypeReference? paramTypeReference = null; + bool isParamValueType = true; // Default not important. It either gets set, or paramTypeReference stays null and we short circuit before referencing this value. + + if (param is DataContract paramContract) + { + paramTypeReference = GetCodeTypeReference(paramContract); + isParamValueType = paramContract.IsValueType; + } + else if (param is Tuple typeParameters) + { + paramTypeReference = GetCodeTypeReference(typeParameters.Item1, typeParameters.Item2); + isParamValueType = (paramTypeReference != null && paramTypeReference.ArrayRank == 0); // only value type information we can get from CodeTypeReference + } + + if (paramTypeReference == null) + return null; + if (type == typeof(Nullable<>) && !isParamValueType) + return paramTypeReference; + else + codeTypeReference.TypeArguments.Add(paramTypeReference); + } + } + + return codeTypeReference; + } + [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] internal CodeTypeReference GetElementTypeReference(DataContract dataContract, bool isElementTypeNullable) { @@ -425,8 +459,8 @@ private void GenerateType(DataContract dataContract, ContractCodeDomInfo contrac type.TypeAttributes = TypeAttributes.Public; } - if (_dataContractSet.TryGetSurrogateData(dataContract, out object? surrogateData)) - type.UserData.Add(s_surrogateDataKey, surrogateData); + if (_options?.SurrogateProvider != null) + type.UserData.Add(s_surrogateDataKey, _dataContractSet.SurrogateData[dataContract]); contractCodeDomInfo.TypeDeclaration = type; } @@ -507,8 +541,8 @@ private static CodeTypeDeclaration CreateTypeDeclaration(string typeName, DataCo if (typeReference != null) return typeReference; - if (_dataContractSet.TryGetReferencedType(dataContract.StableName, dataContract, out Type? type) - && !type.IsGenericTypeDefinition && !type.ContainsGenericParameters) + Type? type = _dataContractSet.GetReferencedType(dataContract.StableName, dataContract, out DataContract? referencedContract, out object[]? parameters, SupportsGenericTypeReference); + if (type != null && !type.IsGenericTypeDefinition && !type.ContainsGenericParameters) { if (dataContract is XmlDataContract xmlContract) { @@ -528,7 +562,7 @@ private static CodeTypeDeclaration CreateTypeDeclaration(string typeName, DataCo } throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.TypeMustBeIXmlSerializable, GetClrTypeFullName(type), GetClrTypeFullName(typeof(IXmlSerializable)), dataContract.StableName.Name, dataContract.StableName.Namespace))); } - DataContract referencedContract = _dataContractSet.GetDataContract(type); + referencedContract = _dataContractSet.GetDataContract(type); if (referencedContract.Equals(dataContract)) { typeReference = GetCodeTypeReference(type); @@ -537,19 +571,12 @@ private static CodeTypeDeclaration CreateTypeDeclaration(string typeName, DataCo } throw ExceptionUtil.ThrowHelperError(new InvalidOperationException(SR.Format(SR.ReferencedTypeDoesNotMatch, type.AssemblyQualifiedName, dataContract.StableName.Name, dataContract.StableName.Namespace))); } - else if (dataContract.GenericInfo != null) + else if (type != null) { - DataContract? referencedContract; - XmlQualifiedName genericStableName = dataContract.GenericInfo.GetExpandedStableName(); - if (genericStableName != dataContract.StableName) - throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericTypeNameMismatch, dataContract.StableName.Name, dataContract.StableName.Namespace, genericStableName.Name, genericStableName.Namespace))); + typeReference = GetCodeTypeReference(type, parameters); - typeReference = GetReferencedGenericType(dataContract.GenericInfo, out referencedContract); if (referencedContract != null && !referencedContract.Equals(dataContract)) { - // NOTE TODO smolloy - This is the 4.8 code... but feels like a bug? Looking at 'GetReferenceGenericType()' it is possible to get return - // a non-null 'referencedContract', but also null 'typeReference'. - // For now... assert to get out of the way of compilation. But should we add a check here? Debug.Assert(typeReference != null); type = (Type?)typeReference.UserData[s_codeUserDataActualTypeKey]; throw ExceptionUtil.ThrowHelperError(new InvalidOperationException(SR.Format(SR.ReferencedTypeDoesNotMatch, @@ -557,6 +584,12 @@ private static CodeTypeDeclaration CreateTypeDeclaration(string typeName, DataCo referencedContract.StableName.Name, referencedContract.StableName.Namespace))); } + + return typeReference; + } + else if (referencedContract != null) + { + typeReference = GetCodeTypeReference(referencedContract); return typeReference; } @@ -622,9 +655,7 @@ private bool TryGetReferencedDictionaryType(DataContract collectionContract, [No if (collectionContract.IsKeyValue(out _, out _, out _) && SupportsGenericTypeReference) { - Type? type; - if (!_dataContractSet.TryGetReferencedType(GenericDictionaryName, GenericDictionaryContract, out type)) - type = typeof(Dictionary<,>); + Type? type = _dataContractSet.GetReferencedType(GenericDictionaryName, GenericDictionaryContract, out DataContract? _, out object[]? _) ?? typeof(Dictionary<,>); // ItemContract - aka BaseContract - is never null for CollectionDataContract DataContract? itemContract = collectionContract.BaseContract!.As(DataContractType.ClassDataContract); @@ -652,12 +683,15 @@ private bool TryGetReferencedDictionaryType(DataContract collectionContract, [No [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] private bool TryGetReferencedListType(DataContract itemContract, bool isItemTypeNullable, out CodeTypeReference? typeReference) { - Type? type; - if (SupportsGenericTypeReference && _dataContractSet.TryGetReferencedType(GenericListName, GenericListContract, out type)) + if (SupportsGenericTypeReference) { - typeReference = GetCodeTypeReference(type); - typeReference.TypeArguments.Add(GetElementTypeReference(itemContract, isItemTypeNullable)!); // Lists have an item type - return true; + Type? type = _dataContractSet.GetReferencedType(GenericListName, GenericListContract, out DataContract? _, out object[]? _); + if (type != null) + { + typeReference = GetCodeTypeReference(type); + typeReference.TypeArguments.Add(GetElementTypeReference(itemContract, isItemTypeNullable)!); // Lists have an item type + return true; + } } typeReference = null; return false; @@ -666,7 +700,7 @@ private bool TryGetReferencedListType(DataContract itemContract, bool isItemType [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] private CodeTypeReference? GetSurrogatedTypeReference(DataContract dataContract) { - Type? type = _dataContractSet.GetReferencedTypeOnImport(dataContract); + Type? type = GetReferencedTypeOnImport(dataContract); if (type != null) { CodeTypeReference typeReference = GetCodeTypeReference(type); @@ -676,66 +710,15 @@ private bool TryGetReferencedListType(DataContract itemContract, bool isItemType return null; } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - private CodeTypeReference? GetReferencedGenericType(GenericInfo genInfo, out DataContract? dataContract) + private Type? GetReferencedTypeOnImport(DataContract dataContract) { - dataContract = null; - - if (!SupportsGenericTypeReference) - return null; - - Type? type; - if (!_dataContractSet.TryGetReferencedType(genInfo.StableName, null, out type)) - { - if (genInfo.Parameters != null) - return null; - dataContract = _dataContractSet.GetDataContract(genInfo.StableName); - if (dataContract == null) - return null; - if (dataContract.GenericInfo != null) - return null; - return GetCodeTypeReference(dataContract); - } - - bool enableStructureCheck = (type != typeof(Nullable<>)); - CodeTypeReference typeReference = GetCodeTypeReference(type); - typeReference.UserData.Add(s_codeUserDataActualTypeKey, type); - if (genInfo.Parameters != null) + Type? type = null; + if (_options?.SurrogateProvider is ISerializationExtendedSurrogateProvider surrogateProvider) { - DataContract[] paramContracts = new DataContract[genInfo.Parameters.Count]; - for (int i = 0; i < genInfo.Parameters.Count; i++) - { - GenericInfo paramInfo = genInfo.Parameters[i]; - XmlQualifiedName stableName = paramInfo.GetExpandedStableName(); - DataContract? paramContract = _dataContractSet.GetDataContract(stableName); - - CodeTypeReference? paramTypeReference; - bool isParamValueType; - if (paramContract != null) - { - paramTypeReference = GetCodeTypeReference(paramContract); - isParamValueType = paramContract.IsValueType; - } - else - { - paramTypeReference = GetReferencedGenericType(paramInfo, out paramContract); - isParamValueType = (paramTypeReference != null && paramTypeReference.ArrayRank == 0); // only value type information we can get from CodeTypeReference - } - paramContracts[i] = paramContract!; // Potentially tricky here. We could assign a null item here, and that's ok. We subsequently disable the structure check in that case. See note below. - if (paramContract == null) - enableStructureCheck = false; - if (paramTypeReference == null) - return null; - if (type == typeof(Nullable<>) && !isParamValueType) - return paramTypeReference; - else - typeReference.TypeArguments.Add(paramTypeReference); - } - // paramContracts could contain null values, but if it does, this structure check is disabled. So we know paramContracts has no null values if we go through with this call. - if (enableStructureCheck) - dataContract = DataContract.GetDataContract(type).BindGenericParameters(paramContracts, new Dictionary()); + if (DataContract.GetBuiltInDataContract(dataContract.StableName.Name, dataContract.StableName.Namespace) == null) + type = surrogateProvider.GetReferencedTypeOnImport(dataContract.StableName.Name, dataContract.StableName.Namespace, _dataContractSet.SurrogateData[dataContract]); } - return typeReference; + return type; } private static bool NamespaceContainsType(CodeNamespace ns, string typeName) @@ -876,7 +859,8 @@ private void ExportClassDataContract(DataContract classDataContract, ContractCod field.Attributes = MemberAttributes.Private; CodeMemberProperty property = CreateProperty(memberType, propertyName, fieldName, dataMember.MemberTypeContract.IsValueType && SupportsDeclareValueTypes, raisePropertyChanged); - if (_dataContractSet.TryGetSurrogateData(dataMember, out object? surrogateData)) + object? surrogateData = _dataContractSet.SurrogateData[dataMember]; + if (surrogateData != null) property.UserData.Add(s_surrogateDataKey, surrogateData); CodeAttributeDeclaration dataMemberAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(DataMemberAttribute))); @@ -993,8 +977,7 @@ private static void AddKnownTypeContracts(DataContract classDataContract, DataCo Debug.Assert(classDataContract.Is(DataContractType.ClassDataContract)); - if (classDataContract.KnownDataContracts == null) - classDataContract.KnownDataContracts = new Dictionary(); + classDataContract.KnownDataContracts ??= new DataContractDictionary(); foreach (KeyValuePair pair in knownContracts) { diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaHelper.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaHelper.cs index 3215f4cb57ab4..9f833c0b4476b 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaHelper.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaHelper.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Xml.Schema; + namespace System.Runtime.Serialization.Schema { internal enum DataContractType @@ -51,6 +53,24 @@ internal static bool IsItemTypeNullable(this DataContract collectionDataContract internal static class SchemaHelper { + internal static void CompileSchemaSet(XmlSchemaSet schemaSet) + { + if (schemaSet.Contains(XmlSchema.Namespace)) + schemaSet.Compile(); + else + { + // Add base XSD schema with top level element named "schema" + XmlSchema xsdSchema = new XmlSchema(); + xsdSchema.TargetNamespace = XmlSchema.Namespace; + XmlSchemaElement element = new XmlSchemaElement(); + element.Name = Globals.SchemaLocalName; + element.SchemaType = new XmlSchemaComplexType(); + xsdSchema.Items.Add(element); + schemaSet.Add(xsdSchema); + schemaSet.Compile(); + } + } + internal static bool IsTypeNullable(Type type) { return !type.IsValueType || diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs index b2dbdc14cbc22..07accbceac432 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs @@ -67,7 +67,7 @@ public XmlSchemaSet Schemas get { XmlSchemaSet schemaSet = GetSchemaSet(); - DataContractSet.CompileSchemaSet(schemaSet); + SchemaHelper.CompileSchemaSet(schemaSet); return schemaSet; } } diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs index 26c33ddda3775..6785fa14d2c46 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs @@ -4,6 +4,7 @@ using System; using System.CodeDom; using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Xml; using System.Xml.Schema; @@ -31,7 +32,6 @@ public sealed class XsdDataContractImporter private DataContractSet? _dataContractSet; private static readonly XmlQualifiedName[] s_emptyTypeNameArray = Array.Empty(); - private static readonly XmlSchemaElement[] s_emptyElementArray = Array.Empty(); private XmlQualifiedName[] _singleTypeNameArray = null!; // Not directly referenced. Always lazy initialized by property getter. private XmlSchemaElement[] _singleElementArray = null!; // Not directly referenced. Always lazy initialized by property getter. @@ -84,7 +84,7 @@ public void Import(XmlSchemaSet schemas) if (schemas == null) throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(schemas))); - InternalImport(schemas, null, s_emptyElementArray, s_emptyTypeNameArray); + InternalImport(schemas, null, null); } /// @@ -101,7 +101,7 @@ public void Import(XmlSchemaSet schemas, ICollection typeNames if (typeNames == null) throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(typeNames))); - InternalImport(schemas, typeNames, s_emptyElementArray, s_emptyTypeNameArray); + InternalImport(schemas, typeNames, null); } /// @@ -119,7 +119,7 @@ public void Import(XmlSchemaSet schemas, XmlQualifiedName typeName) throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(typeName))); SingleTypeNameArray[0] = typeName; - InternalImport(schemas, SingleTypeNameArray, s_emptyElementArray, s_emptyTypeNameArray); + InternalImport(schemas, SingleTypeNameArray, null); } /// @@ -139,8 +139,9 @@ public void Import(XmlSchemaSet schemas, XmlQualifiedName typeName) throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(element))); SingleElementArray[0] = element; - InternalImport(schemas, s_emptyTypeNameArray, SingleElementArray, SingleTypeNameArray /*filled on return*/); - return SingleTypeNameArray[0]; + IList? elementNames = InternalImport(schemas, s_emptyTypeNameArray, SingleElementArray); + Debug.Assert(elementNames != null && elementNames.Count > 0); + return elementNames[0]; } /// @@ -154,7 +155,7 @@ public bool CanImport(XmlSchemaSet schemas) if (schemas == null) throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(schemas))); - return InternalCanImport(schemas, null, s_emptyElementArray, s_emptyTypeNameArray); + return InternalCanImport(schemas, null, null); } /// @@ -172,7 +173,7 @@ public bool CanImport(XmlSchemaSet schemas, ICollection typeNa if (typeNames == null) throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(typeNames))); - return InternalCanImport(schemas, typeNames, s_emptyElementArray, s_emptyTypeNameArray); + return InternalCanImport(schemas, typeNames, null); } /// @@ -190,7 +191,7 @@ public bool CanImport(XmlSchemaSet schemas, XmlQualifiedName typeName) if (typeName == null) throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(typeName))); - return InternalCanImport(schemas, new XmlQualifiedName[] { typeName }, s_emptyElementArray, s_emptyTypeNameArray); + return InternalCanImport(schemas, new XmlQualifiedName[] { typeName }, null); } /// @@ -209,7 +210,7 @@ public bool CanImport(XmlSchemaSet schemas, XmlSchemaElement element) throw ExceptionUtil.ThrowHelperError(new ArgumentNullException(nameof(element))); SingleElementArray[0] = element; - return InternalCanImport(schemas, s_emptyTypeNameArray, SingleElementArray, SingleTypeNameArray); + return InternalCanImport(schemas, s_emptyTypeNameArray, SingleElementArray); } /// @@ -303,15 +304,21 @@ private XmlSchemaElement[] SingleElementArray } [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - private void InternalImport(XmlSchemaSet schemas, ICollection? typeNames, ICollection elements, XmlQualifiedName[] elementTypeNames/*filled on return*/) + private IList? InternalImport(XmlSchemaSet schemas, ICollection? typeNames, ICollection? elements) { DataContractSet? oldValue = (_dataContractSet == null) ? null : new DataContractSet(_dataContractSet); + IList? elementTypeNames = null; try { - DataContractSet.ImportSchemaSet(schemas, typeNames, elements, elementTypeNames/*filled on return*/, ImportXmlDataType); + if (elements != null) + elementTypeNames = DataContractSet.ImportSchemaSet(schemas, elements, ImportXmlDataType); + else + DataContractSet.ImportSchemaSet(schemas, typeNames, ImportXmlDataType); CodeExporter codeExporter = new CodeExporter(DataContractSet, Options, CodeCompileUnit); codeExporter.Export(); + + return elementTypeNames; } catch { @@ -329,12 +336,15 @@ private bool ImportXmlDataType } [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - private bool InternalCanImport(XmlSchemaSet schemas, ICollection? typeNames, ICollection elements, XmlQualifiedName[] elementTypeNames) + private bool InternalCanImport(XmlSchemaSet schemas, ICollection? typeNames, ICollection? elements) { DataContractSet? oldValue = (_dataContractSet == null) ? null : new DataContractSet(_dataContractSet); try { - DataContractSet.ImportSchemaSet(schemas, typeNames, elements, elementTypeNames/*filled on return*/, ImportXmlDataType); + if (elements != null) + DataContractSet.ImportSchemaSet(schemas, elements, ImportXmlDataType); + else + DataContractSet.ImportSchemaSet(schemas, typeNames, ImportXmlDataType); return true; } catch (ArgumentException) diff --git a/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs b/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs index 239377f1ee237..bbb0a59660cf7 100644 --- a/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs +++ b/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs @@ -9,8 +9,6 @@ namespace System.Runtime.Serialization public abstract partial class DataContract { public virtual DataContract? BaseContract { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public virtual DataContract BindGenericParameters(DataContract[] paramContracts, System.Collections.Generic.IDictionary boundContracts) { throw null; } public virtual string? ContractType { get { throw null; } } internal DataContract(DataContractCriticalHelper helper) { } internal const System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes DataContractPreserveMemberTypes = @@ -21,7 +19,6 @@ internal DataContract(DataContractCriticalHelper helper) { } System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties; public static string EncodeLocalName(string localName) { throw null; } - public virtual GenericInfo? GenericInfo { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public virtual System.Xml.XmlQualifiedName GetArrayTypeName(bool isNullable) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] @@ -39,8 +36,8 @@ internal DataContract(DataContractCriticalHelper helper) { } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public static bool IsTypeSerializable(Type type) { throw null; } public virtual bool IsValueType { get { throw null; } } - public virtual System.Collections.Generic.IDictionary? KnownDataContracts { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } set { throw null; } } - public virtual System.Collections.Generic.IList? Members { get { throw null; } } + public virtual System.Collections.Generic.Dictionary? KnownDataContracts { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } set { throw null; } } + public virtual System.Collections.Generic.List? Members { get { throw null; } } public virtual Type OriginalUnderlyingType { get { throw null; } } public virtual System.Xml.XmlQualifiedName StableName { get { throw null; } } [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(DataContract.DataContractPreserveMemberTypes)] @@ -122,8 +119,7 @@ public sealed partial class DataContractSet { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public void Add(Type type) { throw null; } - public static void CompileSchemaSet(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; } - public System.Collections.Generic.IDictionary Contracts { get { throw null; } } + public System.Collections.Generic.Dictionary Contracts { get { throw null; } } public DataContractSet(ISerializationSurrogateProvider? dataContractSurrogate, System.Collections.Generic.ICollection? referencedTypes, System.Collections.Generic.ICollection? referencedCollectionTypes) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public DataContractSet(DataContractSet dataContractSet) { throw null; } @@ -134,14 +130,14 @@ public sealed partial class DataContractSet [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public DataContract? GetDataContract(System.Xml.XmlQualifiedName key) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public Type? GetReferencedTypeOnImport(DataContract dataContract) { throw null; } + public Type? GetReferencedType(System.Xml.XmlQualifiedName stableName, DataContract dataContract, out DataContract? referencedContract, out object[]? genericParameters, bool? supportGenericTypes = null) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public void ImportSchemaSet(System.Xml.Schema.XmlSchemaSet schemaSet, System.Collections.Generic.ICollection? typeNames, System.Collections.Generic.ICollection elements, System.Xml.XmlQualifiedName[] elementTypeNames, bool importXmlDataType) { throw null; } - public System.Collections.Generic.IDictionary? KnownTypesForObject { get { throw null; } } - public System.Collections.Generic.IDictionary ProcessedContracts { get { throw null; } } + public void ImportSchemaSet(System.Xml.Schema.XmlSchemaSet schemaSet, System.Collections.Generic.ICollection? typeNames, bool importXmlDataType) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public bool TryGetReferencedType(System.Xml.XmlQualifiedName stableName, DataContract? dataContract, [System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out Type? type) { throw null; } - public bool TryGetSurrogateData(object key, out object? value) { throw null; } + public System.Collections.Generic.IList ImportSchemaSet(System.Xml.Schema.XmlSchemaSet schemaSet, System.Collections.Generic.ICollection elements, bool importXmlDataType) { throw null; } + public System.Collections.Generic.Dictionary? KnownTypesForObject { get { throw null; } } + public System.Collections.Generic.Dictionary ProcessedContracts { get { throw null; } } + public System.Collections.Hashtable SurrogateData { get { throw null; } } } public sealed partial class DataMember { @@ -162,14 +158,6 @@ public sealed partial class ExtensionDataObject { internal ExtensionDataObject() { } } - public sealed partial class GenericInfo - { - internal GenericInfo() { } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public System.Xml.XmlQualifiedName GetExpandedStableName() { throw null; } - public System.Collections.Generic.IList? Parameters { get { throw null; } } - public System.Xml.XmlQualifiedName StableName { get { throw null; } } - } public partial interface IExtensibleDataObject { System.Runtime.Serialization.ExtensionDataObject? ExtensionData { get; set; } From 8157957a269dcb627a101cc1ee1f803215ca45aa Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Thu, 14 Jul 2022 12:36:47 -0700 Subject: [PATCH 19/33] Project file cleanup --- .../System.Runtime.Serialization.Schema.csproj | 6 +----- .../System.Runtime.Serialization.Schema.csproj | 17 ++++------------- ...em.Runtime.Serialization.Schema.Tests.csproj | 15 +++++---------- 3 files changed, 10 insertions(+), 28 deletions(-) diff --git a/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.csproj b/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.csproj index d2e83b9b09982..1e7317def2573 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.csproj +++ b/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.csproj @@ -1,16 +1,12 @@ - $(NetCoreAppCurrent) + $(NetCoreAppCurrent) - diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj b/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj index 558c94b312d7c..a4c8ca0b8ac07 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj @@ -1,17 +1,12 @@ - $(NetCoreAppCurrent) + $(NetCoreAppCurrent) true - $(DefineConstants) - $(NoWarn);1634;1691;649 Microsoft - false - - - false + true + + true Provides support for importing and exporting xsd schemas for DataContractSerializer. Commonly Used Types: @@ -31,10 +26,6 @@ System.Runtime.Serialization.Schema.XsdDataContractImporter - diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/System.Runtime.Serialization.Schema.Tests.csproj b/src/libraries/System.Runtime.Serialization.Schema/tests/System.Runtime.Serialization.Schema.Tests.csproj index 117d85f44ea29..760c6abace0ae 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/tests/System.Runtime.Serialization.Schema.Tests.csproj +++ b/src/libraries/System.Runtime.Serialization.Schema/tests/System.Runtime.Serialization.Schema.Tests.csproj @@ -1,25 +1,20 @@ + $(NetCoreAppCurrent) true - $(NetCoreAppCurrent) + + - - Always - + + - - - From f1414b8ddb33ffa660abcc3dc3c3c32827b97c6a Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Thu, 14 Jul 2022 17:38:33 -0700 Subject: [PATCH 20/33] Fix mono issue with reflection access to non-public private fields. --- .../src/System/Runtime/Serialization/ClassDataContract.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs index bd3175ec403a5..4ad42f98f8e3f 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs @@ -20,9 +20,9 @@ internal sealed class ClassDataContract : DataContract internal const string ContractTypeString = nameof(ClassDataContract); public override string? ContractType => ContractTypeString; - internal XmlDictionaryString[]? ContractNamespaces; + public XmlDictionaryString[]? ContractNamespaces; - internal XmlDictionaryString[]? MemberNames; + public XmlDictionaryString[]? MemberNames; internal XmlDictionaryString[]? MemberNamespaces; From bf6d5dd3e60f14afabafebc5f26b839b0954e085 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Fri, 29 Jul 2022 13:49:15 -0700 Subject: [PATCH 21/33] Addressing feedback from API review. --- ...m.Private.DataContractSerialization.csproj | 1 - .../Runtime/Serialization/AccessorBuilder.cs | 1 + .../Serialization/ClassDataContract.cs | 51 +-- .../Runtime/Serialization/CodeGenerator.cs | 1 + .../Serialization/CollectionDataContract.cs | 30 +- .../Runtime/Serialization/DataContract.cs | 199 +++++---- .../Serialization/DataContractResolver.cs | 1 + .../Serialization/DataContractSerializer.cs | 3 +- .../Runtime/Serialization/DataContractSet.cs | 136 +++--- .../DataContractSurrogateCaller.cs | 9 +- .../Runtime/Serialization/DataMember.cs | 2 +- .../Runtime/Serialization/EnumDataContract.cs | 32 +- .../Runtime/Serialization/ExportOptions.cs | 16 + .../Serialization/ExtensionDataReader.cs | 7 +- .../GenericParameterDataContract.cs | 4 +- .../System/Runtime/Serialization/Globals.cs | 3 +- .../Json/DataContractJsonSerializer.cs | 16 +- .../Json/JsonByteArrayDataContract.cs | 5 +- .../Json/JsonClassDataContract.cs | 9 +- .../Json/JsonCollectionDataContract.cs | 1 + .../Serialization/Json/JsonDataContract.cs | 13 +- .../Json/JsonEnumDataContract.cs | 1 + .../Json/JsonFormatGeneratorStatics.cs | 1 + .../Json/JsonFormatReaderGenerator.cs | 7 +- .../Json/JsonFormatWriterGenerator.cs | 5 +- .../Json/JsonObjectDataContract.cs | 7 +- .../Json/JsonQNameDataContract.cs | 5 +- .../Json/JsonStringDataContract.cs | 5 +- .../Serialization/Json/JsonUriDataContract.cs | 1 + .../Serialization/Json/JsonXmlDataContract.cs | 9 +- .../Json/ReflectionJsonFormatReader.cs | 1 + .../Json/ReflectionJsonFormatWriter.cs | 1 + ...lObjectSerializerReadContextComplexJson.cs | 7 +- ...ObjectSerializerWriteContextComplexJson.cs | 17 +- .../KnownTypeDataContractResolver.cs | 3 +- .../Serialization/PrimitiveDataContract.cs | 2 +- .../Serialization/ReflectionClassWriter.cs | 1 + .../Serialization/ReflectionFeature.cs | 10 - .../Runtime/Serialization/ReflectionReader.cs | 3 +- .../ReflectionXmlFormatReader.cs | 15 +- .../ReflectionXmlFormatWriter.cs | 5 +- .../Runtime/Serialization/SchemaExporter.cs | 65 +-- .../Runtime/Serialization/SchemaHelper.cs | 6 +- .../Runtime/Serialization/SchemaImporter.cs | 71 ++-- .../Runtime/Serialization/ScopedKnownTypes.cs | 3 +- .../Serialization/SpecialTypeDataContract.cs | 2 +- .../Serialization/SurrogateDataContract.cs | 4 +- .../Serialization/XPathQueryGenerator.cs | 9 +- .../Runtime/Serialization/XmlDataContract.cs | 21 +- .../XmlFormatGeneratorStatics.cs | 5 +- .../Serialization/XmlFormatReaderGenerator.cs | 29 +- .../Serialization/XmlFormatWriterGenerator.cs | 23 +- .../Serialization/XmlObjectSerializer.cs | 3 +- .../XmlObjectSerializerContext.cs | 13 +- .../XmlObjectSerializerReadContext.cs | 7 +- .../XmlObjectSerializerReadContextComplex.cs | 1 + .../XmlObjectSerializerWriteContext.cs | 20 +- .../XmlObjectSerializerWriteContextComplex.cs | 9 +- .../Serialization/XmlReaderDelegator.cs | 7 +- .../Serialization/XmlSerializableWriter.cs | 1 + .../Serialization/XmlWriterDelegator.cs | 1 + .../Serialization/XsdDataContractExporter.cs | 124 +++++- .../ref/System.Runtime.Serialization.Json.cs | 7 +- ...System.Runtime.Serialization.Primitives.cs | 4 +- ...em.Runtime.Serialization.Primitives.csproj | 2 +- ...cs => ISerializationSurrogateProvider2.cs} | 4 +- .../System.Runtime.Serialization.Schema.cs | 49 +-- ...System.Runtime.Serialization.Schema.csproj | 7 +- .../Serialization/Schema/CodeExporter.cs | 328 ++++++++------- .../Schema/ContractCodeDomInfo.cs | 4 +- .../Serialization/Schema/DiagnosticUtility.cs | 2 +- .../Serialization/Schema/ExportOptions.cs | 34 -- .../ISerializationCodeDomSurrogateProvider.cs | 21 + .../Schema/{Globals.cs => ImportGlobals.cs} | 8 +- .../Serialization/Schema/ImportOptions.cs | 14 +- .../Serialization/Schema/SchemaHelper.cs | 109 ----- .../Schema/SchemaImportHelper.cs | 125 ++++++ .../Schema/XsdDataContractExporter.cs | 393 ------------------ .../Schema/XsdDataContractImporter.cs | 49 +-- .../ref/System.Runtime.Serialization.Xml.cs | 169 ++++---- .../tests/DataContractSerializer.cs | 8 - 81 files changed, 1057 insertions(+), 1350 deletions(-) delete mode 100644 src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionFeature.cs rename src/libraries/System.Runtime.Serialization.Primitives/src/System/Runtime/Serialization/{ISerializationExtendedSurrogateProvider.cs => ISerializationSurrogateProvider2.cs} (75%) delete mode 100644 src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ExportOptions.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ISerializationCodeDomSurrogateProvider.cs rename src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/{Globals.cs => ImportGlobals.cs} (96%) delete mode 100644 src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaHelper.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaImportHelper.cs delete mode 100644 src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs diff --git a/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj b/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj index 6b5246e7fa01c..63f4b4b250c61 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj +++ b/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj @@ -48,7 +48,6 @@ - diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/AccessorBuilder.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/AccessorBuilder.cs index e6af588406a6d..23f1ea8aeeb70 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/AccessorBuilder.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/AccessorBuilder.cs @@ -8,6 +8,7 @@ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Serialization; +using System.Runtime.Serialization.DataContracts; using System.Text; using System.Threading.Tasks; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs index 4ad42f98f8e3f..f158fa3ba3afc 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs @@ -11,9 +11,9 @@ using System.Threading; using System.Xml; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; -namespace System.Runtime.Serialization +namespace System.Runtime.Serialization.DataContracts { internal sealed class ClassDataContract : DataContract { @@ -108,7 +108,7 @@ public override DataContractDictionary? KnownDataContracts { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get => _helper.KnownDataContracts; - set => _helper.KnownDataContracts = value; + internal set => _helper.KnownDataContracts = value; } public override bool IsISerializable @@ -259,7 +259,7 @@ internal static void CheckAndAddMember(List members, DataMember memb if (!childType.IsEnum && !Globals.TypeOfIXmlSerializable.IsAssignableFrom(childType) && DataContract.GetBuiltInDataContract(childType) == null && childType != Globals.TypeOfDBNull) { - string ns = DataContract.GetStableName(childType).Namespace; + string ns = DataContract.GetXmlName(childType).Namespace; if (ns.Length > 0 && ns != dataContract.Namespace.Value) return dictionary.Add(ns); } @@ -607,14 +607,14 @@ private sealed class ClassDataContractCriticalHelper : DataContract.DataContract internal ClassDataContractCriticalHelper([DynamicallyAccessedMembers(DataContractPreserveMemberTypes)] Type type) : base(type) { - XmlQualifiedName stableName = GetStableNameAndSetHasDataContract(type); + XmlQualifiedName xmlName = GetXmlNameAndSetHasDataContract(type); if (type == Globals.TypeOfDBNull) { - StableName = stableName; + XmlName = xmlName; _members = new List(); XmlDictionary dictionary = new XmlDictionary(2); - Name = dictionary.Add(StableName.Name); - Namespace = dictionary.Add(StableName.Namespace); + Name = dictionary.Add(XmlName.Name); + Namespace = dictionary.Add(XmlName.Namespace); ContractNamespaces = MemberNames = MemberNamespaces = Array.Empty(); EnsureMethodsImported(); return; @@ -662,15 +662,15 @@ internal ClassDataContractCriticalHelper([DynamicallyAccessedMembers(DataContrac if (_isISerializable) { - SetDataContractName(stableName); + SetDataContractName(xmlName); } else { - StableName = stableName; + XmlName = xmlName; ImportDataMembers(); XmlDictionary dictionary = new XmlDictionary(2 + Members.Count); - Name = dictionary.Add(StableName.Name); - Namespace = dictionary.Add(StableName.Namespace); + Name = dictionary.Add(XmlName.Name); + Namespace = dictionary.Add(XmlName.Namespace); int baseMemberCount = 0; int baseContractCount = 0; @@ -711,10 +711,10 @@ internal ClassDataContractCriticalHelper( [DynamicallyAccessedMembers(DataContractPreserveMemberTypes)] Type type, XmlDictionaryString ns, string[] memberNames) : base(type) { - StableName = new XmlQualifiedName(GetStableNameAndSetHasDataContract(type).Name, ns.Value); + XmlName = new XmlQualifiedName(GetXmlNameAndSetHasDataContract(type).Name, ns.Value); ImportDataMembers(); XmlDictionary dictionary = new XmlDictionary(1 + Members.Count); - Name = dictionary.Add(StableName.Name); + Name = dictionary.Add(XmlName.Name); Namespace = ns; ContractNamespaces = new XmlDictionaryString[] { Namespace }; MemberNames = new XmlDictionaryString[Members.Count]; @@ -962,7 +962,7 @@ private void SetIfMembersHaveConflict(List members) List membersInHierarchy = new List(); foreach (DataMember member in members) { - membersInHierarchy.Add(new Member(member, StableName!.Namespace, baseTypeIndex)); + membersInHierarchy.Add(new Member(member, XmlName!.Namespace, baseTypeIndex)); } ClassDataContract? currContract = BaseClassContract; while (currContract != null) @@ -971,7 +971,7 @@ private void SetIfMembersHaveConflict(List members) foreach (DataMember member in currContract.Members!) { - membersInHierarchy.Add(new Member(member, currContract.StableName!.Namespace, baseTypeIndex)); + membersInHierarchy.Add(new Member(member, currContract.XmlName!.Namespace, baseTypeIndex)); } currContract = currContract.BaseClassContract; } @@ -1016,15 +1016,15 @@ private void SetIfMembersHaveConflict(List members) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private XmlQualifiedName GetStableNameAndSetHasDataContract(Type type) + private XmlQualifiedName GetXmlNameAndSetHasDataContract(Type type) { - return DataContract.GetStableName(type, out _hasDataContract); + return DataContract.GetXmlName(type, out _hasDataContract); } /// /// RequiresReview - marked SRR because callers may need to depend on isNonAttributedType for a security decision /// isNonAttributedType must be calculated correctly - /// SetIsNonAttributedType should not be called before GetStableNameAndSetHasDataContract since it + /// SetIsNonAttributedType should not be called before GetXmlNameAndSetHasDataContract since it /// is dependent on the correct calculation of hasDataContract /// Safe - does not let caller influence isNonAttributedType calculation; no harm in leaking value /// @@ -1128,7 +1128,7 @@ internal ClassDataContract? BaseClassContract { _baseContract = value; if (_baseContract != null && IsValueType) - ThrowInvalidDataContractException(SR.Format(SR.ValueTypeCannotHaveBaseType, StableName!.Name, StableName.Namespace, _baseContract.StableName!.Name, _baseContract.StableName.Namespace)); + ThrowInvalidDataContractException(SR.Format(SR.ValueTypeCannotHaveBaseType, XmlName!.Name, XmlName.Namespace, _baseContract.XmlName!.Name, _baseContract.XmlName.Namespace)); } } @@ -1198,6 +1198,7 @@ internal override DataContractDictionary? KnownDataContracts Interlocked.MemoryBarrier(); _isKnownTypeAttributeChecked = true; } + _knownDataContracts ??= new DataContractDictionary(); } } return _knownDataContracts; @@ -1303,12 +1304,12 @@ internal override DataContract BindGenericParameters(DataContract[] paramContrac if (boundContracts != null && boundContracts.TryGetValue(this, out DataContract? boundContract)) return boundContract; - XmlQualifiedName stableName; + XmlQualifiedName xmlName; object[] genericParams; Type boundType; if (type.IsGenericTypeDefinition) { - stableName = StableName; + xmlName = XmlName; genericParams = paramContracts; // NOTE TODO smolloy - this type-binding ('boundType') stuff is new. We did not do this in NetFx. We used to use default constructors and let the @@ -1321,8 +1322,8 @@ internal override DataContract BindGenericParameters(DataContract[] paramContrac } else { - //partial Generic: Construct stable name from its open generic type definition - stableName = DataContract.GetStableName(type.GetGenericTypeDefinition()); + //partial Generic: Construct xml name from its open generic type definition + xmlName = DataContract.GetXmlName(type.GetGenericTypeDefinition()); Type[] paramTypes = type.GetGenericArguments(); genericParams = new object[paramTypes.Length]; for (int i = 0; i < paramTypes.Length; i++) @@ -1343,7 +1344,7 @@ internal override DataContract BindGenericParameters(DataContract[] paramContrac ClassDataContract boundClassContract = new ClassDataContract(boundType); boundContracts ??= new Dictionary(); boundContracts.Add(this, boundClassContract); - boundClassContract.StableName = CreateQualifiedName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(stableName.Name), new GenericNameProvider(DataContract.GetClrTypeFullName(UnderlyingType), genericParams)), stableName.Namespace); + boundClassContract.XmlName = CreateQualifiedName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(xmlName.Name), new GenericNameProvider(DataContract.GetClrTypeFullName(UnderlyingType), genericParams)), xmlName.Namespace); if (BaseClassContract != null) boundClassContract.BaseClassContract = (ClassDataContract)BaseClassContract.BindGenericParameters(paramContracts, boundContracts); boundClassContract.IsISerializable = IsISerializable; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs index 16f055759ca30..201bdc3e93e83 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs @@ -8,6 +8,7 @@ using System.Globalization; using System.Reflection; using System.Reflection.Emit; +using System.Runtime.Serialization.DataContracts; namespace System.Runtime.Serialization { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs index 0a54659ba532a..60c6f7e33af75 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs @@ -12,7 +12,7 @@ using System.Threading; using System.Xml; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization { @@ -74,7 +74,10 @@ internal enum CollectionKind : byte Enumerable, Array, } +} +namespace System.Runtime.Serialization.DataContracts +{ internal sealed class CollectionDataContract : DataContract { internal const string ContractTypeString = nameof(CollectionDataContract); @@ -187,7 +190,7 @@ internal string? ValueName set => _helper.ValueName = value; } - public override bool IsKeyValue(out string? keyName, out string? valueName, out string? itemName) + public override bool IsDictionaryLike([NotNullWhen(true)] out string? keyName, [NotNullWhen(true)] out string? valueName, [NotNullWhen(true)] out string? itemName) { keyName = KeyName; valueName = ValueName; @@ -250,7 +253,7 @@ public override DataContractDictionary? KnownDataContracts { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get => _helper.KnownDataContracts; - set => _helper.KnownDataContracts = value; + internal set => _helper.KnownDataContracts = value; } internal string? InvalidCollectionInSharedContractMessage => _helper.InvalidCollectionInSharedContractMessage; @@ -465,9 +468,9 @@ private void Init(CollectionKind kind, Type? itemType, CollectionDataContractAtt } XmlDictionary dictionary = isDictionary ? new XmlDictionary(5) : new XmlDictionary(3); - Name = dictionary.Add(StableName.Name); - Namespace = dictionary.Add(StableName.Namespace); - _itemName = itemName ?? DataContract.GetStableName(DataContract.UnwrapNullableType(itemType)).Name; + Name = dictionary.Add(XmlName.Name); + Namespace = dictionary.Add(XmlName.Namespace); + _itemName = itemName ?? DataContract.GetXmlName(DataContract.UnwrapNullableType(itemType)).Name; _collectionItemName = dictionary.Add(_itemName); if (isDictionary) { @@ -490,7 +493,7 @@ internal CollectionDataContractCriticalHelper( type = Globals.TypeOfObjectArray; if (type.GetArrayRank() > 1) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.SupportForMultidimensionalArraysNotPresent)); - StableName = DataContract.GetStableName(type); + XmlName = DataContract.GetXmlName(type); Init(CollectionKind.Array, type.GetElementType(), null); } @@ -500,7 +503,7 @@ internal CollectionDataContractCriticalHelper( Type type, CollectionKind kind) : base(type) { - StableName = DataContract.GetStableName(type); + XmlName = DataContract.GetXmlName(type); Init(kind, type.GetElementType(), null); } @@ -513,7 +516,7 @@ internal CollectionDataContractCriticalHelper( { if (type.GetArrayRank() > 1) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.SupportForMultidimensionalArraysNotPresent)); - StableName = CreateQualifiedName(Globals.ArrayPrefix + itemContract.StableName.Name, itemContract.StableName.Namespace); + XmlName = CreateQualifiedName(Globals.ArrayPrefix + itemContract.XmlName.Name, itemContract.XmlName.Namespace); _itemContract = itemContract; Init(CollectionKind.Array, type.GetElementType(), null); } @@ -532,7 +535,7 @@ internal CollectionDataContractCriticalHelper( throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.CollectionMustHaveItemType, GetClrTypeFullName(type)))); CollectionDataContractAttribute? collectionContractAttribute; - StableName = DataContract.GetCollectionStableName(type, itemType, out collectionContractAttribute); + XmlName = DataContract.GetCollectionXmlName(type, itemType, out collectionContractAttribute); Init(kind, itemType, collectionContractAttribute); _getEnumeratorMethod = getEnumeratorMethod; @@ -682,6 +685,7 @@ internal override DataContractDictionary? KnownDataContracts Interlocked.MemoryBarrier(); _isKnownTypeAttributeChecked = true; } + _knownDataContracts ??= new DataContractDictionary(); } } return _knownDataContracts; @@ -1353,11 +1357,11 @@ internal override DataContract BindGenericParameters(DataContract[] paramContrac boundContracts.Add(this, boundCollectionContract); boundCollectionContract.ItemContract = ItemContract.BindGenericParameters(paramContracts, boundContracts); boundCollectionContract.IsItemTypeNullable = !boundCollectionContract.ItemContract.IsValueType; - boundCollectionContract.ItemName = ItemNameSetExplicit ? ItemName : boundCollectionContract.ItemContract.StableName.Name; + boundCollectionContract.ItemName = ItemNameSetExplicit ? ItemName : boundCollectionContract.ItemContract.XmlName.Name; boundCollectionContract.KeyName = KeyName; boundCollectionContract.ValueName = ValueName; - boundCollectionContract.StableName = CreateQualifiedName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(StableName.Name), new GenericNameProvider(DataContract.GetClrTypeFullName(UnderlyingType), paramContracts)), - IsCollectionDataContract(UnderlyingType) ? StableName.Namespace : DataContract.GetCollectionNamespace(boundCollectionContract.ItemContract.StableName.Namespace)); + boundCollectionContract.XmlName = CreateQualifiedName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(XmlName.Name), new GenericNameProvider(DataContract.GetClrTypeFullName(UnderlyingType), paramContracts)), + IsCollectionDataContract(UnderlyingType) ? XmlName.Namespace : DataContract.GetCollectionNamespace(boundCollectionContract.ItemContract.XmlName.Namespace)); return boundCollectionContract; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs index c63bb71000f63..31134fbd87357 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs @@ -11,12 +11,13 @@ using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.Serialization.DataContracts; using System.Text; using System.Xml; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; -namespace System.Runtime.Serialization +namespace System.Runtime.Serialization.DataContracts { public abstract class DataContract { @@ -47,7 +48,7 @@ internal DataContract(DataContractCriticalHelper helper) internal MethodInfo? ParseMethod => _helper.ParseMethod; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public static DataContract GetDataContract(Type type) + internal static DataContract GetDataContract(Type type) { return GetDataContract(type.TypeHandle, type); } @@ -134,15 +135,6 @@ internal static XmlDictionaryString GetClrTypeString(string key) return DataContractCriticalHelper.GetClrTypeString(key); } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public static Type GetSurrogateType(ISerializationSurrogateProvider surrogateProvider, Type type) - { - if (surrogateProvider != null) - return DataContractSurrogateCaller.GetDataContractType(surrogateProvider, type); - - return type; - } - [DoesNotReturn] internal static void ThrowInvalidDataContractException(string? message, Type? type) { @@ -195,10 +187,10 @@ public virtual bool IsReference internal set => _helper.IsReference = value; } - public virtual XmlQualifiedName StableName + public virtual XmlQualifiedName XmlName { - get => _helper.StableName; - internal set => _helper.StableName = value; + get => _helper.XmlName; + internal set => _helper.XmlName = value; } public virtual DataContract? BaseContract @@ -218,7 +210,7 @@ public virtual DataContractDictionary? KnownDataContracts { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get => _helper.KnownDataContracts; - set => _helper.KnownDataContracts = value; + internal set => _helper.KnownDataContracts = value; } public virtual bool IsISerializable @@ -253,7 +245,7 @@ public virtual XmlDictionaryString? TopLevelElementNamespace internal virtual bool IsPrimitive => false; - public virtual bool IsKeyValue(out string? keyName, out string? valueName, out string? itemName) + public virtual bool IsDictionaryLike([NotNullWhen(true)] out string? keyName, [NotNullWhen(true)] out string? valueName, [NotNullWhen(true)] out string? itemName) { keyName = valueName = itemName = null; return false; @@ -315,7 +307,7 @@ internal class DataContractCriticalHelper private Type? _originalUnderlyingType; private bool _isValueType; private GenericInfo? _genericInfo; - private XmlQualifiedName _stableName = null!; // StableName is always set in concrete ctors set except for the "invalid" CollectionDataContract + private XmlQualifiedName _xmlName = null!; // XmlName is always set in concrete ctors set except for the "invalid" CollectionDataContract private XmlDictionaryString _name = null!; // Name is always set in concrete ctors set except for the "invalid" CollectionDataContract private XmlDictionaryString _ns = null!; // Namespace is always set in concrete ctors set except for the "invalid" CollectionDataContract @@ -482,10 +474,10 @@ private static DataContract CreateDataContract(Type type) if (type != originalType) { var originalDataContract = new ClassDataContract(originalType); - if (dataContract.StableName != originalDataContract.StableName) + if (dataContract.XmlName != originalDataContract.XmlName) { - // for non-DC types, type adapters will not have the same stable name (contract name). - dataContract.StableName = originalDataContract.StableName; + // for non-DC types, type adapters will not have the same xml name (contract name). + dataContract.XmlName = originalDataContract.XmlName; } } } @@ -1012,10 +1004,10 @@ internal bool IsValueType set => _isValueType = value; } - internal XmlQualifiedName StableName + internal XmlQualifiedName XmlName { - get => _stableName; - set => _stableName = value; + get => _xmlName; + set => _xmlName = value; } internal GenericInfo? GenericInfo @@ -1094,19 +1086,19 @@ internal MethodInfo? ParseMethod } } - internal void SetDataContractName(XmlQualifiedName stableName) + internal void SetDataContractName(XmlQualifiedName xmlName) { XmlDictionary dictionary = new XmlDictionary(2); - Name = dictionary.Add(stableName.Name); - Namespace = dictionary.Add(stableName.Namespace); - StableName = stableName; + Name = dictionary.Add(xmlName.Name); + Namespace = dictionary.Add(xmlName.Namespace); + XmlName = xmlName; } internal void SetDataContractName(XmlDictionaryString name, XmlDictionaryString ns) { Name = name; Namespace = ns; - StableName = CreateQualifiedName(name.Value, ns.Value); + XmlName = CreateQualifiedName(name.Value, ns.Value); } [DoesNotReturn] @@ -1117,7 +1109,7 @@ internal void ThrowInvalidDataContractException(string message) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public static bool IsTypeSerializable(Type type) + internal static bool IsTypeSerializable(Type type) { return IsTypeSerializable(type, null); } @@ -1220,7 +1212,7 @@ private static bool IsAsciiLocalName(string localName) return true; } - public static string EncodeLocalName(string localName) + internal static string EncodeLocalName(string localName) { if (IsAsciiLocalName(localName)) return localName; @@ -1245,22 +1237,22 @@ internal static bool IsValidNCName(string name) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public static XmlQualifiedName GetStableName(Type type) + public static XmlQualifiedName GetXmlName(Type type) { - return GetStableName(type, out _); + return GetXmlName(type, out _); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static XmlQualifiedName GetStableName(Type type, out bool hasDataContract) + internal static XmlQualifiedName GetXmlName(Type type, out bool hasDataContract) { - return GetStableName(type, new HashSet(), out hasDataContract); + return GetXmlName(type, new HashSet(), out hasDataContract); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static XmlQualifiedName GetStableName(Type type, HashSet previousCollectionTypes, out bool hasDataContract) + internal static XmlQualifiedName GetXmlName(Type type, HashSet previousCollectionTypes, out bool hasDataContract) { type = UnwrapRedundantNullableType(type); - if (TryGetBuiltInXmlAndArrayTypeStableName(type, previousCollectionTypes, out XmlQualifiedName? stableName)) + if (TryGetBuiltInXmlAndArrayTypeXmlName(type, previousCollectionTypes, out XmlQualifiedName? xmlName)) { hasDataContract = false; } @@ -1268,21 +1260,21 @@ internal static XmlQualifiedName GetStableName(Type type, HashSet previous { if (TryGetDCAttribute(type, out DataContractAttribute? dataContractAttribute)) { - stableName = GetDCTypeStableName(type, dataContractAttribute); + xmlName = GetDCTypeXmlName(type, dataContractAttribute); hasDataContract = true; } else { - stableName = GetNonDCTypeStableName(type, previousCollectionTypes); + xmlName = GetNonDCTypeXmlName(type, previousCollectionTypes); hasDataContract = false; } } - return stableName; + return xmlName; } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private static XmlQualifiedName GetDCTypeStableName(Type type, DataContractAttribute dataContractAttribute) + private static XmlQualifiedName GetDCTypeXmlName(Type type, DataContractAttribute dataContractAttribute) { string? name, ns; if (dataContractAttribute.IsNameSetExplicitly) @@ -1295,7 +1287,7 @@ private static XmlQualifiedName GetDCTypeStableName(Type type, DataContractAttri name = DataContract.EncodeLocalName(name); } else - name = GetDefaultStableLocalName(type); + name = GetDefaultXmlLocalName(type); if (dataContractAttribute.IsNamespaceSetExplicitly) { @@ -1311,16 +1303,16 @@ private static XmlQualifiedName GetDCTypeStableName(Type type, DataContractAttri } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private static XmlQualifiedName GetNonDCTypeStableName(Type type, HashSet previousCollectionTypes) + private static XmlQualifiedName GetNonDCTypeXmlName(Type type, HashSet previousCollectionTypes) { string? name, ns; if (CollectionDataContract.IsCollection(type, out Type? itemType)) { ValidatePreviousCollectionTypes(type, itemType, previousCollectionTypes); - return GetCollectionStableName(type, itemType, previousCollectionTypes, out _); + return GetCollectionXmlName(type, itemType, previousCollectionTypes, out _); } - name = GetDefaultStableLocalName(type); + name = GetDefaultXmlLocalName(type); // ensures that ContractNamespaceAttribute is honored when used with non-attributed types if (ClassDataContract.IsNonAttributedTypeValidForSerialization(type)) @@ -1329,33 +1321,33 @@ private static XmlQualifiedName GetNonDCTypeStableName(Type type, HashSet } else { - ns = GetDefaultStableNamespace(type); + ns = GetDefaultXmlNamespace(type); } return CreateQualifiedName(name, ns); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private static bool TryGetBuiltInXmlAndArrayTypeStableName(Type type, HashSet previousCollectionTypes, [NotNullWhen(true)] out XmlQualifiedName? stableName) + private static bool TryGetBuiltInXmlAndArrayTypeXmlName(Type type, HashSet previousCollectionTypes, [NotNullWhen(true)] out XmlQualifiedName? xmlName) { - stableName = null; + xmlName = null; DataContract? builtInContract = GetBuiltInDataContract(type); if (builtInContract != null) { - stableName = builtInContract.StableName; + xmlName = builtInContract.XmlName; } else if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type)) { - SchemaExporter.GetXmlTypeInfo(type, out XmlQualifiedName xmlTypeStableName, out _, out _); - stableName = xmlTypeStableName; + SchemaExporter.GetXmlTypeInfo(type, out XmlQualifiedName xmlTypeName, out _, out _); + xmlName = xmlTypeName; } else if (type.IsArray) { Type itemType = type.GetElementType()!; ValidatePreviousCollectionTypes(type, itemType, previousCollectionTypes); - stableName = GetCollectionStableName(type, itemType, previousCollectionTypes, out _); + xmlName = GetCollectionXmlName(type, itemType, previousCollectionTypes, out _); } - return stableName != null; + return xmlName != null; } internal static bool TryGetDCAttribute(Type type, [NotNullWhen(true)] out DataContractAttribute? dataContractAttribute) @@ -1376,13 +1368,13 @@ internal static bool TryGetDCAttribute(Type type, [NotNullWhen(true)] out DataCo } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static XmlQualifiedName GetCollectionStableName(Type type, Type itemType, out CollectionDataContractAttribute? collectionContractAttribute) + internal static XmlQualifiedName GetCollectionXmlName(Type type, Type itemType, out CollectionDataContractAttribute? collectionContractAttribute) { - return GetCollectionStableName(type, itemType, new HashSet(), out collectionContractAttribute); + return GetCollectionXmlName(type, itemType, new HashSet(), out collectionContractAttribute); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static XmlQualifiedName GetCollectionStableName(Type type, Type itemType, HashSet previousCollectionTypes, out CollectionDataContractAttribute? collectionContractAttribute) + internal static XmlQualifiedName GetCollectionXmlName(Type type, Type itemType, HashSet previousCollectionTypes, out CollectionDataContractAttribute? collectionContractAttribute) { string? name, ns; object[] collectionContractAttributes = type.GetCustomAttributes(Globals.TypeOfCollectionDataContractAttribute, false).ToArray(); @@ -1403,7 +1395,7 @@ internal static XmlQualifiedName GetCollectionStableName(Type type, Type itemTyp name = DataContract.EncodeLocalName(name); } else - name = GetDefaultStableLocalName(type); + name = GetDefaultXmlLocalName(type); if (collectionContractAttribute.IsNamespaceSetExplicitly) { @@ -1419,9 +1411,9 @@ internal static XmlQualifiedName GetCollectionStableName(Type type, Type itemTyp { collectionContractAttribute = null; string arrayOfPrefix = Globals.ArrayPrefix + GetArrayPrefix(ref itemType); - XmlQualifiedName elementStableName = GetStableName(itemType, previousCollectionTypes, out _); - name = arrayOfPrefix + elementStableName.Name; - ns = GetCollectionNamespace(elementStableName.Namespace); + XmlQualifiedName elementXmlName = GetXmlName(itemType, previousCollectionTypes, out _); + name = arrayOfPrefix + elementXmlName.Name; + ns = GetCollectionNamespace(elementXmlName.Namespace); } return CreateQualifiedName(name, ns); } @@ -1451,14 +1443,14 @@ public virtual XmlQualifiedName GetArrayTypeName(bool isNullable) XmlQualifiedName itemName; if (IsValueType && isNullable) { - GenericInfo genericInfo = new GenericInfo(DataContract.GetStableName(Globals.TypeOfNullable), Globals.TypeOfNullable.FullName!); - genericInfo.Add(new GenericInfo(StableName, null)); + GenericInfo genericInfo = new GenericInfo(DataContract.GetXmlName(Globals.TypeOfNullable), Globals.TypeOfNullable.FullName!); + genericInfo.Add(new GenericInfo(XmlName, null)); genericInfo.AddToLevel(0, 1); - itemName = genericInfo.GetExpandedStableName(); + itemName = genericInfo.GetExpandedXmlName(); } else { - itemName = StableName; + itemName = XmlName; } string ns = GetCollectionNamespace(itemName.Namespace); string name = Globals.ArrayPrefix + itemName.Name; @@ -1466,13 +1458,13 @@ public virtual XmlQualifiedName GetArrayTypeName(bool isNullable) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static XmlQualifiedName GetDefaultStableName(Type type) + internal static XmlQualifiedName GetDefaultXmlName(Type type) { - return CreateQualifiedName(GetDefaultStableLocalName(type), GetDefaultStableNamespace(type)); + return CreateQualifiedName(GetDefaultXmlLocalName(type), GetDefaultXmlNamespace(type)); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private static string GetDefaultStableLocalName(Type type) + private static string GetDefaultXmlLocalName(Type type) { if (type.IsGenericParameter) return "{" + type.GenericParameterPosition + "}"; @@ -1509,7 +1501,7 @@ private static string GetDefaultStableLocalName(Type type) localName.Append('{').Append(i).Append('}'); else { - XmlQualifiedName qname = DataContract.GetStableName(genParam); + XmlQualifiedName qname = DataContract.GetXmlName(genParam); localName.Append(qname.Name); namespaces.Append(' ').Append(qname.Namespace); if (parametersFromBuiltInNamespaces) @@ -1538,7 +1530,7 @@ private static string GetDefaultDataContractNamespace(Type type) if (ns == null) { - ns = GetDefaultStableNamespace(type); + ns = GetDefaultXmlNamespace(type); } else { @@ -1585,11 +1577,11 @@ internal static bool IsBuiltInNamespace(string ns) return (ns == Globals.SchemaNamespace || ns == Globals.SerializationNamespace); } - internal static string GetDefaultStableNamespace(Type type) + internal static string GetDefaultXmlNamespace(Type type) { if (type.IsGenericParameter) return "{ns}"; - return GetDefaultStableNamespace(type.Namespace); + return GetDefaultXmlNamespace(type.Namespace); } internal static XmlQualifiedName CreateQualifiedName(string localName, string ns) @@ -1597,27 +1589,27 @@ internal static XmlQualifiedName CreateQualifiedName(string localName, string ns return new XmlQualifiedName(localName, GetNamespace(ns)); } - internal static string GetDefaultStableNamespace(string? clrNs) + internal static string GetDefaultXmlNamespace(string? clrNs) { return new Uri(Globals.DataContractXsdBaseNamespaceUri, clrNs ?? string.Empty).AbsoluteUri; } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static void GetDefaultStableName(string fullTypeName, out string localName, out string ns) + internal static void GetDefaultXmlName(string fullTypeName, out string localName, out string ns) { CodeTypeReference typeReference = new CodeTypeReference(fullTypeName); - GetDefaultStableName(typeReference, out localName, out ns); + GetDefaultName(typeReference, out localName, out ns); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private static void GetDefaultStableName(CodeTypeReference typeReference, out string localName, out string ns) + private static void GetDefaultName(CodeTypeReference typeReference, out string localName, out string ns) { string fullTypeName = typeReference.BaseType; DataContract? dataContract = GetBuiltInDataContract(fullTypeName); if (dataContract != null) { - localName = dataContract.StableName.Name; - ns = dataContract.StableName.Namespace; + localName = dataContract.XmlName.Name; + ns = dataContract.XmlName.Namespace; return; } @@ -1630,7 +1622,7 @@ private static void GetDefaultStableName(CodeTypeReference typeReference, out st List nestedParamCounts = GetDataContractNameForGenericName(localName, localNameBuilder); foreach (CodeTypeReference typeArg in typeReference.TypeArguments) { - GetDefaultStableName(typeArg, out string typeArgName, out string typeArgNs); + GetDefaultName(typeArg, out string typeArgName, out string typeArgNs); localNameBuilder.Append(typeArgName); argNamespacesBuilder.Append(' ').Append(typeArgNs); if (parametersFromBuiltInNamespaces) @@ -1653,7 +1645,7 @@ private static void GetDefaultStableName(CodeTypeReference typeReference, out st } localName = DataContract.EncodeLocalName(localName); - ns = GetDefaultStableNamespace(ns); + ns = GetDefaultXmlNamespace(ns); } private static void CheckExplicitDataContractNamespaceUri(string dataContractNs, Type type) @@ -2018,7 +2010,7 @@ private static void ImportKnownTypeAttributes(Type? type, Dictionary DataContract itemDataContract = DataContract.GetDataContract(Globals.TypeOfKeyValuePair.MakeGenericType(collectionDataContract.ItemType.GetGenericArguments())); knownDataContracts ??= new DataContractDictionary(); - knownDataContracts.TryAdd(itemDataContract.StableName, itemDataContract); + knownDataContracts.TryAdd(itemDataContract.XmlName, itemDataContract); } } catch (InvalidDataContractException) @@ -2042,15 +2034,15 @@ internal static void CheckAndAdd(Type type, Dictionary typesChecked, { nameToDataContractTable = new DataContractDictionary(); } - else if (nameToDataContractTable.TryGetValue(dataContract.StableName, out DataContract? alreadyExistingContract)) + else if (nameToDataContractTable.TryGetValue(dataContract.XmlName, out DataContract? alreadyExistingContract)) { // NOTE TODO smolloy - The existing contract type was used as-is in NetFx. The call to get the appropriate adapter type was added in CoreFx with https://github.com/dotnet/runtime/commit/50c0a70c52fa66fafa1227be552ccdab5e4cf8e4 // Don't throw duplicate if its a KeyValuePair as it could have been added by Dictionary if (DataContractCriticalHelper.GetDataContractAdapterType(alreadyExistingContract.UnderlyingType) != DataContractCriticalHelper.GetDataContractAdapterType(type)) - throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.DupContractInKnownTypes, type, alreadyExistingContract.UnderlyingType, dataContract.StableName.Namespace, dataContract.StableName.Name))); + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.DupContractInKnownTypes, type, alreadyExistingContract.UnderlyingType, dataContract.XmlName.Namespace, dataContract.XmlName.Name))); return; } - nameToDataContractTable.Add(dataContract.StableName, dataContract); + nameToDataContractTable.Add(dataContract.XmlName, dataContract); ImportKnownTypeAttributes(type, typesChecked, ref nameToDataContractTable); } @@ -2069,7 +2061,7 @@ internal virtual bool Equals(object? other, HashSet checked { if (other is DataContract dataContract) { - return (StableName.Name == dataContract.StableName.Name && StableName.Namespace == dataContract.StableName.Namespace && IsReference == dataContract.IsReference); + return (XmlName.Name == dataContract.XmlName.Name && XmlName.Namespace == dataContract.XmlName.Namespace && IsReference == dataContract.IsReference); } return false; } @@ -2237,7 +2229,10 @@ internal static string SanitizeTypeName(string typeName) return typeName.Replace('.', '_'); } } +} +namespace System.Runtime.Serialization +{ internal interface IGenericNameProvider { int GetParameterCount(); @@ -2287,7 +2282,7 @@ public IList GetNestedParameterCounts() [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] public string GetParameterName(int paramIndex) { - return GetStableName(paramIndex).Name; + return GetXmlName(paramIndex).Name; } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -2295,7 +2290,7 @@ public string GetNamespaces() { StringBuilder namespaces = new StringBuilder(); for (int j = 0; j < GetParameterCount(); j++) - namespaces.Append(' ').Append(GetStableName(j).Namespace); + namespaces.Append(' ').Append(GetXmlName(j).Namespace); return namespaces.ToString(); } @@ -2313,7 +2308,7 @@ public bool ParametersFromBuiltInNamespaces for (int j = 0; j < GetParameterCount(); j++) { if (parametersFromBuiltInNamespaces) - parametersFromBuiltInNamespaces = DataContract.IsBuiltInNamespace(GetStableName(j).Namespace); + parametersFromBuiltInNamespaces = DataContract.IsBuiltInNamespace(GetXmlName(j).Namespace); else break; } @@ -2322,7 +2317,7 @@ public bool ParametersFromBuiltInNamespaces } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private XmlQualifiedName GetStableName(int i) + private XmlQualifiedName GetXmlName(int i) { object o = _genericParams[i]; XmlQualifiedName? qname = o as XmlQualifiedName; @@ -2330,9 +2325,9 @@ private XmlQualifiedName GetStableName(int i) { Type? paramType = o as Type; if (paramType != null) - _genericParams[i] = qname = DataContract.GetStableName(paramType); + _genericParams[i] = qname = DataContract.GetXmlName(paramType); else - _genericParams[i] = qname = ((DataContract)o).StableName; + _genericParams[i] = qname = ((DataContract)o).XmlName; } return qname; } @@ -2341,27 +2336,27 @@ private XmlQualifiedName GetStableName(int i) internal sealed class GenericInfo : IGenericNameProvider { private string? _genericTypeName; - private XmlQualifiedName _stableName; + private XmlQualifiedName _xmlName; private List? _paramGenericInfos; private List _nestedParamCounts; - internal GenericInfo(XmlQualifiedName stableName, string? genericTypeName) + internal GenericInfo(XmlQualifiedName xmlName, string? genericTypeName) { - _stableName = stableName; + _xmlName = xmlName; _genericTypeName = genericTypeName; _nestedParamCounts = new List(); _nestedParamCounts.Add(0); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public XmlQualifiedName GetExpandedStableName() + public XmlQualifiedName GetExpandedXmlName() { if (_paramGenericInfos == null) - return _stableName; - return new XmlQualifiedName(DataContract.EncodeLocalName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(_stableName.Name), this)), _stableName.Namespace); + return _xmlName; + return new XmlQualifiedName(DataContract.EncodeLocalName(DataContract.ExpandGenericParameters(XmlConvert.DecodeName(_xmlName.Name), this)), _xmlName.Namespace); } - public XmlQualifiedName StableName => _stableName; + public XmlQualifiedName XmlName => _xmlName; public IList? Parameters => _paramGenericInfos; @@ -2385,9 +2380,9 @@ internal void AddToLevel(int level, int count) _nestedParamCounts[level] = _nestedParamCounts[level] + count; } - internal string GetStableNamespace() + internal string GetXmlNamespace() { - return _stableName.Namespace; + return _xmlName.Namespace; } int IGenericNameProvider.GetParameterCount() @@ -2404,7 +2399,7 @@ IList IGenericNameProvider.GetNestedParameterCounts() string IGenericNameProvider.GetParameterName(int paramIndex) { Debug.Assert(_paramGenericInfos != null); - return _paramGenericInfos[paramIndex].GetExpandedStableName().Name; + return _paramGenericInfos[paramIndex].GetExpandedXmlName().Name; } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -2415,7 +2410,7 @@ string IGenericNameProvider.GetNamespaces() StringBuilder namespaces = new StringBuilder(); for (int j = 0; j < _paramGenericInfos.Count; j++) - namespaces.Append(' ').Append(_paramGenericInfos[j].GetStableNamespace()); + namespaces.Append(' ').Append(_paramGenericInfos[j].GetXmlNamespace()); return namespaces.ToString(); } @@ -2437,7 +2432,7 @@ bool IGenericNameProvider.ParametersFromBuiltInNamespaces for (int j = 0; j < _paramGenericInfos.Count; j++) { if (parametersFromBuiltInNamespaces) - parametersFromBuiltInNamespaces = DataContract.IsBuiltInNamespace(_paramGenericInfos[j].GetStableNamespace()); + parametersFromBuiltInNamespaces = DataContract.IsBuiltInNamespace(_paramGenericInfos[j].GetXmlNamespace()); else break; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractResolver.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractResolver.cs index 2b9345dc2c5f2..6983923059fb4 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractResolver.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractResolver.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization.DataContracts; using System.Xml; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs index c0d6cfec922d8..6549e9d46e333 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs @@ -6,9 +6,10 @@ using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; +using System.Runtime.Serialization.DataContracts; using System.Xml; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs index 4b0e82695d13f..02ea2cb54821f 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs @@ -1,34 +1,34 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Xml; using System.Collections; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Text; +using System.Xml; using System.Xml.Schema; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; -namespace System.Runtime.Serialization +namespace System.Runtime.Serialization.DataContracts { public sealed class DataContractSet { private DataContractDictionary? _contracts; private Dictionary? _processedContracts; private readonly ISerializationSurrogateProvider? _surrogateProvider; - private readonly ISerializationExtendedSurrogateProvider? _extendedSurrogateProvider; + private readonly ISerializationSurrogateProvider2? _extendedSurrogateProvider; private Hashtable? _surrogateData; private DataContractDictionary? _knownTypesForObject; - private readonly ICollection? _referencedTypes; - private readonly ICollection? _referencedCollectionTypes; + private readonly List? _referencedTypes; + private readonly List? _referencedCollectionTypes; - public DataContractSet(ISerializationSurrogateProvider? dataContractSurrogate, ICollection? referencedTypes, ICollection? referencedCollectionTypes) + public DataContractSet(ISerializationSurrogateProvider? dataContractSurrogate, IEnumerable? referencedTypes, IEnumerable? referencedCollectionTypes) { - _referencedTypes = referencedTypes; - _referencedCollectionTypes = referencedCollectionTypes; _surrogateProvider = dataContractSurrogate; - _extendedSurrogateProvider = dataContractSurrogate as ISerializationExtendedSurrogateProvider; + _extendedSurrogateProvider = dataContractSurrogate as ISerializationSurrogateProvider2; + _referencedTypes = referencedTypes != null ? new List(referencedTypes) : null; + _referencedCollectionTypes = referencedCollectionTypes != null ? new List(referencedCollectionTypes) : null; } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -67,25 +67,24 @@ public DataContractDictionary? KnownTypesForObject get => _knownTypesForObject; internal set => _knownTypesForObject = value; } + internal static void EnsureTypeNotGeneric(Type type) + { + if (type.ContainsGenericParameters) + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericTypeNotExportable, type))); + } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public void Add(Type type) + internal void Add(Type type) { DataContract dataContract = GetDataContract(type); EnsureTypeNotGeneric(dataContract.UnderlyingType); Add(dataContract); } - internal static void EnsureTypeNotGeneric(Type type) - { - if (type.ContainsGenericParameters) - throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericTypeNotExportable, type))); - } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private void Add(DataContract dataContract) { - Add(dataContract.StableName, dataContract); + Add(dataContract.XmlName, dataContract); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -105,11 +104,11 @@ internal void InternalAdd(XmlQualifiedName name, DataContract dataContract) if (!dataContractInSet.Equals(dataContract)) { if (dataContract.UnderlyingType == null || dataContractInSet.UnderlyingType == null) - throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.DupContractInDataContractSet, dataContract.StableName.Name, dataContract.StableName.Namespace))); + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.DupContractInDataContractSet, dataContract.XmlName.Name, dataContract.XmlName.Namespace))); else { bool typeNamesEqual = (DataContract.GetClrTypeFullName(dataContract.UnderlyingType) == DataContract.GetClrTypeFullName(dataContractInSet.UnderlyingType)); - throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.DupTypeContractInDataContractSet, (typeNamesEqual ? dataContract.UnderlyingType.AssemblyQualifiedName : DataContract.GetClrTypeFullName(dataContract.UnderlyingType)), (typeNamesEqual ? dataContractInSet.UnderlyingType.AssemblyQualifiedName : DataContract.GetClrTypeFullName(dataContractInSet.UnderlyingType)), dataContract.StableName.Name, dataContract.StableName.Namespace))); + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.DupTypeContractInDataContractSet, (typeNamesEqual ? dataContract.UnderlyingType.AssemblyQualifiedName : DataContract.GetClrTypeFullName(dataContract.UnderlyingType)), (typeNamesEqual ? dataContractInSet.UnderlyingType.AssemblyQualifiedName : DataContract.GetClrTypeFullName(dataContractInSet.UnderlyingType)), dataContract.XmlName.Name, dataContract.XmlName.Namespace))); } } } @@ -137,7 +136,7 @@ private void AddClassDataContract(ClassDataContract classDataContract) { if (classDataContract.BaseClassContract != null) { - Add(classDataContract.BaseClassContract.StableName, classDataContract.BaseClassContract); + Add(classDataContract.BaseClassContract.XmlName, classDataContract.BaseClassContract); } if (!classDataContract.IsISerializable) { @@ -158,7 +157,7 @@ private void AddClassDataContract(ClassDataContract classDataContract) SurrogateData.Add(dataMember, customData); } - Add(memberDataContract.StableName, memberDataContract); + Add(memberDataContract.XmlName, memberDataContract); } } } @@ -177,7 +176,7 @@ private void AddCollectionDataContract(CollectionDataContract collectionDataCont { DataContract itemContract = GetItemTypeDataContract(collectionDataContract); if (itemContract != null) - Add(itemContract.StableName, itemContract); + Add(itemContract.XmlName, itemContract); } AddKnownDataContracts(collectionDataContract.KnownDataContracts); } @@ -191,7 +190,7 @@ private void AddXmlDataContract(XmlDataContract xmlDataContract) [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private void AddKnownDataContracts(DataContractDictionary? knownDataContracts) { - if (knownDataContracts != null) + if (knownDataContracts?.Count > 0) { foreach (DataContract knownDataContract in knownDataContracts.Values) { @@ -201,14 +200,14 @@ private void AddKnownDataContracts(DataContractDictionary? knownDataContracts) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal XmlQualifiedName GetStableName(Type clrType) + internal XmlQualifiedName GetXmlName(Type clrType) { if (_surrogateProvider != null) { Type dcType = DataContractSurrogateCaller.GetDataContractType(_surrogateProvider, clrType); - return DataContract.GetStableName(dcType); + return DataContract.GetXmlName(dcType); } - return DataContract.GetStableName(clrType); + return DataContract.GetXmlName(clrType); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -300,7 +299,7 @@ private Dictionary GetReferencedTypes() _referencedTypesDictionary = new Dictionary(); //Always include Nullable as referenced type //Do not allow surrogating Nullable - _referencedTypesDictionary.Add(DataContract.GetStableName(Globals.TypeOfNullable), Globals.TypeOfNullable); + _referencedTypesDictionary.Add(DataContract.GetXmlName(Globals.TypeOfNullable), Globals.TypeOfNullable); if (_referencedTypes != null) { foreach (Type type in _referencedTypes) @@ -330,7 +329,7 @@ private Dictionary GetReferencedCollectionTypes() AddReferencedType(_referencedCollectionTypesDictionary, type); } } - XmlQualifiedName genericDictionaryName = DataContract.GetStableName(Globals.TypeOfDictionaryGeneric); + XmlQualifiedName genericDictionaryName = DataContract.GetXmlName(Globals.TypeOfDictionaryGeneric); if (!_referencedCollectionTypesDictionary.ContainsKey(genericDictionaryName) && GetReferencedTypes().ContainsKey(genericDictionaryName)) AddReferencedType(_referencedCollectionTypesDictionary, Globals.TypeOfDictionaryGeneric); } @@ -342,33 +341,33 @@ private void AddReferencedType(Dictionary referencedTy { if (IsTypeReferenceable(type)) { - XmlQualifiedName stableName; + XmlQualifiedName xmlName; try { - stableName = GetStableName(type); + xmlName = GetXmlName(type); } catch (InvalidDataContractException) { - // Type not referenceable if we can't get a stable name. + // Type not referenceable if we can't get a xml name. return; } catch (InvalidOperationException) { - // Type not referenceable if we can't get a stable name. + // Type not referenceable if we can't get a xml name. return; } - if (referencedTypes.TryGetValue(stableName, out object? value)) + if (referencedTypes.TryGetValue(xmlName, out object? value)) { if (value is Type referencedType) { if (referencedType != type) { - referencedTypes.Remove(stableName); + referencedTypes.Remove(xmlName); List types = new List(); types.Add(referencedType); types.Add(type); - referencedTypes.Add(stableName, types); + referencedTypes.Add(xmlName, types); } } else @@ -379,7 +378,7 @@ private void AddReferencedType(Dictionary referencedTy } } else - referencedTypes.Add(stableName, type); + referencedTypes.Add(xmlName, type); } } @@ -406,9 +405,9 @@ private static bool IsTypeReferenceable(Type type) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public Type? GetReferencedType(XmlQualifiedName stableName, DataContract dataContract, out DataContract? referencedContract, out object[]? genericParameters, bool? supportGenericTypes = null) + public Type? GetReferencedType(XmlQualifiedName xmlName, DataContract dataContract, out DataContract? referencedContract, out object[]? genericParameters, bool? supportGenericTypes = null) { - Type? type = GetReferencedTypeInternal(stableName, dataContract); + Type? type = GetReferencedTypeInternal(xmlName, dataContract); referencedContract = null; genericParameters = null; @@ -421,9 +420,9 @@ private static bool IsTypeReferenceable(Type type) if (dataContract.GenericInfo == null) return null; - XmlQualifiedName genericStableName = dataContract.GenericInfo.GetExpandedStableName(); - if (genericStableName != dataContract.StableName) - throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericTypeNameMismatch, dataContract.StableName.Name, dataContract.StableName.Namespace, genericStableName.Name, genericStableName.Namespace))); + XmlQualifiedName genericXmlName = dataContract.GenericInfo.GetExpandedXmlName(); + if (genericXmlName != dataContract.XmlName) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericTypeNameMismatch, dataContract.XmlName.Name, dataContract.XmlName.Namespace, genericXmlName.Name, genericXmlName.Namespace))); // This check originally came "here" in the old code. Its tempting to move it up with the GenericInfo check. if (!supportGenericTypes.Value) @@ -439,14 +438,14 @@ private static bool IsTypeReferenceable(Type type) genericParameters = null; referencedContract = null; - Type? type = GetReferencedTypeInternal(genInfo.StableName, null); + Type? type = GetReferencedTypeInternal(genInfo.XmlName, null); if (type == null) { if (genInfo.Parameters != null) return null; - referencedContract = GetDataContract(genInfo.StableName); + referencedContract = GetDataContract(genInfo.XmlName); if (referencedContract != null && referencedContract.GenericInfo != null) referencedContract = null; @@ -463,8 +462,8 @@ private static bool IsTypeReferenceable(Type type) for (int i = 0; i < genInfo.Parameters.Count; i++) { GenericInfo paramInfo = genInfo.Parameters[i]; - XmlQualifiedName paramStableName = paramInfo.GetExpandedStableName(); - DataContract? paramContract = GetDataContract(paramStableName); + XmlQualifiedName paramXmlName = paramInfo.GetExpandedXmlName(); + DataContract? paramContract = GetDataContract(paramXmlName); if (paramContract != null) { @@ -495,15 +494,15 @@ private static bool IsTypeReferenceable(Type type) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private Type? GetReferencedTypeInternal(XmlQualifiedName stableName, DataContract? dataContract) + private Type? GetReferencedTypeInternal(XmlQualifiedName xmlName, DataContract? dataContract) { Type? type; if (dataContract == null) { - if (TryGetReferencedCollectionType(stableName, null, out type)) + if (TryGetReferencedCollectionType(xmlName, null, out type)) return type; - if (TryGetReferencedType(stableName, null, out type)) + if (TryGetReferencedType(xmlName, null, out type)) { // enforce that collection types only be specified via ReferencedCollectionTypes if (CollectionDataContract.IsCollection(type)) @@ -514,37 +513,37 @@ private static bool IsTypeReferenceable(Type type) } else if (dataContract is CollectionDataContract) { - if (TryGetReferencedCollectionType(stableName, dataContract, out type)) + if (TryGetReferencedCollectionType(xmlName, dataContract, out type)) return type; } else { if (dataContract is XmlDataContract xmlDataContract && xmlDataContract.IsAnonymous) - stableName = SchemaImporter.ImportActualType(xmlDataContract.XsdType?.Annotation, stableName, dataContract.StableName); + xmlName = SchemaImporter.ImportActualType(xmlDataContract.XsdType?.Annotation, xmlName, dataContract.XmlName); - if (TryGetReferencedType(stableName, dataContract, out type)) + if (TryGetReferencedType(xmlName, dataContract, out type)) return type; } return null; } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal bool TryGetReferencedType(XmlQualifiedName stableName, DataContract? dataContract, [NotNullWhen(true)] out Type? type) + internal bool TryGetReferencedType(XmlQualifiedName xmlName, DataContract? dataContract, [NotNullWhen(true)] out Type? type) { - return TryGetReferencedType(stableName, dataContract, false/*useReferencedCollectionTypes*/, out type); + return TryGetReferencedType(xmlName, dataContract, false/*useReferencedCollectionTypes*/, out type); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal bool TryGetReferencedCollectionType(XmlQualifiedName stableName, DataContract? dataContract, [NotNullWhen(true)] out Type? type) + internal bool TryGetReferencedCollectionType(XmlQualifiedName xmlName, DataContract? dataContract, [NotNullWhen(true)] out Type? type) { - return TryGetReferencedType(stableName, dataContract, true/*useReferencedCollectionTypes*/, out type); + return TryGetReferencedType(xmlName, dataContract, true/*useReferencedCollectionTypes*/, out type); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private bool TryGetReferencedType(XmlQualifiedName stableName, DataContract? dataContract, bool useReferencedCollectionTypes, [NotNullWhen(true)] out Type? type) + private bool TryGetReferencedType(XmlQualifiedName xmlName, DataContract? dataContract, bool useReferencedCollectionTypes, [NotNullWhen(true)] out Type? type) { Dictionary referencedTypes = useReferencedCollectionTypes ? GetReferencedCollectionTypes() : GetReferencedTypes(); - if (referencedTypes.TryGetValue(stableName, out object? value)) + if (referencedTypes.TryGetValue(xmlName, out object? value)) { type = value as Type; if (type != null) @@ -579,8 +578,8 @@ private bool TryGetReferencedType(XmlQualifiedName stableName, DataContract? dat { throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format( (useReferencedCollectionTypes ? SR.AmbiguousReferencedCollectionTypes3 : SR.AmbiguousReferencedTypes3), - XmlConvert.DecodeName(stableName.Name), - stableName.Namespace, + XmlConvert.DecodeName(xmlName.Name), + xmlName.Namespace, errorMessage.ToString()))); } } @@ -589,7 +588,7 @@ private bool TryGetReferencedType(XmlQualifiedName stableName, DataContract? dat return false; } - internal ISerializationExtendedSurrogateProvider? SerializationExtendedSurrogateProvider => _extendedSurrogateProvider; + internal ISerializationSurrogateProvider2? SerializationExtendedSurrogateProvider => _extendedSurrogateProvider; internal object? GetSurrogateData(object key) { @@ -617,24 +616,17 @@ internal IEnumerator> GetEnumerator } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public void ExportSchemaSet(XmlSchemaSet schemaSet) - { - SchemaExporter exporter = new SchemaExporter(schemaSet, this); - exporter.Export(); - } - - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public void ImportSchemaSet(XmlSchemaSet schemaSet, ICollection? typeNames, bool importXmlDataType) + public void ImportSchemaSet(XmlSchemaSet schemaSet, IEnumerable? typeNames, bool importXmlDataType) { SchemaImporter importer = new SchemaImporter(schemaSet, typeNames, null, this, importXmlDataType); - importer.Import(out IList _); + importer.Import(out List _); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - public IList ImportSchemaSet(XmlSchemaSet schemaSet, ICollection elements, bool importXmlDataType) + public List ImportSchemaSet(XmlSchemaSet schemaSet, IEnumerable elements, bool importXmlDataType) { SchemaImporter importer = new SchemaImporter(schemaSet, Array.Empty() /* Needs to be empty, not null for 'elements' to be used. */, elements, this, importXmlDataType); - importer.Import(out IList? elementNames); + importer.Import(out List? elementNames); return elementNames!; // Not null when we have provided non-null 'typeNames' and 'elements' } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSurrogateCaller.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSurrogateCaller.cs index 1fffd1c604d47..81e35932b1650 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSurrogateCaller.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSurrogateCaller.cs @@ -5,6 +5,7 @@ using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; using System.Reflection; +using System.Runtime.Serialization.DataContracts; namespace System.Runtime.Serialization { @@ -40,26 +41,26 @@ internal static Type GetDataContractType(ISerializationSurrogateProvider surroga return surrogateProvider.GetDeserializedObject(obj, memberType); } - internal static object? GetCustomDataToExport(ISerializationExtendedSurrogateProvider surrogateProvider, MemberInfo memberInfo, Type dataContractType) + internal static object? GetCustomDataToExport(ISerializationSurrogateProvider2 surrogateProvider, MemberInfo memberInfo, Type dataContractType) { return surrogateProvider.GetCustomDataToExport(memberInfo, dataContractType); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static object? GetCustomDataToExport(ISerializationExtendedSurrogateProvider surrogateProvider, Type clrType, Type dataContractType) + internal static object? GetCustomDataToExport(ISerializationSurrogateProvider2 surrogateProvider, Type clrType, Type dataContractType) { if (DataContract.GetBuiltInDataContract(clrType) != null) return null; return surrogateProvider.GetCustomDataToExport(clrType, dataContractType); } - internal static void GetKnownCustomDataTypes(ISerializationExtendedSurrogateProvider surrogateProvider, Collection customDataTypes) + internal static void GetKnownCustomDataTypes(ISerializationSurrogateProvider2 surrogateProvider, Collection customDataTypes) { surrogateProvider.GetKnownCustomDataTypes(customDataTypes); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static Type? GetReferencedTypeOnImport(ISerializationExtendedSurrogateProvider surrogateProvider, string typeName, string typeNamespace, object? customData) + internal static Type? GetReferencedTypeOnImport(ISerializationSurrogateProvider2 surrogateProvider, string typeName, string typeNamespace, object? customData) { if (DataContract.GetBuiltInDataContract(typeName, typeNamespace) != null) return null; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs index a5abdb176b36a..816b9aca0cdbf 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs @@ -6,7 +6,7 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; -namespace System.Runtime.Serialization +namespace System.Runtime.Serialization.DataContracts { public sealed class DataMember { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs index 197b0cb0cd1a2..7ae2bd9b8738b 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs @@ -3,14 +3,14 @@ using System; using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; using System.Reflection; using System.Threading; using System.Xml; -using System.Linq; -using System.Diagnostics.CodeAnalysis; -using System.Diagnostics; -namespace System.Runtime.Serialization +namespace System.Runtime.Serialization.DataContracts { internal sealed class EnumDataContract : DataContract { @@ -95,9 +95,9 @@ static EnumDataContractCriticalHelper() internal static void Add(Type type, string localName) { - XmlQualifiedName stableName = CreateQualifiedName(localName, Globals.SchemaNamespace); - s_typeToName.Add(type, stableName); - s_nameToType.Add(stableName, type); + XmlQualifiedName xmlName = CreateQualifiedName(localName, Globals.SchemaNamespace); + s_typeToName.Add(type, xmlName); + s_nameToType.Add(xmlName, type); } internal static XmlQualifiedName GetBaseContractName(Type type) @@ -119,19 +119,19 @@ internal EnumDataContractCriticalHelper( [DynamicallyAccessedMembers(ClassDataContract.DataContractPreserveMemberTypes)] Type type) : base(type) { - StableName = DataContract.GetStableName(type, out _hasDataContract); + XmlName = DataContract.GetXmlName(type, out _hasDataContract); Type baseType = Enum.GetUnderlyingType(type); XmlQualifiedName baseTypeName = GetBaseContractName(baseType); _baseContract = DataContract.GetBuiltInDataContract(baseTypeName.Name, baseTypeName.Namespace)!; - // NOTE TODO smolloy - Setting StableName might be redundant. But I don't want to miss an edge case. - _baseContract.StableName = baseTypeName; + // NOTE TODO smolloy - Setting XmlName might be redundant. But I don't want to miss an edge case. + _baseContract.XmlName = baseTypeName; ImportBaseType(baseType); IsFlags = type.IsDefined(Globals.TypeOfFlagsAttribute, false); ImportDataMembers(); XmlDictionary dictionary = new XmlDictionary(2 + Members.Count); - Name = dictionary.Add(StableName.Name); - Namespace = dictionary.Add(StableName.Namespace); + Name = dictionary.Add(XmlName.Name); + Namespace = dictionary.Add(XmlName.Namespace); _childElementNames = new XmlDictionaryString[Members.Count]; for (int i = 0; i < Members.Count; i++) _childElementNames[i] = dictionary.Add(Members[i].Name); @@ -153,7 +153,7 @@ internal EnumDataContractCriticalHelper( internal XmlQualifiedName BaseContractName { - get => _baseContract.StableName; + get => _baseContract.XmlName; [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] set @@ -161,11 +161,11 @@ internal XmlQualifiedName BaseContractName Type? baseType = GetBaseType(value); if (baseType == null) ThrowInvalidDataContractException( - SR.Format(SR.InvalidEnumBaseType, value.Name, value.Namespace, StableName.Name, StableName.Namespace)); + SR.Format(SR.InvalidEnumBaseType, value.Name, value.Namespace, XmlName.Name, XmlName.Namespace)); ImportBaseType(baseType); _baseContract = DataContract.GetBuiltInDataContract(value.Name, value.Namespace)!; - // NOTE TODO smolloy - Setting StableName might be redundant. But I don't want to miss an edge case. - _baseContract.StableName = value; + // NOTE TODO smolloy - Setting XmlName might be redundant. But I don't want to miss an edge case. + _baseContract.XmlName = value; } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExportOptions.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExportOptions.cs index 88a8a1c148934..8034f326ea09e 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExportOptions.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExportOptions.cs @@ -5,10 +5,26 @@ namespace System.Runtime.Serialization { + /// + /// Represents the options that can be set for an . + /// + /// + /// The is used to generate XSD schemas from a type or assembly. You can also use the XsdDataContractImporter to generate .NET Framework code from a schema document. + /// + /// The property is used by the to include types that can be read in an object graph. + /// public class ExportOptions { private Collection? _knownTypes; + /// + /// Gets or sets a serialization surrogate provider. + /// + public ISerializationSurrogateProvider? DataContractSurrogate { get; set; } + + /// + /// Gets the collection of types that may be encountered during serialization or deserialization. + /// public Collection KnownTypes => _knownTypes ??= new Collection(); } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExtensionDataReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExtensionDataReader.cs index b339a271d56d5..ee25766466b35 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExtensionDataReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExtensionDataReader.cs @@ -1,12 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Xml; using System.Collections; -using System.Diagnostics.CodeAnalysis; using System.Collections.Generic; -using System.Globalization; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Runtime.Serialization.DataContracts; +using System.Xml; namespace System.Runtime.Serialization { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs index 3f3b87a01b340..1d5eca774631c 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/GenericParameterDataContract.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -namespace System.Runtime.Serialization +namespace System.Runtime.Serialization.DataContracts { internal sealed class GenericParameterDataContract : DataContract { @@ -32,7 +32,7 @@ internal GenericParameterDataContractCriticalHelper( Type type) : base(type) { - SetDataContractName(DataContract.GetStableName(type)); + SetDataContractName(DataContract.GetXmlName(type)); _parameterPosition = type.GenericParameterPosition; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs index c10db1641eb12..16fc2561b92a5 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs @@ -8,6 +8,7 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Reflection; +using System.Runtime.Serialization.DataContracts; using System.Text.RegularExpressions; using System.Xml; using System.Xml.Schema; @@ -321,7 +322,7 @@ internal static Type TypeOfHashtable private static MemberInfo? s_schemaMemberInfoPlaceholder; internal static MemberInfo SchemaMemberInfoPlaceholder => - s_schemaMemberInfoPlaceholder ??= TypeOfSchemaDefinedType.GetField("_stableName", BindingFlags.NonPublic | BindingFlags.Instance)!; + s_schemaMemberInfoPlaceholder ??= TypeOfSchemaDefinedType.GetField("_xmlName", BindingFlags.NonPublic | BindingFlags.Instance)!; private static Uri? s_dataContractXsdBaseNamespaceUri; internal static Uri DataContractXsdBaseNamespaceUri => diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs index 8b6120b95eaf2..03bfb8abee2f1 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs @@ -10,11 +10,12 @@ using System.IO; using System.Reflection; using System.Runtime.Serialization; +using System.Runtime.Serialization.DataContracts; using System.Security; using System.Text; using System.Xml; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization.Json { @@ -200,6 +201,19 @@ private XmlDictionaryString RootName } } + // These Get/Set methods mirror the extensions that were added to DCS in the early days of Core, which allowed + // using a slimmed-down surrogate on both NetFx and Core via type-forwarding mechanisms. That's why these are + // a pair of methods instead of making the property itself public. + public ISerializationSurrogateProvider? GetSerializationSurrogateProvider() + { + return SerializationSurrogateProvider; + } + + public void SetSerializationSurrogateProvider(ISerializationSurrogateProvider? provider) + { + SerializationSurrogateProvider = provider; + } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] public override bool IsStartObject(XmlReader reader) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonByteArrayDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonByteArrayDataContract.cs index 5518442c8649d..8a6ca1fb0f4c4 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonByteArrayDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonByteArrayDataContract.cs @@ -3,10 +3,11 @@ using System; using System.Collections.Generic; -using System.Text; using System.Diagnostics; -using System.Xml; using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization.DataContracts; +using System.Text; +using System.Xml; namespace System.Runtime.Serialization.Json { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonClassDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonClassDataContract.cs index 6ff59d9eaa7f2..509b99f968217 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonClassDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonClassDataContract.cs @@ -1,12 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Threading; -using System.Xml; -using System.Diagnostics; using System.Collections.Generic; -using System.Runtime.CompilerServices; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.Serialization.DataContracts; +using System.Threading; +using System.Xml; namespace System.Runtime.Serialization.Json { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonCollectionDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonCollectionDataContract.cs index 9d0a40cc5d1c9..cbf92bf3e43e3 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonCollectionDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonCollectionDataContract.cs @@ -5,6 +5,7 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.Serialization.DataContracts; using System.Threading; using System.Xml; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonDataContract.cs index f33cfa3b9b9eb..589e69485f54f 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonDataContract.cs @@ -2,14 +2,15 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; using System.Runtime; using System.Runtime.Serialization; -using System.Reflection; +using System.Runtime.Serialization.DataContracts; using System.Xml; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization.Json { @@ -287,13 +288,13 @@ private void AddCollectionItemContractsToKnownDataContracts() DataContract itemContract = collectionDataContract.ItemContract; _knownDataContracts ??= new DataContractDictionary(); - _knownDataContracts.TryAdd(itemContract.StableName, itemContract); + _knownDataContracts.TryAdd(itemContract.XmlName, itemContract); if (collectionDataContract.ItemType.IsGenericType && collectionDataContract.ItemType.GetGenericTypeDefinition() == typeof(KeyValue<,>)) { DataContract itemDataContract = DataContract.GetDataContract(Globals.TypeOfKeyValuePair.MakeGenericType(collectionDataContract.ItemType.GenericTypeArguments)); - _knownDataContracts.TryAdd(itemDataContract.StableName, itemDataContract); + _knownDataContracts.TryAdd(itemDataContract.XmlName, itemDataContract); } if (!(itemContract is CollectionDataContract)) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonEnumDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonEnumDataContract.cs index 76f774cde91f0..e20b49ca92b4e 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonEnumDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonEnumDataContract.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization.DataContracts; namespace System.Runtime.Serialization.Json { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatGeneratorStatics.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatGeneratorStatics.cs index 0df641f90eea0..b094e6fcde688 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatGeneratorStatics.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatGeneratorStatics.cs @@ -7,6 +7,7 @@ using System.Xml; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization.DataContracts; using System.Runtime.Serialization.Json; namespace System.Runtime.Serialization diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs index 177aba2e87060..9b7dd72c90c93 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs @@ -8,6 +8,7 @@ using System.Reflection; using System.Reflection.Emit; using System.Runtime; +using System.Runtime.Serialization.DataContracts; using System.Security; using System.Xml; @@ -62,7 +63,7 @@ public JsonFormatClassReaderDelegate GenerateClassReader(ClassDataContract class bool memberAccessFlag = classContract.RequiresMemberAccessForRead(null); try { - BeginMethod(_ilg, "Read" + DataContract.SanitizeTypeName(classContract.StableName!.Name) + "FromJson", typeof(JsonFormatClassReaderDelegate), memberAccessFlag); + BeginMethod(_ilg, "Read" + DataContract.SanitizeTypeName(classContract.XmlName!.Name) + "FromJson", typeof(JsonFormatClassReaderDelegate), memberAccessFlag); } catch (SecurityException securityException) { @@ -143,11 +144,11 @@ private CodeGenerator GenerateCollectionReaderHelper(CollectionDataContract coll { if (isGetOnlyCollection) { - BeginMethod(_ilg, "Read" + DataContract.SanitizeTypeName(collectionContract.StableName.Name) + "FromJson" + "IsGetOnly", typeof(JsonFormatGetOnlyCollectionReaderDelegate), memberAccessFlag); + BeginMethod(_ilg, "Read" + DataContract.SanitizeTypeName(collectionContract.XmlName.Name) + "FromJson" + "IsGetOnly", typeof(JsonFormatGetOnlyCollectionReaderDelegate), memberAccessFlag); } else { - BeginMethod(_ilg, "Read" + DataContract.SanitizeTypeName(collectionContract.StableName.Name) + "FromJson", typeof(JsonFormatCollectionReaderDelegate), memberAccessFlag); + BeginMethod(_ilg, "Read" + DataContract.SanitizeTypeName(collectionContract.XmlName.Name) + "FromJson", typeof(JsonFormatCollectionReaderDelegate), memberAccessFlag); } } catch (SecurityException securityException) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs index f3263d067c13e..a57df0b14d279 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs @@ -7,6 +7,7 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Reflection.Emit; +using System.Runtime.Serialization.DataContracts; using System.Security; using System.Xml; @@ -56,7 +57,7 @@ internal JsonFormatClassWriterDelegate GenerateClassWriter(ClassDataContract cla bool memberAccessFlag = classContract.RequiresMemberAccessForWrite(null); try { - BeginMethod(_ilg, "Write" + DataContract.SanitizeTypeName(classContract.StableName.Name) + "ToJson", typeof(JsonFormatClassWriterDelegate), memberAccessFlag); + BeginMethod(_ilg, "Write" + DataContract.SanitizeTypeName(classContract.XmlName.Name) + "ToJson", typeof(JsonFormatClassWriterDelegate), memberAccessFlag); } catch (SecurityException securityException) { @@ -82,7 +83,7 @@ internal JsonFormatCollectionWriterDelegate GenerateCollectionWriter(CollectionD bool memberAccessFlag = collectionContract.RequiresMemberAccessForWrite(null); try { - BeginMethod(_ilg, "Write" + DataContract.SanitizeTypeName(collectionContract.StableName.Name) + "ToJson", typeof(JsonFormatCollectionWriterDelegate), memberAccessFlag); + BeginMethod(_ilg, "Write" + DataContract.SanitizeTypeName(collectionContract.XmlName.Name) + "ToJson", typeof(JsonFormatCollectionWriterDelegate), memberAccessFlag); } catch (SecurityException securityException) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonObjectDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonObjectDataContract.cs index c6e4945072ef8..4505882af7fe5 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonObjectDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonObjectDataContract.cs @@ -1,10 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Xml; -using System.Runtime.Serialization; -using System.Globalization; using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Runtime.Serialization; +using System.Runtime.Serialization.DataContracts; +using System.Xml; namespace System.Runtime.Serialization.Json { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonQNameDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonQNameDataContract.cs index 8bc4a2d1f5042..5cf4f54cec7ad 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonQNameDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonQNameDataContract.cs @@ -3,10 +3,11 @@ using System; using System.Collections.Generic; -using System.Text; using System.Diagnostics; -using System.Xml; using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization.DataContracts; +using System.Text; +using System.Xml; namespace System.Runtime.Serialization.Json { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonStringDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonStringDataContract.cs index e65c58c9caed5..1e3379ceb62f2 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonStringDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonStringDataContract.cs @@ -3,10 +3,11 @@ using System; using System.Collections.Generic; -using System.Text; using System.Diagnostics; -using System.Xml; using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization.DataContracts; +using System.Xml; +using System.Text; namespace System.Runtime.Serialization.Json { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonUriDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonUriDataContract.cs index bd4b68daf4103..3dc37084b1d74 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonUriDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonUriDataContract.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization.DataContracts; namespace System.Runtime.Serialization.Json { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonXmlDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonXmlDataContract.cs index 96bef751e97a4..f08ce85a82ffb 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonXmlDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonXmlDataContract.cs @@ -4,10 +4,11 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; +using System.Runtime.Serialization.DataContracts; using System.Text; using System.Xml; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization.Json { @@ -60,7 +61,7 @@ private static List GetKnownTypesFromContext(XmlObjectSerializerContext? c List knownTypesList = new List(); if (context != null) { - List stableNames = new List(); + List xmlNames = new List(); DataContractDictionary[] entries = context.scopedKnownTypes.dataContractDictionaries; if (entries != null) { @@ -71,9 +72,9 @@ private static List GetKnownTypesFromContext(XmlObjectSerializerContext? c { foreach (KeyValuePair pair in entry) { - if (!stableNames.Contains(pair.Key)) + if (!xmlNames.Contains(pair.Key)) { - stableNames.Add(pair.Key); + xmlNames.Add(pair.Key); knownTypesList.Add(pair.Value.UnderlyingType); } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatReader.cs index 4161f53a29aec..b8564fda29941 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatReader.cs @@ -8,6 +8,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; +using System.Runtime.Serialization.DataContracts; using System.Text; using System.Threading.Tasks; using System.Xml; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatWriter.cs index a2cc3eed509ef..b0417289512db 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/ReflectionJsonFormatWriter.cs @@ -8,6 +8,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; +using System.Runtime.Serialization.DataContracts; using System.Text; using System.Threading.Tasks; using System.Xml; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlObjectSerializerReadContextComplexJson.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlObjectSerializerReadContextComplexJson.cs index 9c61887a150b4..e94d7ff80848a 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlObjectSerializerReadContextComplexJson.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlObjectSerializerReadContextComplexJson.cs @@ -3,11 +3,12 @@ using System; using System.Collections.Generic; -using System.Text; +using System.Diagnostics.CodeAnalysis; using System.Reflection; -using System.Xml; using System.Runtime.Serialization; -using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization.DataContracts; +using System.Text; +using System.Xml; namespace System.Runtime.Serialization.Json { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlObjectSerializerWriteContextComplexJson.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlObjectSerializerWriteContextComplexJson.cs index 117f37afdcb96..d9433179d318d 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlObjectSerializerWriteContextComplexJson.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/XmlObjectSerializerWriteContextComplexJson.cs @@ -2,13 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Collections; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Reflection; +using System.Runtime.Serialization.DataContracts; using System.Text; using System.Xml; -using System.Reflection; -using System.Collections; -using System.IO; -using System.Diagnostics.CodeAnalysis; namespace System.Runtime.Serialization.Json { @@ -255,7 +256,7 @@ internal override void SerializeWithXsiTypeAtTopLevel(DataContract dataContract, private void VerifyType(DataContract dataContract, Type declaredType) { bool knownTypesAddedInCurrentScope = false; - if (dataContract.KnownDataContracts != null) + if (dataContract.KnownDataContracts?.Count > 0) { scopedKnownTypes.Push(dataContract.KnownDataContracts); knownTypesAddedInCurrentScope = true; @@ -263,7 +264,7 @@ private void VerifyType(DataContract dataContract, Type declaredType) if (!IsKnownType(dataContract, declaredType)) { - throw XmlObjectSerializer.CreateSerializationException(SR.Format(SR.DcTypeNotFoundOnSerialize, DataContract.GetClrTypeFullName(dataContract.UnderlyingType), dataContract.StableName.Name, dataContract.StableName.Namespace)); + throw XmlObjectSerializer.CreateSerializationException(SR.Format(SR.DcTypeNotFoundOnSerialize, DataContract.GetClrTypeFullName(dataContract.UnderlyingType), dataContract.XmlName.Name, dataContract.XmlName.Namespace)); } if (knownTypesAddedInCurrentScope) @@ -383,7 +384,7 @@ internal override DataContract GetDataContract(int id, RuntimeTypeHandle typeHan [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal static DataContract? ResolveJsonDataContractFromRootDataContract(XmlObjectSerializerContext context, XmlQualifiedName typeQName, DataContract rootTypeDataContract) { - if (rootTypeDataContract.StableName == typeQName) + if (rootTypeDataContract.XmlName == typeQName) return rootTypeDataContract; CollectionDataContract? collectionContract = rootTypeDataContract as CollectionDataContract; @@ -399,7 +400,7 @@ internal override DataContract GetDataContract(int id, RuntimeTypeHandle typeHan { itemContract = context.GetDataContract(context.GetSurrogatedType(collectionContract.ItemType)); } - if (itemContract.StableName == typeQName) + if (itemContract.XmlName == typeQName) { return itemContract; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/KnownTypeDataContractResolver.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/KnownTypeDataContractResolver.cs index 6a6acdfc56742..ca96ede659dab 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/KnownTypeDataContractResolver.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/KnownTypeDataContractResolver.cs @@ -1,8 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Xml; using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization.DataContracts; +using System.Xml; namespace System.Runtime.Serialization { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs index 098927687e433..d861fcbdbdcf5 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs @@ -9,7 +9,7 @@ using System.Reflection; using System.Xml; -namespace System.Runtime.Serialization +namespace System.Runtime.Serialization.DataContracts { internal abstract class PrimitiveDataContract : DataContract { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionClassWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionClassWriter.cs index a2c462953ba1f..10c2cc1f199f6 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionClassWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionClassWriter.cs @@ -9,6 +9,7 @@ using System.IO; using System.Linq; using System.Reflection; +using System.Runtime.Serialization.DataContracts; using System.Text; using System.Threading.Tasks; using System.Xml; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionFeature.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionFeature.cs deleted file mode 100644 index d071056761ce3..0000000000000 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionFeature.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Runtime.Serialization -{ - internal static class ReflectionBasedSerializationFeature - { - public const string Name = "System.Runtime.Serialization.ReflectionBasedSerialization"; - } -} diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs index d895befacdecb..a1982aa1ac3db 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs @@ -8,6 +8,7 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; +using System.Runtime.Serialization.DataContracts; using System.Text; using System.Threading.Tasks; using System.Xml; @@ -222,7 +223,7 @@ protected void ReflectionReadMember(XmlReaderDelegator xmlReader, XmlObjectSeria else { context.ResetCollectionMemberInfo(); - var value = ReflectionReadValue(xmlReader, context, dataMember, classContract.StableName.Namespace); + var value = ReflectionReadValue(xmlReader, context, dataMember, classContract.XmlName.Namespace); MemberInfo memberInfo = dataMember.MemberInfo; Debug.Assert(memberInfo != null); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatReader.cs index 63572bd37dc26..6c31a151498d7 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatReader.cs @@ -2,15 +2,16 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Xml; -using System.Xml.Schema; -using System.Reflection; -using System.Reflection.Emit; using System.Collections; using System.Collections.Generic; -using System.Security; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.Serialization.DataContracts; +using System.Security; +using System.Xml; +using System.Xml.Schema; namespace System.Runtime.Serialization { @@ -101,7 +102,7 @@ protected override void ReflectionReadMembers(XmlReaderDelegator xmlReader, XmlO protected override string GetClassContractNamespace(ClassDataContract classContract) { - return classContract.StableName!.Namespace; + return classContract.XmlName!.Namespace; } protected override string GetCollectionContractItemName(CollectionDataContract collectionContract) @@ -111,7 +112,7 @@ protected override string GetCollectionContractItemName(CollectionDataContract c protected override string GetCollectionContractNamespace(CollectionDataContract collectionContract) { - return collectionContract.StableName.Namespace; + return collectionContract.XmlName.Namespace; } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatWriter.cs index 204d4cb8c15fb..339cb9c1021fb 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionXmlFormatWriter.cs @@ -7,6 +7,7 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Reflection.Emit; +using System.Runtime.Serialization.DataContracts; using System.Xml; namespace System.Runtime.Serialization @@ -230,11 +231,11 @@ private static bool CheckIfMemberHasConflict(DataMember member, ClassDataContrac // Check for conflict with derived type members string? name = member.Name; - string? ns = classContract.StableName.Namespace; + string? ns = classContract.XmlName.Namespace; ClassDataContract? currentContract = derivedMostClassContract; while (currentContract != null && currentContract != classContract) { - if (ns == currentContract.StableName.Namespace) + if (ns == currentContract.XmlName.Namespace) { List members = currentContract.Members!; for (int j = 0; j < members.Count; j++) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs index fbc73634fb3f8..976d9880a41d4 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaExporter.cs @@ -10,6 +10,7 @@ using System.Globalization; using System.IO; using System.Reflection; +using System.Runtime.Serialization.DataContracts; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; @@ -80,7 +81,7 @@ private void ExportDataContract(DataContract dataContract) ExportXmlDataContract((XmlDataContract)dataContract); else { - XmlSchema schema = GetSchema(dataContract.StableName.Namespace); + XmlSchema schema = GetSchema(dataContract.XmlName.Namespace); if (dataContract is ClassDataContract classDataContract) { @@ -100,7 +101,7 @@ private void ExportDataContract(DataContract dataContract) private XmlSchemaElement ExportTopLevelElement(DataContract dataContract, XmlSchema? schema) { - if (schema == null || dataContract.StableName.Namespace != dataContract.TopLevelElementNamespace!.Value) + if (schema == null || dataContract.XmlName.Namespace != dataContract.TopLevelElementNamespace!.Value) schema = GetSchema(dataContract.TopLevelElementNamespace!.Value); XmlSchemaElement topLevelElement = new XmlSchemaElement(); @@ -115,7 +116,7 @@ private XmlSchemaElement ExportTopLevelElement(DataContract dataContract, XmlSch private void ExportClassDataContract(ClassDataContract classDataContract, XmlSchema schema) { XmlSchemaComplexType type = new XmlSchemaComplexType(); - type.Name = classDataContract.StableName.Name; + type.Name = classDataContract.XmlName.Name; schema.Items.Add(type); XmlElement? genericInfoElement = null; if (classDataContract.UnderlyingType.IsGenericType) @@ -133,8 +134,8 @@ private void ExportClassDataContract(ClassDataContract classDataContract, XmlSch if (CheckIfMemberHasConflict(dataMember)) { element.SchemaTypeName = AnytypeQualifiedName; - actualTypeElement = ExportActualType(memberTypeContract.StableName); - SchemaHelper.AddSchemaImport(memberTypeContract.StableName.Namespace, schema); + actualTypeElement = ExportActualType(memberTypeContract.XmlName); + SchemaHelper.AddSchemaImport(memberTypeContract.XmlName.Namespace, schema); } else SetElementType(element, memberTypeContract, schema); @@ -151,7 +152,7 @@ private void ExportClassDataContract(ClassDataContract classDataContract, XmlSch XmlElement? isValueTypeElement = null; if (classDataContract.BaseClassContract != null) { - XmlSchemaComplexContentExtension extension = CreateTypeContent(type, classDataContract.BaseClassContract.StableName, schema); + XmlSchemaComplexContentExtension extension = CreateTypeContent(type, classDataContract.BaseClassContract.XmlName, schema); extension.Particle = rootSequence; if (classDataContract.IsReference && !classDataContract.BaseClassContract.IsReference) { @@ -185,12 +186,12 @@ private static void SetElementType(XmlSchemaElement element, DataContract dataCo } else { - element.SchemaTypeName = dataContract.StableName; + element.SchemaTypeName = dataContract.XmlName; if (element.SchemaTypeName.Namespace.Equals(Globals.SerializationNamespace)) schema.Namespaces.Add(Globals.SerPrefixForSchema, Globals.SerializationNamespace); - SchemaHelper.AddSchemaImport(dataContract.StableName.Namespace, schema); + SchemaHelper.AddSchemaImport(dataContract.XmlName.Namespace, schema); } } @@ -278,7 +279,7 @@ private XmlElement ExportGenericInfo(Type clrType, string elementName, string el genericArgumentCounts = DataContract.GetDataContractNameForGenericName(typeName, null); clrType = clrType.GetGenericTypeDefinition(); } - XmlQualifiedName dcqname = DataContract.GetStableName(clrType); + XmlQualifiedName dcqname = DataContract.GetXmlName(clrType); if (nestedCollectionLevel > 0) { string collectionName = dcqname.Name; @@ -353,7 +354,7 @@ private XmlElement ExportGenericInfo(Type clrType, string elementName, string el private void ExportCollectionDataContract(CollectionDataContract collectionDataContract, XmlSchema schema) { XmlSchemaComplexType type = new XmlSchemaComplexType(); - type.Name = collectionDataContract.StableName.Name; + type.Name = collectionDataContract.XmlName.Name; schema.Items.Add(type); XmlElement? genericInfoElement = null, isDictionaryElement = null; if (collectionDataContract.UnderlyingType.IsGenericType && CollectionDataContract.IsCollectionDataContract(collectionDataContract.UnderlyingType)) @@ -414,7 +415,7 @@ private XmlElement ExportIsDictionary() private void ExportEnumDataContract(EnumDataContract enumDataContract, XmlSchema schema) { XmlSchemaSimpleType type = new XmlSchemaSimpleType(); - type.Name = enumDataContract.StableName.Name; + type.Name = enumDataContract.XmlName.Name; XmlElement? actualTypeElement = (enumDataContract.BaseContractName == DefaultEnumBaseTypeName) ? null : ExportActualType(enumDataContract.BaseContractName); type.Annotation = GetSchemaAnnotation(actualTypeElement, ExportSurrogateData(enumDataContract)); schema.Items.Add(type); @@ -454,7 +455,7 @@ internal static long GetDefaultEnumValue(bool isFlags, int index) private void ExportISerializableDataContract(ClassDataContract dataContract, XmlSchema schema) { XmlSchemaComplexType type = new XmlSchemaComplexType(); - type.Name = dataContract.StableName.Name; + type.Name = dataContract.XmlName.Name; schema.Items.Add(type); XmlElement? genericInfoElement = null; if (dataContract.UnderlyingType.IsGenericType) @@ -463,7 +464,7 @@ private void ExportISerializableDataContract(ClassDataContract dataContract, Xml XmlElement? isValueTypeElement = null; if (dataContract.BaseClassContract != null) { - _ = CreateTypeContent(type, dataContract.BaseClassContract.StableName, schema); + _ = CreateTypeContent(type, dataContract.BaseClassContract.XmlName, schema); } else { @@ -504,7 +505,7 @@ private void ExportXmlDataContract(XmlDataContract dataContract) if (hasRoot) { - if (!(typeQName.Equals(dataContract.StableName))) + if (!(typeQName.Equals(dataContract.XmlName))) { Fx.Assert("XML data contract type name does not match schema name"); } @@ -578,26 +579,26 @@ private static void ReprocessAll(XmlSchemaSet schemas)// and remove duplicate it } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal static void GetXmlTypeInfo(Type type, out XmlQualifiedName stableName, out XmlSchemaType? xsdType, out bool hasRoot) + internal static void GetXmlTypeInfo(Type type, out XmlQualifiedName xmlName, out XmlSchemaType? xsdType, out bool hasRoot) { - if (IsSpecialXmlType(type, out stableName!, out xsdType, out hasRoot)) + if (IsSpecialXmlType(type, out xmlName!, out xsdType, out hasRoot)) return; XmlSchemaSet schemas = new XmlSchemaSet(); schemas.XmlResolver = null; - InvokeSchemaProviderMethod(type, schemas, out stableName, out xsdType, out hasRoot); - if (stableName.Name == null || stableName.Name.Length == 0) + InvokeSchemaProviderMethod(type, schemas, out xmlName, out xsdType, out hasRoot); + if (xmlName.Name == null || xmlName.Name.Length == 0) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidXmlDataContractName, DataContract.GetClrTypeFullName(type)))); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private static bool InvokeSchemaProviderMethod(Type clrType, XmlSchemaSet schemas, out XmlQualifiedName stableName, out XmlSchemaType? xsdType, out bool hasRoot) + private static bool InvokeSchemaProviderMethod(Type clrType, XmlSchemaSet schemas, out XmlQualifiedName xmlName, out XmlSchemaType? xsdType, out bool hasRoot) { xsdType = null; hasRoot = true; object[] attrs = clrType.GetCustomAttributes(Globals.TypeOfXmlSchemaProviderAttribute, false); if (attrs == null || attrs.Length == 0) { - stableName = DataContract.GetDefaultStableName(clrType); + xmlName = DataContract.GetDefaultXmlName(clrType); return false; } @@ -612,7 +613,7 @@ private static bool InvokeSchemaProviderMethod(Type clrType, XmlSchemaSet schema { if (!provider.IsAny) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidGetSchemaMethod, DataContract.GetClrTypeFullName(clrType)))); - stableName = DataContract.GetDefaultStableName(clrType); + xmlName = DataContract.GetDefaultXmlName(clrType); } else { @@ -629,13 +630,13 @@ private static bool InvokeSchemaProviderMethod(Type clrType, XmlSchemaSet schema { if (typeInfo != null) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidNonNullReturnValueByIsAny, DataContract.GetClrTypeFullName(clrType), methodName))); - stableName = DataContract.GetDefaultStableName(clrType); + xmlName = DataContract.GetDefaultXmlName(clrType); } else if (typeInfo == null) { xsdType = CreateAnyElementType(); hasRoot = false; - stableName = DataContract.GetDefaultStableName(clrType); + xmlName = DataContract.GetDefaultXmlName(clrType); } else { @@ -645,9 +646,9 @@ private static bool InvokeSchemaProviderMethod(Type clrType, XmlSchemaSet schema string? typeNs = null; if (typeName == null || typeName.Length == 0) { - DataContract.GetDefaultStableName(DataContract.GetClrTypeFullName(clrType), out typeName, out typeNs); - stableName = new XmlQualifiedName(typeName, typeNs); - providerXsdType.Annotation = GetSchemaAnnotation(ExportActualType(stableName, new XmlDocument())); + DataContract.GetDefaultXmlName(DataContract.GetClrTypeFullName(clrType), out typeName, out typeNs); + xmlName = new XmlQualifiedName(typeName, typeNs); + providerXsdType.Annotation = GetSchemaAnnotation(ExportActualType(xmlName, new XmlDocument())); xsdType = providerXsdType; } else @@ -667,11 +668,11 @@ private static bool InvokeSchemaProviderMethod(Type clrType, XmlSchemaSet schema } if (typeNs == null) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.MissingSchemaType, typeName, DataContract.GetClrTypeFullName(clrType)))); - stableName = new XmlQualifiedName(typeName, typeNs); + xmlName = new XmlQualifiedName(typeName, typeNs); } } else - stableName = (XmlQualifiedName)typeInfo; + xmlName = (XmlQualifiedName)typeInfo; } } return true; @@ -680,19 +681,19 @@ private static bool InvokeSchemaProviderMethod(Type clrType, XmlSchemaSet schema private static void InvokeGetSchemaMethod( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type clrType, - XmlSchemaSet schemas, XmlQualifiedName stableName) + XmlSchemaSet schemas, XmlQualifiedName xmlName) { IXmlSerializable ixmlSerializable = (IXmlSerializable)Activator.CreateInstance(clrType)!; XmlSchema? schema = ixmlSerializable.GetSchema(); if (schema == null) { - AddDefaultDatasetType(schemas, stableName.Name, stableName.Namespace); + AddDefaultDatasetType(schemas, xmlName.Name, xmlName.Namespace); } else { if (schema.Id == null || schema.Id.Length == 0) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidReturnSchemaOnGetSchemaMethod, DataContract.GetClrTypeFullName(clrType)))); - AddDefaultTypedDatasetType(schemas, schema, stableName.Name, stableName.Namespace); + AddDefaultTypedDatasetType(schemas, schema, xmlName.Name, xmlName.Namespace); } } @@ -750,7 +751,7 @@ internal static bool IsSpecialXmlType(Type type, [NotNullWhen(true)] out XmlQual name = "ArrayOfXmlNode"; hasRoot = true; } - typeName = new XmlQualifiedName(name, DataContract.GetDefaultStableNamespace(type)); + typeName = new XmlQualifiedName(name, DataContract.GetDefaultXmlNamespace(type)); return true; } typeName = null; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs index 9c0f606d0542d..59639ac8bc6cc 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs @@ -29,11 +29,11 @@ internal SchemaObjectInfo(XmlSchemaType? type, XmlSchemaElement? element, XmlSch internal sealed class SchemaDefinedType { - private XmlQualifiedName _stableName; + private XmlQualifiedName _xmlName; - public SchemaDefinedType(XmlQualifiedName stableName) + public SchemaDefinedType(XmlQualifiedName xmlName) { - _stableName = stableName; + _xmlName = xmlName; } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs index a50a9b35dcd85..07afed9f5d03f 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs @@ -9,10 +9,11 @@ using System.Globalization; using System.IO; using System.Linq; +using System.Runtime.Serialization.DataContracts; using System.Xml; using System.Xml.Schema; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; using SchemaObjectDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization @@ -22,8 +23,8 @@ internal sealed class SchemaImporter { private DataContractSet _dataContractSet; private XmlSchemaSet _schemaSet; - private ICollection? _typeNames; - private ICollection? _elements; + private IEnumerable? _typeNames; + private IEnumerable? _elements; private bool _importXmlDataType; private SchemaObjectDictionary _schemaObjects = null!; // Not directly referenced. Always lazy initialized by property getter. private List _redefineList = null!; // Not directly referenced. Always lazy initialized by property getter. @@ -31,7 +32,7 @@ internal sealed class SchemaImporter private static Hashtable? s_serializationSchemaElements; - internal SchemaImporter(XmlSchemaSet schemas, ICollection? typeNames, ICollection? elements, DataContractSet dataContractSet, bool importXmlDataType) + internal SchemaImporter(XmlSchemaSet schemas, IEnumerable? typeNames, IEnumerable? elements, DataContractSet dataContractSet, bool importXmlDataType) { _dataContractSet = dataContractSet; _schemaSet = schemas; @@ -41,7 +42,7 @@ internal SchemaImporter(XmlSchemaSet schemas, ICollection? typ } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal void Import([NotNullIfNotNull("_elements")] out IList? elementTypeNames) + internal void Import([NotNullIfNotNull("_elements")] out List? elementTypeNames) { elementTypeNames = null!; @@ -97,29 +98,32 @@ internal void Import([NotNullIfNotNull("_elements")] out IList ImportType(typeName); } - if (_elements?.Count > 0) + if (_elements != null) { - elementTypeNames = new List(); + var elementNameList = new List(); foreach (XmlSchemaElement element in _elements) { XmlQualifiedName typeName = element.SchemaTypeName; if (typeName != null && typeName.Name.Length > 0) { - elementTypeNames.Add(ImportType(typeName).StableName); + elementNameList.Add(ImportType(typeName).XmlName); } else { XmlSchema? schema = SchemaHelper.GetSchemaWithGlobalElementDeclaration(element, _schemaSet); if (schema == null) { - elementTypeNames.Add(ImportAnonymousElement(element, element.QualifiedName).StableName); + elementNameList.Add(ImportAnonymousElement(element, element.QualifiedName).XmlName); } else { - elementTypeNames.Add(ImportAnonymousGlobalElement(element, element.QualifiedName, schema.TargetNamespace).StableName); + elementNameList.Add(ImportAnonymousGlobalElement(element, element.QualifiedName, schema.TargetNamespace).XmlName); } } } + + if (elementNameList.Count > 0) + elementTypeNames = elementNameList; } } ImportKnownTypesForObject(); @@ -223,9 +227,9 @@ private void ImportKnownTypesForObject() { // Expected: will throw exception if schema set contains types that are not supported DataContract dataContract = ImportType(knownType); - if (!knownDataContracts.TryGetValue(dataContract.StableName, out _)) + if (!knownDataContracts.TryGetValue(dataContract.XmlName, out _)) { - knownDataContracts.Add(dataContract.StableName, dataContract); + knownDataContracts.Add(dataContract.XmlName, dataContract); } } _dataContractSet.KnownTypesForObject = knownDataContracts; @@ -548,7 +552,7 @@ private bool CheckIfEnum(XmlSchemaSimpleTypeRestriction restriction) else if (restriction.BaseType != null) { DataContract baseContract = ImportType(restriction.BaseType); - return (baseContract.StableName == expectedBase || baseContract is EnumDataContract); + return (baseContract.XmlName == expectedBase || baseContract is EnumDataContract); } return false; @@ -644,7 +648,7 @@ private static void RemoveOptionalUnknownSerializationElements(XmlSchemaObjectCo private ClassDataContract ImportClass(XmlQualifiedName typeName, XmlSchemaSequence rootSequence, XmlQualifiedName? baseTypeName, XmlSchemaAnnotation? annotation, bool isReference) { ClassDataContract dataContract = new ClassDataContract(Globals.TypeOfSchemaDefinedType); - dataContract.StableName = typeName; + dataContract.XmlName = typeName; AddDataContract(dataContract); dataContract.IsValueType = IsValueType(typeName, annotation); @@ -658,7 +662,7 @@ private ClassDataContract ImportClass(XmlQualifiedName typeName, XmlSchemaSequen if (IsISerializableDerived(typeName, rootSequence)) dataContract.IsISerializable = true; else - ThrowTypeCannotBeImportedException(dataContract.StableName.Name, dataContract.StableName.Namespace, SR.Format(SR.DerivedTypeNotISerializable, baseTypeName.Name, baseTypeName.Namespace)); + ThrowTypeCannotBeImportedException(dataContract.XmlName.Name, dataContract.XmlName.Namespace, SR.Format(SR.DerivedTypeNotISerializable, baseTypeName.Name, baseTypeName.Namespace)); } if (dataContract.BaseClassContract.IsReference) { @@ -694,7 +698,7 @@ private DataContract ImportXmlDataType(XmlQualifiedName typeName, XmlSchemaType return xmlDataContract; xmlDataContract = new XmlDataContract(Globals.TypeOfSchemaDefinedType); - xmlDataContract.StableName = typeName; + xmlDataContract.XmlName = typeName; xmlDataContract.IsValueType = false; AddDataContract(xmlDataContract); if (xsdType != null) @@ -811,7 +815,7 @@ private static bool IsValueType(XmlQualifiedName typeName, XmlSchemaAnnotation? private ClassDataContract ImportISerializable(XmlQualifiedName typeName, XmlSchemaSequence rootSequence, XmlQualifiedName? baseTypeName, XmlSchemaObjectCollection attributes, XmlSchemaAnnotation? annotation) { ClassDataContract dataContract = new ClassDataContract(Globals.TypeOfSchemaDefinedType); - dataContract.StableName = typeName; + dataContract.XmlName = typeName; dataContract.IsISerializable = true; AddDataContract(dataContract); @@ -823,7 +827,7 @@ private ClassDataContract ImportISerializable(XmlQualifiedName typeName, XmlSche ImportBaseContract(baseTypeName, dataContract); Debug.Assert(dataContract.BaseClassContract != null); // ImportBaseContract will always set this... or throw. if (!dataContract.BaseClassContract.IsISerializable) - ThrowISerializableTypeCannotBeImportedException(dataContract.StableName.Name, dataContract.StableName.Namespace, SR.Format(SR.BaseTypeNotISerializable, baseTypeName.Name, baseTypeName.Namespace)); + ThrowISerializableTypeCannotBeImportedException(dataContract.XmlName.Name, dataContract.XmlName.Namespace, SR.Format(SR.BaseTypeNotISerializable, baseTypeName.Name, baseTypeName.Namespace)); if (!IsISerializableDerived(typeName, rootSequence)) ThrowISerializableTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ISerializableDerivedContainsOneOrMoreItems)); } @@ -887,7 +891,7 @@ private void ImportBaseContract(XmlQualifiedName baseTypeName, ClassDataContract { ClassDataContract? baseContract = ImportType(baseTypeName) as ClassDataContract; if (baseContract == null) - ThrowTypeCannotBeImportedException(dataContract.StableName.Name, dataContract.StableName.Namespace, SR.Format(dataContract.IsISerializable ? SR.InvalidISerializableDerivation : SR.InvalidClassDerivation, baseTypeName.Name, baseTypeName.Namespace)); + ThrowTypeCannotBeImportedException(dataContract.XmlName.Name, dataContract.XmlName.Namespace, SR.Format(dataContract.IsISerializable ? SR.InvalidISerializableDerivation : SR.InvalidClassDerivation, baseTypeName.Name, baseTypeName.Namespace)); // Note: code ignores IsValueType annotation if derived type exists if (baseContract.IsValueType) @@ -896,13 +900,8 @@ private void ImportBaseContract(XmlQualifiedName baseTypeName, ClassDataContract ClassDataContract? ancestorDataContract = baseContract; while (ancestorDataContract != null) { - DataContractDictionary? knownDataContracts = ancestorDataContract.KnownDataContracts; - if (knownDataContracts == null) - { - knownDataContracts = new DataContractDictionary(); - ancestorDataContract.KnownDataContracts = knownDataContracts; - } - knownDataContracts.Add(dataContract.StableName, dataContract); + DataContractDictionary knownDataContracts = ancestorDataContract.KnownDataContracts!; // Might be .Count == 0, but always non-null for ClassDataContract + knownDataContracts.Add(dataContract.XmlName, dataContract); ancestorDataContract = ancestorDataContract.BaseClassContract; } @@ -934,7 +933,7 @@ private void ImportTopLevelElement(XmlQualifiedName typeName) [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private void ImportClassMember(XmlSchemaElement element, ClassDataContract dataContract) { - XmlQualifiedName typeName = dataContract.StableName; + XmlQualifiedName typeName = dataContract.XmlName; Debug.Assert(element.Name != null); @@ -1040,7 +1039,7 @@ internal static XmlQualifiedName ImportActualType(XmlSchemaAnnotation? annotatio private CollectionDataContract ImportCollection(XmlQualifiedName typeName, XmlSchemaSequence rootSequence, XmlSchemaObjectCollection attributes, XmlSchemaAnnotation? annotation, bool isReference) { CollectionDataContract dataContract = new CollectionDataContract(Globals.TypeOfSchemaDefinedType, CollectionKind.Array); - dataContract.StableName = typeName; + dataContract.XmlName = typeName; AddDataContract(dataContract); dataContract.IsReference = isReference; @@ -1108,13 +1107,13 @@ private CollectionDataContract ImportCollection(XmlQualifiedName typeName, XmlSc dataContract.ValueName = value.Name; if (element.SchemaType != null) { - _dataContractSet.Remove(keyValueContract.StableName); + _dataContractSet.Remove(keyValueContract.XmlName); - GenericInfo genericInfo = new GenericInfo(DataContract.GetStableName(Globals.TypeOfKeyValue), Globals.TypeOfKeyValue.FullName); + GenericInfo genericInfo = new GenericInfo(DataContract.GetXmlName(Globals.TypeOfKeyValue), Globals.TypeOfKeyValue.FullName); genericInfo.Add(GetGenericInfoForDataMember(key)); genericInfo.Add(GetGenericInfoForDataMember(value)); genericInfo.AddToLevel(0, 2); - dataContract.ItemContract.StableName = new XmlQualifiedName(genericInfo.GetExpandedStableName().Name, typeName.Namespace); + dataContract.ItemContract.XmlName = new XmlQualifiedName(genericInfo.GetExpandedXmlName().Name, typeName.Namespace); } } @@ -1127,12 +1126,12 @@ private static GenericInfo GetGenericInfoForDataMember(DataMember dataMember) GenericInfo genericInfo; if (dataMember.MemberTypeContract.IsValueType && dataMember.IsNullable) { - genericInfo = new GenericInfo(DataContract.GetStableName(Globals.TypeOfNullable), Globals.TypeOfNullable.FullName); - genericInfo.Add(new GenericInfo(dataMember.MemberTypeContract.StableName, null)); + genericInfo = new GenericInfo(DataContract.GetXmlName(Globals.TypeOfNullable), Globals.TypeOfNullable.FullName); + genericInfo.Add(new GenericInfo(dataMember.MemberTypeContract.XmlName, null)); } else { - genericInfo = new GenericInfo(dataMember.MemberTypeContract.StableName, null); + genericInfo = new GenericInfo(dataMember.MemberTypeContract.XmlName, null); } return genericInfo; @@ -1181,7 +1180,7 @@ private static bool IsDictionary(XmlQualifiedName typeName, XmlSchemaAnnotation? private EnumDataContract ImportEnum(XmlQualifiedName typeName, XmlSchemaSimpleTypeRestriction restriction, bool isFlags, XmlSchemaAnnotation? annotation) { EnumDataContract dataContract = new EnumDataContract(Globals.TypeOfSchemaDefinedType); - dataContract.StableName = typeName; + dataContract.XmlName = typeName; dataContract.BaseContractName = ImportActualType(annotation, SchemaExporter.DefaultEnumBaseTypeName, typeName); dataContract.IsFlags = isFlags; AddDataContract(dataContract); @@ -1388,7 +1387,7 @@ private static bool TryCheckIfAttribute(XmlQualifiedName typeName, XmlSchemaAttr [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private void AddDataContract(DataContract dataContract) { - _dataContractSet.Add(dataContract.StableName, dataContract); + _dataContractSet.Add(dataContract.XmlName, dataContract); } private static string? GetInnerText(XmlQualifiedName typeName, XmlElement? xmlElement) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ScopedKnownTypes.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ScopedKnownTypes.cs index ebf0d78e87b59..149a661a95bff 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ScopedKnownTypes.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ScopedKnownTypes.cs @@ -2,9 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Runtime.Serialization.DataContracts; using System.Xml; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SpecialTypeDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SpecialTypeDataContract.cs index 010871e02e13a..978de94bae99d 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SpecialTypeDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SpecialTypeDataContract.cs @@ -4,7 +4,7 @@ using System.Diagnostics.CodeAnalysis; using System.Xml; -namespace System.Runtime.Serialization +namespace System.Runtime.Serialization.DataContracts { internal sealed class SpecialTypeDataContract : DataContract { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SurrogateDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SurrogateDataContract.cs index 199d62050bc2b..77a2e181052fd 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SurrogateDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SurrogateDataContract.cs @@ -7,7 +7,7 @@ using System.Runtime.CompilerServices; using System.Security; -namespace System.Runtime.Serialization +namespace System.Runtime.Serialization.DataContracts { internal sealed class SurrogateDataContract : DataContract { @@ -92,7 +92,7 @@ internal SurrogateDataContractCriticalHelper( { this.serializationSurrogate = serializationSurrogate; string name, ns; - DataContract.GetDefaultStableName(DataContract.GetClrTypeFullName(type), out name, out ns); + DataContract.GetDefaultXmlName(DataContract.GetClrTypeFullName(type), out name, out ns); SetDataContractName(CreateQualifiedName(name, ns)); } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XPathQueryGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XPathQueryGenerator.cs index 469685278a86f..2fac683e1d727 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XPathQueryGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XPathQueryGenerator.cs @@ -2,12 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Text; -using System.Reflection; -using System.Globalization; using System.Collections.Generic; -using System.Xml; using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Reflection; +using System.Runtime.Serialization.DataContracts; +using System.Text; +using System.Xml; namespace System.Runtime.Serialization { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs index d9d66185046e5..c0066d6d42850 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs @@ -13,9 +13,9 @@ using System.Xml.Schema; using System.Xml.Serialization; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; -namespace System.Runtime.Serialization +namespace System.Runtime.Serialization.DataContracts { internal delegate IXmlSerializable CreateXmlSerializableDelegate(); public sealed class XmlDataContract : DataContract @@ -35,7 +35,7 @@ public override DataContractDictionary? KnownDataContracts { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] get => _helper.KnownDataContracts; - set => _helper.KnownDataContracts = value; + internal set => _helper.KnownDataContracts = value; } public XmlSchemaType? XsdType @@ -139,21 +139,21 @@ internal XmlDataContractCriticalHelper( throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.IXmlSerializableCannotHaveCollectionDataContract, DataContract.GetClrTypeFullName(type)))); bool hasRoot; XmlSchemaType? xsdType; - XmlQualifiedName stableName; - SchemaExporter.GetXmlTypeInfo(type, out stableName, out xsdType, out hasRoot); - StableName = stableName; + XmlQualifiedName xmlName; + SchemaExporter.GetXmlTypeInfo(type, out xmlName, out xsdType, out hasRoot); + XmlName = xmlName; XsdType = xsdType; HasRoot = hasRoot; XmlDictionary dictionary = new XmlDictionary(); - Name = dictionary.Add(StableName.Name); - Namespace = dictionary.Add(StableName.Namespace); + Name = dictionary.Add(XmlName.Name); + Namespace = dictionary.Add(XmlName.Namespace); object[]? xmlRootAttributes = UnderlyingType?.GetCustomAttributes(Globals.TypeOfXmlRootAttribute, false).ToArray(); if (xmlRootAttributes == null || xmlRootAttributes.Length == 0) { if (hasRoot) { _topLevelElementName = Name; - _topLevelElementNamespace = (this.StableName.Namespace == Globals.SchemaNamespace) ? DictionaryGlobals.EmptyString : Namespace; + _topLevelElementNamespace = (this.XmlName.Namespace == Globals.SchemaNamespace) ? DictionaryGlobals.EmptyString : Namespace; _isTopLevelElementNullable = true; } } @@ -190,6 +190,7 @@ internal override DataContractDictionary? KnownDataContracts Interlocked.MemoryBarrier(); _isKnownTypeAttributeChecked = true; } + _knownDataContracts ??= new DataContractDictionary(); } } return _knownDataContracts; @@ -394,7 +395,7 @@ internal override bool Equals(object? other, HashSet checke } else { - return (StableName.Name == dataContract.StableName.Name && StableName.Namespace == dataContract.StableName.Namespace); + return (XmlName.Name == dataContract.XmlName.Name && XmlName.Namespace == dataContract.XmlName.Namespace); } } return false; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatGeneratorStatics.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatGeneratorStatics.cs index ba1a955f8044d..ec6392e62e7c3 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatGeneratorStatics.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatGeneratorStatics.cs @@ -1,11 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Reflection; -using System.Xml; using System.Collections; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Runtime.Serialization.DataContracts; +using System.Xml; namespace System.Runtime.Serialization { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs index eab43fba40bde..5144ee966b5ed 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs @@ -2,17 +2,18 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Xml; -using System.Xml.Schema; -using System.Reflection; -using System.Reflection.Emit; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Security; +using System.Reflection; +using System.Reflection.Emit; using System.Runtime.CompilerServices; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization.DataContracts; +using System.Security; +using System.Xml; +using System.Xml.Schema; namespace System.Runtime.Serialization { @@ -83,7 +84,7 @@ public XmlFormatClassReaderDelegate GenerateClassReader(ClassDataContract classC bool memberAccessFlag = classContract.RequiresMemberAccessForRead(null); try { - _ilg.BeginMethod("Read" + classContract.StableName.Name + "FromXml", Globals.TypeOfXmlFormatClassReaderDelegate, memberAccessFlag); + _ilg.BeginMethod("Read" + classContract.XmlName.Name + "FromXml", Globals.TypeOfXmlFormatClassReaderDelegate, memberAccessFlag); } catch (SecurityException securityException) { @@ -206,11 +207,11 @@ private CodeGenerator GenerateCollectionReaderHelper(CollectionDataContract coll { if (isGetOnlyCollection) { - _ilg.BeginMethod("Read" + collectionContract.StableName.Name + "FromXml" + "IsGetOnly", Globals.TypeOfXmlFormatGetOnlyCollectionReaderDelegate, memberAccessFlag); + _ilg.BeginMethod("Read" + collectionContract.XmlName.Name + "FromXml" + "IsGetOnly", Globals.TypeOfXmlFormatGetOnlyCollectionReaderDelegate, memberAccessFlag); } else { - _ilg.BeginMethod("Read" + collectionContract.StableName.Name + "FromXml" + string.Empty, Globals.TypeOfXmlFormatCollectionReaderDelegate, memberAccessFlag); + _ilg.BeginMethod("Read" + collectionContract.XmlName.Name + "FromXml" + string.Empty, Globals.TypeOfXmlFormatCollectionReaderDelegate, memberAccessFlag); } } catch (SecurityException securityException) @@ -429,12 +430,12 @@ private int ReadMembers(ClassDataContract classContract, bool[] requiredMembers, value = _ilg.DeclareLocal(memberType, dataMember.Name + "Value"); _ilg.Stloc(value); _ilg.Call(_contextArg, XmlFormatGeneratorStatics.StoreCollectionMemberInfoMethod, value); - ReadValue(memberType, dataMember.Name, classContract.StableName.Namespace); + ReadValue(memberType, dataMember.Name, classContract.XmlName.Namespace); } else { _ilg.Call(_contextArg, XmlFormatGeneratorStatics.ResetCollectionMemberInfoMethod); - value = ReadValue(memberType, dataMember.Name, classContract.StableName.Namespace); + value = ReadValue(memberType, dataMember.Name, classContract.XmlName.Namespace); _ilg.LoadAddress(_objectLocal); _ilg.ConvertAddress(_objectLocal.LocalType, _objectType); _ilg.Ldloc(value); @@ -645,7 +646,7 @@ private void ReadCollection(CollectionDataContract collectionContract) } } string itemName = collectionContract.ItemName; - string itemNs = collectionContract.StableName.Namespace; + string itemNs = collectionContract.XmlName.Namespace; _objectLocal = _ilg.DeclareLocal(type, "objectDeserialized"); if (!isArray) @@ -760,7 +761,7 @@ private void ReadGetOnlyCollection(CollectionDataContract collectionContract) Type itemType = collectionContract.ItemType; bool isArray = (collectionContract.Kind == CollectionKind.Array); string itemName = collectionContract.ItemName; - string itemNs = collectionContract.StableName.Namespace; + string itemNs = collectionContract.XmlName.Namespace; _objectLocal = _ilg.DeclareLocal(type, "objectDeserialized"); _ilg.Load(_contextArg); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs index 0e984e1a3adb3..2d49e4b023b47 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs @@ -2,17 +2,18 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Xml; -using System.Xml.Schema; -using System.Reflection; -using System.Reflection.Emit; using System.Collections; using System.Collections.Generic; -using System.Globalization; -using System.Security; -using System.Runtime.CompilerServices; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.CompilerServices; +using System.Runtime.Serialization.DataContracts; +using System.Security; +using System.Xml; +using System.Xml.Schema; namespace System.Runtime.Serialization { @@ -78,7 +79,7 @@ internal XmlFormatClassWriterDelegate GenerateClassWriter(ClassDataContract clas bool memberAccessFlag = classContract.RequiresMemberAccessForWrite(null); try { - _ilg.BeginMethod("Write" + classContract.StableName.Name + "ToXml", Globals.TypeOfXmlFormatClassWriterDelegate, memberAccessFlag); + _ilg.BeginMethod("Write" + classContract.XmlName.Name + "ToXml", Globals.TypeOfXmlFormatClassWriterDelegate, memberAccessFlag); } catch (SecurityException securityException) { @@ -120,7 +121,7 @@ internal XmlFormatCollectionWriterDelegate GenerateCollectionWriter(CollectionDa bool memberAccessFlag = collectionContract.RequiresMemberAccessForWrite(null); try { - _ilg.BeginMethod("Write" + collectionContract.StableName.Name + "ToXml", Globals.TypeOfXmlFormatCollectionWriterDelegate, memberAccessFlag); + _ilg.BeginMethod("Write" + collectionContract.XmlName.Name + "ToXml", Globals.TypeOfXmlFormatCollectionWriterDelegate, memberAccessFlag); } catch (SecurityException securityException) { @@ -781,11 +782,11 @@ private static bool CheckIfMemberHasConflict(DataMember member, ClassDataContrac // Check for conflict with derived type members string name = member.Name; - string ns = classContract.StableName.Namespace; + string ns = classContract.XmlName.Namespace; ClassDataContract? currentContract = derivedMostClassContract; while (currentContract != null && currentContract != classContract) { - if (ns == currentContract.StableName.Namespace) + if (ns == currentContract.XmlName.Namespace) { List members = currentContract.Members!; for (int j = 0; j < members.Count; j++) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializer.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializer.cs index 9e43885574c57..e656e9b259c83 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializer.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializer.cs @@ -7,11 +7,12 @@ using System.Globalization; using System.IO; using System.Runtime.CompilerServices; +using System.Runtime.Serialization.DataContracts; using System.Security; using System.Text; using System.Xml; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs index d9bbe2b0d4dff..57b3353cee2cb 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerContext.cs @@ -6,10 +6,11 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; +using System.Runtime.Serialization.DataContracts; using System.Security; using System.Xml; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization { @@ -195,7 +196,7 @@ internal virtual DataContractDictionary? SerializerKnownDataContracts internal bool IsKnownType(DataContract dataContract, DataContractDictionary? knownDataContracts, Type? declaredType) { bool knownTypesAddedInCurrentScope = false; - if (knownDataContracts != null) + if (knownDataContracts?.Count > 0) { scopedKnownTypes.Push(knownDataContracts); knownTypesAddedInCurrentScope = true; @@ -213,7 +214,7 @@ internal bool IsKnownType(DataContract dataContract, DataContractDictionary? kno [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal bool IsKnownType(DataContract dataContract, Type? declaredType) { - DataContract? knownContract = ResolveDataContractFromKnownTypes(dataContract.StableName.Name, dataContract.StableName.Namespace, null /*memberTypeContract*/, declaredType); + DataContract? knownContract = ResolveDataContractFromKnownTypes(dataContract.XmlName.Name, dataContract.XmlName.Namespace, null /*memberTypeContract*/, declaredType); return knownContract != null && knownContract.UnderlyingType == dataContract.UnderlyingType; } @@ -248,13 +249,13 @@ internal bool IsKnownType(DataContract dataContract, Type? declaredType) { if (memberTypeContract != null && !memberTypeContract.UnderlyingType.IsInterface - && memberTypeContract.StableName == qname) + && memberTypeContract.XmlName == qname) { dataContract = memberTypeContract; } if (dataContract == null && rootTypeDataContract != null) { - if (rootTypeDataContract.StableName == qname) + if (rootTypeDataContract.XmlName == qname) dataContract = rootTypeDataContract; else dataContract = ResolveDataContractFromRootDataContract(qname); @@ -270,7 +271,7 @@ internal bool IsKnownType(DataContract dataContract, Type? declaredType) while (collectionContract != null) { DataContract itemContract = GetDataContract(GetSurrogatedType(collectionContract.ItemType)); - if (itemContract.StableName == typeQName) + if (itemContract.XmlName == typeQName) { return itemContract; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContext.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContext.cs index b310d9d075bb5..ed546bc93ee99 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContext.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContext.cs @@ -6,12 +6,13 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization.DataContracts; using System.Security; using System.Text; using System.Xml; using System.Xml.Serialization; -using DataContractDictionary = System.Collections.Generic.Dictionary; +using DataContractDictionary = System.Collections.Generic.Dictionary; namespace System.Runtime.Serialization { @@ -138,7 +139,7 @@ protected bool TryHandleNullOrRef(XmlReaderDelegator reader, Type declaredType, return retObj; bool knownTypesAddedInCurrentScope = false; - if (dataContract.KnownDataContracts != null) + if (dataContract.KnownDataContracts?.Count > 0) { scopedKnownTypes.Push(dataContract.KnownDataContracts); knownTypesAddedInCurrentScope = true; @@ -197,7 +198,7 @@ private bool ReplaceScopedKnownTypesTop(DataContractDictionary? knownDataContrac scopedKnownTypes.Pop(); knownTypesAddedInCurrentScope = false; } - if (knownDataContracts != null) + if (knownDataContracts?.Count > 0) { scopedKnownTypes.Push(knownDataContracts); knownTypesAddedInCurrentScope = true; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContextComplex.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContextComplex.cs index 333a0d400a247..7458857221d20 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContextComplex.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerReadContextComplex.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; +using System.Runtime.Serialization.DataContracts; namespace System.Runtime.Serialization { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerWriteContext.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerWriteContext.cs index 317e2638cb4dc..9abdced84b6e2 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerWriteContext.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerWriteContext.cs @@ -3,18 +3,20 @@ using System; using System.Collections; +using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.Serialization.DataContracts; +using System.Security; using System.Text; using System.Xml; -using System.Collections.Generic; using System.Xml.Serialization; -using System.Security; -using System.Runtime.CompilerServices; + using ExtensionDataObject = System.Object; -using System.Diagnostics.CodeAnalysis; namespace System.Runtime.Serialization { @@ -122,7 +124,7 @@ internal void SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelega { if (OnHandleIsReference(xmlWriter, dataContract, obj)) return; - if (dataContract.KnownDataContracts != null) + if (dataContract.KnownDataContracts?.Count > 0) { scopedKnownTypes.Push(dataContract.KnownDataContracts); WriteDataContractValue(dataContract, xmlWriter, obj, declaredTypeHandle); @@ -224,7 +226,7 @@ internal bool OnHandleIsReference(XmlWriterDelegator xmlWriter, DataContract con protected void SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, object obj, bool verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType) { bool knownTypesAddedInCurrentScope = false; - if (dataContract.KnownDataContracts != null) + if (dataContract.KnownDataContracts?.Count > 0) { scopedKnownTypes.Push(dataContract.KnownDataContracts); knownTypesAddedInCurrentScope = true; @@ -234,10 +236,10 @@ protected void SerializeAndVerifyType(DataContract dataContract, XmlWriterDelega { if (!IsKnownType(dataContract, declaredType)) { - DataContract? knownContract = ResolveDataContractFromKnownTypes(dataContract.StableName.Name, dataContract.StableName.Namespace, null /*memberTypeContract*/, declaredType); + DataContract? knownContract = ResolveDataContractFromKnownTypes(dataContract.XmlName.Name, dataContract.XmlName.Namespace, null /*memberTypeContract*/, declaredType); if (knownContract == null || knownContract.UnderlyingType != dataContract.UnderlyingType) { - throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.DcTypeNotFoundOnSerialize, DataContract.GetClrTypeFullName(dataContract.UnderlyingType), dataContract.StableName.Name, dataContract.StableName.Namespace))); + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.Format(SR.DcTypeNotFoundOnSerialize, DataContract.GetClrTypeFullName(dataContract.UnderlyingType), dataContract.XmlName.Name, dataContract.XmlName.Namespace))); } } } @@ -527,7 +529,7 @@ internal void WriteSerializationInfo(XmlWriterDelegator xmlWriter, Type objType, else { string typeName, typeNs; - DataContract.GetDefaultStableName(serInfo.FullTypeName, out typeName, out typeNs); + DataContract.GetDefaultXmlName(serInfo.FullTypeName, out typeName, out typeNs); xmlWriter.WriteAttributeQualifiedName(Globals.SerPrefix, DictionaryGlobals.ISerializableFactoryTypeLocalName, DictionaryGlobals.SerializationNamespace, DataContract.GetClrTypeString(typeName), DataContract.GetClrTypeString(typeNs)); } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerWriteContextComplex.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerWriteContextComplex.cs index c71bc9d1b168a..1d9ebcb41ddd0 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerWriteContextComplex.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlObjectSerializerWriteContextComplex.cs @@ -3,16 +3,17 @@ using System; using System.Collections; +using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.Serialization.DataContracts; +using System.Security; using System.Text; using System.Xml; -using System.Collections.Generic; -using System.Security; -using System.Runtime.CompilerServices; -using System.Diagnostics.CodeAnalysis; namespace System.Runtime.Serialization { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlReaderDelegator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlReaderDelegator.cs index f8427dc8f2834..a05d18e8f32df 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlReaderDelegator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlReaderDelegator.cs @@ -1,11 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Xml; -using System.Globalization; using System.Collections.Generic; -using System.Xml.Serialization; using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Runtime.Serialization.DataContracts; +using System.Xml; +using System.Xml.Serialization; namespace System.Runtime.Serialization { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlSerializableWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlSerializableWriter.cs index 8dc67936bf496..1b9c39249c6ba 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlSerializableWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlSerializableWriter.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Runtime.Serialization.DataContracts; using System.Xml; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlWriterDelegator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlWriterDelegator.cs index ec08e05117772..9873c19c40abb 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlWriterDelegator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlWriterDelegator.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Xml; +using System.Runtime.Serialization.DataContracts; using System.Globalization; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs index 3158b1fd98619..8cc82bbb2ed98 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs @@ -1,42 +1,73 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Xml; -using System.Xml.Schema; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Reflection; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Runtime.Serialization.DataContracts; +using System.Xml; +using System.Xml.Schema; namespace System.Runtime.Serialization { + /// + /// Allows the transformation of a set of .NET types that are used in data contracts into an XML schema file (.xsd). + /// + /// + /// Use the class when you have created a Web service that incorporates data represented by + /// runtime types and when you need to export XML schemas for each type to be consumed by other Web services. + /// That is, transforms a set of runtime types into XML schemas. The schemas can then be exposed + /// through a Web Services Description Language (WSDL) document for use by others who need to interoperate with your service. + /// + /// Conversely, if you are creating a Web service that must interoperate with an existing Web service, use the XsdDataContractImporter + /// to transform XML schemas and create the runtime types that represent the data in a selected programming language. + /// + /// The generates an object that contains the collection of schemas. + /// Access the set of schemas through the property. + /// public class XsdDataContractExporter { private ExportOptions? _options; private XmlSchemaSet? _schemas; private DataContractSet? _dataContractSet; + /// + /// Initializes a new instance of the class. + /// public XsdDataContractExporter() { } + /// + /// Initializes a new instance of the class with the specified set of schemas. + /// + /// An that contains the schemas to be exported. public XsdDataContractExporter(XmlSchemaSet? schemas) { - this._schemas = schemas; + _schemas = schemas; } + /// + /// Gets or sets an that contains options that can be set for the export operation. + /// public ExportOptions? Options { get { return _options; } set { _options = value; } } + /// + /// Gets the collection of exported XML schemas. + /// public XmlSchemaSet Schemas { get { - throw new PlatformNotSupportedException(SR.PlatformNotSupported_SchemaImporter); + XmlSchemaSet schemaSet = GetSchemaSet(); + SchemaImporter.CompileSchemaSet(schemaSet); + return schemaSet; } } @@ -50,17 +81,28 @@ private XmlSchemaSet GetSchemaSet() return _schemas; } - private static DataContractSet DataContractSet + private DataContractSet DataContractSet { get { - // On .NET Framework , we set _dataContractSet = Options.GetSurrogate()); - // But Options.GetSurrogate() is not available on NetCore because IDataContractSurrogate - // is not in NetStandard. - throw new PlatformNotSupportedException(SR.PlatformNotSupported_IDataContractSurrogate); + if (_dataContractSet == null) + { + _dataContractSet = new DataContractSet(Options?.DataContractSurrogate, null, null); + } + return _dataContractSet; } } + private static void EnsureTypeNotGeneric(Type type) + { + if (type.ContainsGenericParameters) + throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericTypeNotExportable, type))); + } + + /// + /// Transforms the types contained in the specified collection of assemblies. + /// + /// A (of ) that contains the types to export. [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] public void Export(ICollection assemblies) { @@ -88,6 +130,10 @@ public void Export(ICollection assemblies) } } + /// + /// Transforms the types contained in the passed to this method. + /// + /// A (of ) that contains the types to export. [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] public void Export(ICollection types) { @@ -112,6 +158,10 @@ public void Export(ICollection types) } } + /// + /// Transforms the specified .NET Framework type into an XML schema definition language (XSD) schema. + /// + /// The to transform into an XML schema. [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] public void Export(Type type) { @@ -130,6 +180,11 @@ public void Export(Type type) } } + /// + /// Returns the contract name and contract namespace for the . + /// + /// The that was exported. + /// An that represents the contract name of the type and its namespace. [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] public XmlQualifiedName GetSchemaTypeName(Type type) { @@ -137,12 +192,17 @@ public XmlQualifiedName GetSchemaTypeName(Type type) type = GetSurrogatedType(type); DataContract dataContract = DataContract.GetDataContract(type); - DataContractSet.EnsureTypeNotGeneric(dataContract.UnderlyingType); + EnsureTypeNotGeneric(dataContract.UnderlyingType); if (dataContract is XmlDataContract xmlDataContract && xmlDataContract.IsAnonymous) return XmlQualifiedName.Empty; - return dataContract.StableName; + return dataContract.XmlName; } + /// + /// Returns the XML schema type for the specified type. + /// + /// The type to return a schema for. + /// An that contains the XML schema. [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] public XmlSchemaType? GetSchemaType(Type type) { @@ -150,12 +210,17 @@ public XmlQualifiedName GetSchemaTypeName(Type type) type = GetSurrogatedType(type); DataContract dataContract = DataContract.GetDataContract(type); - DataContractSet.EnsureTypeNotGeneric(dataContract.UnderlyingType); + EnsureTypeNotGeneric(dataContract.UnderlyingType); if (dataContract is XmlDataContract xmlDataContract && xmlDataContract.IsAnonymous) return xmlDataContract.XsdType; return null; } + /// + /// Returns the top-level name and namespace for the . + /// + /// The to query. + /// The that represents the top-level name and namespace for this Type, which is written to the stream when writing this object. [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] public XmlQualifiedName? GetRootElementName(Type type) { @@ -163,8 +228,8 @@ public XmlQualifiedName GetSchemaTypeName(Type type) type = GetSurrogatedType(type); DataContract dataContract = DataContract.GetDataContract(type); - DataContractSet.EnsureTypeNotGeneric(dataContract.UnderlyingType); - if (dataContract.HasRoot) + EnsureTypeNotGeneric(dataContract.UnderlyingType); + if (dataContract is not XmlDataContract xdc || xdc.HasRoot) // All non-XmlDataContracts "have root". { return new XmlQualifiedName(dataContract.TopLevelElementName!.Value, dataContract.TopLevelElementNamespace!.Value); } @@ -174,13 +239,17 @@ public XmlQualifiedName GetSchemaTypeName(Type type) } } - private static Type GetSurrogatedType(Type type) + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + private Type GetSurrogatedType(Type type) { + ISerializationSurrogateProvider? surrogate = Options?.DataContractSurrogate; + if (surrogate != null) + type = DataContractSurrogateCaller.GetDataContractType(surrogate, type); return type; } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private static void CheckAndAddType(Type type) + private void CheckAndAddType(Type type) { type = GetSurrogatedType(type); if (!type.ContainsGenericParameters && DataContract.IsTypeSerializable(type)) @@ -188,7 +257,7 @@ private static void CheckAndAddType(Type type) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - private static void AddType(Type type) + private void AddType(Type type) { DataContractSet.Add(type); } @@ -197,8 +266,8 @@ private static void AddType(Type type) private void Export() { AddKnownTypes(); - SchemaExporter schemaExporter = new SchemaExporter(GetSchemaSet(), DataContractSet); - schemaExporter.Export(); + SchemaExporter exporter = new SchemaExporter(GetSchemaSet(), DataContractSet); + exporter.Export(); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -221,6 +290,11 @@ private void AddKnownTypes() } } + /// + /// Gets a value that indicates whether the set of runtime types contained in a set of assemblies can be exported. + /// + /// A of that contains the assemblies with the types to export. + /// true if the types can be exported; otherwise, false. [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] public bool CanExport(ICollection assemblies) { @@ -253,6 +327,11 @@ public bool CanExport(ICollection assemblies) } } + /// + /// Gets a value that indicates whether the set of runtime types contained in a can be exported. + /// + /// A that contains the specified types to export. + /// true if the types can be exported; otherwise, false. [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] public bool CanExport(ICollection types) { @@ -282,6 +361,11 @@ public bool CanExport(ICollection types) } } + /// + /// Gets a value that indicates whether the specified runtime type can be exported. + /// + /// The to export. + /// true if the type can be exported; otherwise, false. [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] public bool CanExport(Type type) { diff --git a/src/libraries/System.Runtime.Serialization.Json/ref/System.Runtime.Serialization.Json.cs b/src/libraries/System.Runtime.Serialization.Json/ref/System.Runtime.Serialization.Json.cs index ba4b193c89311..668170766c98c 100644 --- a/src/libraries/System.Runtime.Serialization.Json/ref/System.Runtime.Serialization.Json.cs +++ b/src/libraries/System.Runtime.Serialization.Json/ref/System.Runtime.Serialization.Json.cs @@ -46,6 +46,8 @@ public DataContractJsonSerializer(System.Type type, System.Xml.XmlDictionaryStri public int MaxItemsInObjectGraph { get { throw null; } } public bool SerializeReadOnlyTypes { get { throw null; } } public bool UseSimpleDictionaryFormat { get { throw null; } } + public System.Runtime.Serialization.ISerializationSurrogateProvider? GetSerializationSurrogateProvider() { throw null; } + public void SetSerializationSurrogateProvider(System.Runtime.Serialization.ISerializationSurrogateProvider? provider) { } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public override bool IsStartObject(System.Xml.XmlDictionaryReader reader) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] @@ -79,11 +81,6 @@ public override void WriteStartObject(System.Xml.XmlDictionaryWriter writer, obj [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public override void WriteStartObject(System.Xml.XmlWriter writer, object? graph) { } } - public static partial class DataContractJsonSerializerExtensions - { - public static System.Runtime.Serialization.ISerializationSurrogateProvider? GetSerializationSurrogateProvider(this System.Runtime.Serialization.Json.DataContractJsonSerializer serializer) { throw null; } - public static void SetSerializationSurrogateProvider(this System.Runtime.Serialization.Json.DataContractJsonSerializer serializer, System.Runtime.Serialization.ISerializationSurrogateProvider? provider) { } - } public partial class DataContractJsonSerializerSettings { public DataContractJsonSerializerSettings() { } diff --git a/src/libraries/System.Runtime.Serialization.Primitives/ref/System.Runtime.Serialization.Primitives.cs b/src/libraries/System.Runtime.Serialization.Primitives/ref/System.Runtime.Serialization.Primitives.cs index 043023f6bdcfa..e57d5032e1c72 100644 --- a/src/libraries/System.Runtime.Serialization.Primitives/ref/System.Runtime.Serialization.Primitives.cs +++ b/src/libraries/System.Runtime.Serialization.Primitives/ref/System.Runtime.Serialization.Primitives.cs @@ -78,10 +78,10 @@ public partial interface ISerializationSurrogateProvider object GetObjectToSerialize(object obj, System.Type targetType); System.Type GetSurrogateType(System.Type type); } - public interface ISerializationExtendedSurrogateProvider : ISerializationSurrogateProvider + public interface ISerializationSurrogateProvider2 : ISerializationSurrogateProvider { object? GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType); - object? GetCustomDataToExport(Type clrType, Type dataContractType); + object? GetCustomDataToExport(Type runtimeType, Type dataContractType); void GetKnownCustomDataTypes(Collection customDataTypes); Type? GetReferencedTypeOnImport(string typeName, string typeNamespace, object? customData); } diff --git a/src/libraries/System.Runtime.Serialization.Primitives/src/System.Runtime.Serialization.Primitives.csproj b/src/libraries/System.Runtime.Serialization.Primitives/src/System.Runtime.Serialization.Primitives.csproj index cdadada2f3fea..bd7267ae26b97 100644 --- a/src/libraries/System.Runtime.Serialization.Primitives/src/System.Runtime.Serialization.Primitives.csproj +++ b/src/libraries/System.Runtime.Serialization.Primitives/src/System.Runtime.Serialization.Primitives.csproj @@ -11,7 +11,7 @@ - + diff --git a/src/libraries/System.Runtime.Serialization.Primitives/src/System/Runtime/Serialization/ISerializationExtendedSurrogateProvider.cs b/src/libraries/System.Runtime.Serialization.Primitives/src/System/Runtime/Serialization/ISerializationSurrogateProvider2.cs similarity index 75% rename from src/libraries/System.Runtime.Serialization.Primitives/src/System/Runtime/Serialization/ISerializationExtendedSurrogateProvider.cs rename to src/libraries/System.Runtime.Serialization.Primitives/src/System/Runtime/Serialization/ISerializationSurrogateProvider2.cs index 857544cd2c88e..0d53dff2f33f0 100644 --- a/src/libraries/System.Runtime.Serialization.Primitives/src/System/Runtime/Serialization/ISerializationExtendedSurrogateProvider.cs +++ b/src/libraries/System.Runtime.Serialization.Primitives/src/System/Runtime/Serialization/ISerializationSurrogateProvider2.cs @@ -6,10 +6,10 @@ namespace System.Runtime.Serialization { - public interface ISerializationExtendedSurrogateProvider : ISerializationSurrogateProvider + public interface ISerializationSurrogateProvider2 : ISerializationSurrogateProvider { object? GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType); - object? GetCustomDataToExport(Type clrType, Type dataContractType); + object? GetCustomDataToExport(Type runtimeType, Type dataContractType); void GetKnownCustomDataTypes(Collection customDataTypes); Type? GetReferencedTypeOnImport(string typeName, string typeNamespace, object? customData); } diff --git a/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.cs b/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.cs index 2316e6b0677c5..5f1c074aaf6dd 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/ref/System.Runtime.Serialization.Schema.cs @@ -4,53 +4,32 @@ // Changes to this file must follow the https://aka.ms/api-review process. // ------------------------------------------------------------------------------ -namespace System.Runtime.Serialization.Schema +namespace System.Runtime.Serialization { - public sealed partial class ExportOptions + public partial interface ISerializationCodeDomSurrogateProvider { - public System.Collections.ObjectModel.Collection KnownTypes { get { throw null; } } - public ISerializationSurrogateProvider? SurrogateProvider { get { throw null; } set { throw null; } } + System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit); } - public sealed partial class ImportOptions + public partial class ImportOptions { public System.CodeDom.Compiler.CodeDomProvider? CodeProvider { get { throw null; } set { throw null; } } public bool EnableDataBinding { get { throw null; } set { throw null; } } - public ISerializationSurrogateProvider? SurrogateProvider { get { throw null; } set { throw null; } } + public ISerializationSurrogateProvider? DataContractSurrogate { get { throw null; } set { throw null; } } public bool GenerateInternal { get { throw null; } set { throw null; } } public bool GenerateSerializable { get { throw null; } set { throw null; } } public bool ImportXmlType { get { throw null; } set { throw null; } } public System.Collections.Generic.IDictionary Namespaces { get { throw null; } } - public Func? ProcessImportedType; public System.Collections.Generic.ICollection ReferencedCollectionTypes { get { throw null; } } public System.Collections.Generic.ICollection ReferencedTypes { get { throw null; } } } - public sealed partial class XsdDataContractExporter - { - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public bool CanExport(System.Collections.Generic.ICollection assemblies) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public bool CanExport(System.Collections.Generic.ICollection types) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public bool CanExport(Type type) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public void Export(System.Collections.Generic.ICollection assemblies) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public void Export(System.Collections.Generic.ICollection types) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public void Export(Type type) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public System.Xml.XmlQualifiedName? GetRootElementName(Type type) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public System.Xml.Schema.XmlSchemaType? GetSchemaType(Type type) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public System.Xml.XmlQualifiedName GetSchemaTypeName(Type type) { throw null; } - public ExportOptions? Options { get { throw null; } set { throw null; } } - public System.Xml.Schema.XmlSchemaSet Schemas { get { throw null; } } - public XsdDataContractExporter() { throw null; } - public XsdDataContractExporter(System.Xml.Schema.XmlSchemaSet? schemas) { throw null; } - } - public sealed partial class XsdDataContractImporter + public partial class XsdDataContractImporter { + public XsdDataContractImporter() { throw null; } + public XsdDataContractImporter(System.CodeDom.CodeCompileUnit codeCompileUnit) { throw null; } + + public System.CodeDom.CodeCompileUnit CodeCompileUnit { get { throw null; } } + public ImportOptions? Options { get { throw null; } set { throw null; } } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public bool CanImport(System.Xml.Schema.XmlSchemaSet schemas) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] @@ -59,7 +38,6 @@ public sealed partial class XsdDataContractImporter public bool CanImport(System.Xml.Schema.XmlSchemaSet schemas, System.Xml.XmlQualifiedName typeName) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public bool CanImport(System.Xml.Schema.XmlSchemaSet schemas, System.Xml.Schema.XmlSchemaElement element) { throw null; } - public System.CodeDom.CodeCompileUnit CodeCompileUnit { get { throw null; } } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public System.CodeDom.CodeTypeReference GetCodeTypeReference(System.Xml.XmlQualifiedName typeName) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] @@ -74,8 +52,5 @@ public sealed partial class XsdDataContractImporter public void Import(System.Xml.Schema.XmlSchemaSet schemas, System.Xml.XmlQualifiedName typeName) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] public System.Xml.XmlQualifiedName? Import(System.Xml.Schema.XmlSchemaSet schemas, System.Xml.Schema.XmlSchemaElement element) { throw null; } - public ImportOptions? Options { get { throw null; } set { throw null; } } - public XsdDataContractImporter() { throw null; } - public XsdDataContractImporter(System.CodeDom.CodeCompileUnit codeCompileUnit) { throw null; } } } diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj b/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj index a4c8ca0b8ac07..1629d7f071f76 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj @@ -18,11 +18,10 @@ System.Runtime.Serialization.Schema.XsdDataContractImporter - - + + - - + diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs index 2989fec643feb..7de43e0371495 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs @@ -11,17 +11,17 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection; -using System.Runtime.Serialization; +using System.Runtime.Serialization.DataContracts; using System.Security; using System.Text; using System.Xml; using System.Xml.Schema; using System.Xml.Serialization; -using DataContractDictionary = System.Collections.Generic.Dictionary; -using ExceptionUtil = System.Runtime.Serialization.Schema.DiagnosticUtility.ExceptionUtility; +using DataContractDictionary = System.Collections.Generic.Dictionary; +using ExceptionUtil = System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility; -namespace System.Runtime.Serialization.Schema +namespace System.Runtime.Serialization { internal sealed class CodeExporter { @@ -30,7 +30,7 @@ internal sealed class CodeExporter private const int MaxIdentifierLength = 511; private static readonly object s_codeUserDataActualTypeKey = new object(); - private static readonly object s_surrogateDataKey = typeof(ISerializationExtendedSurrogateProvider); + private static readonly object s_surrogateDataKey = typeof(ISerializationSurrogateProvider2); private DataContractSet _dataContractSet; private CodeCompileUnit _codeCompileUnit; @@ -59,8 +59,8 @@ internal CodeExporter(DataContractSet dataContractSet, ImportOptions? options, C string? clrNamespace = contractCodeDomInfo.ClrNamespace; if (clrNamespace != null && !_clrNamespaces.ContainsKey(clrNamespace)) { - _clrNamespaces.Add(clrNamespace, dataContract.StableName.Namespace); - _namespaces.Add(dataContract.StableName.Namespace, clrNamespace); + _clrNamespaces.Add(clrNamespace, dataContract.XmlName.Namespace); + _namespaces.Add(dataContract.XmlName.Namespace, clrNamespace); } } } @@ -205,7 +205,7 @@ private Dictionary Namespaces get { return _clrNamespaces; } } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] internal void Export() { try @@ -225,7 +225,7 @@ internal void Export() if (dataContract.IsISerializable) ExportISerializableDataContract(dataContract, contractCodeDomInfo); else - ExportClassDataContractHierarchy(dataContract.StableName, dataContract, contractCodeDomInfo, new Dictionary()); + ExportClassDataContractHierarchy(dataContract.XmlName, dataContract, contractCodeDomInfo, new Dictionary()); break; case DataContractType.CollectionDataContract: ExportCollectionDataContract(dataContract, contractCodeDomInfo); @@ -244,12 +244,12 @@ internal void Export() } } - if (_options?.ProcessImportedType != null) + if (_options?.DataContractSurrogate is ISerializationCodeDomSurrogateProvider cdSurrogateProvider) { CodeNamespace[] namespaces = new CodeNamespace[_codeCompileUnit.Namespaces.Count]; _codeCompileUnit.Namespaces.CopyTo(namespaces, 0); foreach (CodeNamespace codeNamespace in namespaces) - InvokeProcessImportedType(codeNamespace.Types); + InvokeProcessImportedType(codeNamespace.Types, cdSurrogateProvider); } } finally @@ -258,14 +258,14 @@ internal void Export() } } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private void ExportClassDataContractHierarchy(XmlQualifiedName typeName, DataContract classContract, ContractCodeDomInfo contractCodeDomInfo, Dictionary contractNamesInHierarchy) { Debug.Assert(classContract.Is(DataContractType.ClassDataContract)); - if (contractNamesInHierarchy.ContainsKey(classContract.StableName)) - throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.TypeCannotBeImported, typeName.Name, typeName.Namespace, SR.Format(SR.CircularTypeReference, classContract.StableName.Name, classContract.StableName.Namespace)))); - contractNamesInHierarchy.Add(classContract.StableName, null); + if (contractNamesInHierarchy.ContainsKey(classContract.XmlName)) + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.TypeCannotBeImported, typeName.Name, typeName.Namespace, SR.Format(SR.CircularTypeReference, classContract.XmlName.Name, classContract.XmlName.Namespace)))); + contractNamesInHierarchy.Add(classContract.XmlName, null); DataContract? baseContract = classContract.BaseContract; if (baseContract != null) @@ -280,18 +280,16 @@ private void ExportClassDataContractHierarchy(XmlQualifiedName typeName, DataCon ExportClassDataContract(classContract, contractCodeDomInfo); } - private void InvokeProcessImportedType(CollectionBase collection) + private void InvokeProcessImportedType(CollectionBase collection, ISerializationCodeDomSurrogateProvider surrogateProvider) { object[] objects = new object[collection.Count]; ((ICollection)collection).CopyTo(objects, 0); - Debug.Assert(_options?.ProcessImportedType != null); // The only caller into this method already did a null check for this Func - foreach (object obj in objects) { if (obj is CodeTypeDeclaration codeTypeDeclaration) { - CodeTypeDeclaration? newCodeTypeDeclaration = _options?.ProcessImportedType.Invoke(codeTypeDeclaration, _codeCompileUnit); + CodeTypeDeclaration? newCodeTypeDeclaration = surrogateProvider.ProcessImportedType(codeTypeDeclaration, _codeCompileUnit); if (newCodeTypeDeclaration != codeTypeDeclaration) { @@ -300,12 +298,12 @@ private void InvokeProcessImportedType(CollectionBase collection) ((IList)collection).Add(newCodeTypeDeclaration); } if (newCodeTypeDeclaration != null) - InvokeProcessImportedType(newCodeTypeDeclaration.Members); + InvokeProcessImportedType(newCodeTypeDeclaration.Members, surrogateProvider); } } } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] internal CodeTypeReference GetCodeTypeReference(DataContract dataContract) { if (dataContract.IsBuiltInDataContract) @@ -359,7 +357,7 @@ private CodeTypeReference GetCodeTypeReference(Type type) return codeTypeReference; } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] internal CodeTypeReference GetElementTypeReference(DataContract dataContract, bool isElementTypeNullable) { CodeTypeReference elementTypeReference = GetCodeTypeReference(dataContract); @@ -371,26 +369,26 @@ internal CodeTypeReference GetElementTypeReference(DataContract dataContract, bo [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Part of a logical set of properties, some of which are not static. May not remain static with future implementation updates.")] private XmlQualifiedName GenericListName { - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - get { return DataContract.GetStableName(typeof(List<>)); } + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] + get { return DataContract.GetXmlName(typeof(List<>)); } } private DataContract GenericListContract { - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] get { return _dataContractSet.GetDataContract(typeof(List<>)); } } [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Part of a logical set of properties, some of which are not static. May not remain static with future implementation updates.")] private XmlQualifiedName GenericDictionaryName { - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - get { return DataContract.GetStableName(typeof(Dictionary<,>)); } + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] + get { return DataContract.GetXmlName(typeof(Dictionary<,>)); } } private DataContract GenericDictionaryContract { - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] get { return _dataContractSet.GetDataContract(typeof(Dictionary<,>)); } } @@ -407,7 +405,7 @@ private ContractCodeDomInfo GetContractCodeDomInfo(DataContract dataContract) return contractCodeDomInfo; } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private void GenerateType(DataContract dataContract, ContractCodeDomInfo contractCodeDomInfo) { if (!contractCodeDomInfo.IsProcessed) @@ -424,12 +422,12 @@ private void GenerateType(DataContract dataContract, ContractCodeDomInfo contrac if (type == null) { string clrNamespace = GetClrNamespace(dataContract, contractCodeDomInfo); - CodeNamespace ns = GetCodeNamespace(clrNamespace, dataContract.StableName.Namespace, contractCodeDomInfo); + CodeNamespace ns = GetCodeNamespace(clrNamespace, dataContract.XmlName.Namespace, contractCodeDomInfo); type = GetNestedType(dataContract, contractCodeDomInfo); if (type == null) { - string typeName = XmlConvert.DecodeName(dataContract.StableName.Name); - typeName = GetClrIdentifier(typeName, Globals.DefaultTypeName); + string typeName = XmlConvert.DecodeName(dataContract.XmlName.Name); + typeName = GetClrIdentifier(typeName, ImportGlobals.DefaultTypeName); if (NamespaceContainsType(ns, typeName) || GlobalTypeNameConflicts(clrNamespace, typeName)) { for (int i = 1;; i++) @@ -459,7 +457,7 @@ private void GenerateType(DataContract dataContract, ContractCodeDomInfo contrac type.TypeAttributes = TypeAttributes.Public; } - if (_options?.SurrogateProvider != null) + if (_options?.DataContractSurrogate != null) type.UserData.Add(s_surrogateDataKey, _dataContractSet.SurrogateData[dataContract]); contractCodeDomInfo.TypeDeclaration = type; @@ -468,21 +466,21 @@ private void GenerateType(DataContract dataContract, ContractCodeDomInfo contrac } } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private CodeTypeDeclaration? GetNestedType(DataContract dataContract, ContractCodeDomInfo contractCodeDomInfo) { if (!SupportsNestedTypes) return null; - string originalName = dataContract.StableName.Name; + string originalName = dataContract.XmlName.Name; int nestedTypeIndex = originalName.LastIndexOf('.'); if (nestedTypeIndex <= 0) return null; string containingTypeName = originalName.Substring(0, nestedTypeIndex); - DataContract? containingDataContract = _dataContractSet.GetDataContract(new XmlQualifiedName(containingTypeName, dataContract.StableName.Namespace)); + DataContract? containingDataContract = _dataContractSet.GetDataContract(new XmlQualifiedName(containingTypeName, dataContract.XmlName.Namespace)); if (containingDataContract == null) return null; string nestedTypeName = XmlConvert.DecodeName(originalName.Substring(nestedTypeIndex + 1)); - nestedTypeName = GetClrIdentifier(nestedTypeName, Globals.DefaultTypeName); + nestedTypeName = GetClrIdentifier(nestedTypeName, ImportGlobals.DefaultTypeName); ContractCodeDomInfo containingContractCodeDomInfo = GetContractCodeDomInfo(containingDataContract); GenerateType(containingDataContract, containingContractCodeDomInfo); @@ -534,14 +532,14 @@ private static CodeTypeDeclaration CreateTypeDeclaration(string typeName, DataCo return typeDecl; } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private CodeTypeReference? GetReferencedType(DataContract dataContract) { CodeTypeReference? typeReference = GetSurrogatedTypeReference(dataContract); if (typeReference != null) return typeReference; - Type? type = _dataContractSet.GetReferencedType(dataContract.StableName, dataContract, out DataContract? referencedContract, out object[]? parameters, SupportsGenericTypeReference); + Type? type = _dataContractSet.GetReferencedType(dataContract.XmlName, dataContract, out DataContract? referencedContract, out object[]? parameters, SupportsGenericTypeReference); if (type != null && !type.IsGenericTypeDefinition && !type.ContainsGenericParameters) { if (dataContract is XmlDataContract xmlContract) @@ -551,7 +549,7 @@ private static CodeTypeDeclaration CreateTypeDeclaration(string typeName, DataCo if (xmlContract.IsTypeDefinedOnImport) { if (!xmlContract.Equals(_dataContractSet.GetDataContract(type))) - throw ExceptionUtil.ThrowHelperError(new InvalidOperationException(SR.Format(SR.ReferencedTypeDoesNotMatch, type.AssemblyQualifiedName, dataContract.StableName.Name, dataContract.StableName.Namespace))); + throw ExceptionUtil.ThrowHelperError(new InvalidOperationException(SR.Format(SR.ReferencedTypeDoesNotMatch, type.AssemblyQualifiedName, dataContract.XmlName.Name, dataContract.XmlName.Namespace))); } else { @@ -560,7 +558,7 @@ private static CodeTypeDeclaration CreateTypeDeclaration(string typeName, DataCo } return GetCodeTypeReference(type); } - throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.TypeMustBeIXmlSerializable, GetClrTypeFullName(type), GetClrTypeFullName(typeof(IXmlSerializable)), dataContract.StableName.Name, dataContract.StableName.Namespace))); + throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.TypeMustBeIXmlSerializable, GetClrTypeFullName(type), GetClrTypeFullName(typeof(IXmlSerializable)), dataContract.XmlName.Name, dataContract.XmlName.Namespace))); } referencedContract = _dataContractSet.GetDataContract(type); if (referencedContract.Equals(dataContract)) @@ -569,7 +567,7 @@ private static CodeTypeDeclaration CreateTypeDeclaration(string typeName, DataCo typeReference.UserData.Add(s_codeUserDataActualTypeKey, type); return typeReference; } - throw ExceptionUtil.ThrowHelperError(new InvalidOperationException(SR.Format(SR.ReferencedTypeDoesNotMatch, type.AssemblyQualifiedName, dataContract.StableName.Name, dataContract.StableName.Namespace))); + throw ExceptionUtil.ThrowHelperError(new InvalidOperationException(SR.Format(SR.ReferencedTypeDoesNotMatch, type.AssemblyQualifiedName, dataContract.XmlName.Name, dataContract.XmlName.Namespace))); } else if (type != null) { @@ -581,8 +579,8 @@ private static CodeTypeDeclaration CreateTypeDeclaration(string typeName, DataCo type = (Type?)typeReference.UserData[s_codeUserDataActualTypeKey]; throw ExceptionUtil.ThrowHelperError(new InvalidOperationException(SR.Format(SR.ReferencedTypeDoesNotMatch, type?.AssemblyQualifiedName, - referencedContract.StableName.Name, - referencedContract.StableName.Namespace))); + referencedContract.XmlName.Name, + referencedContract.XmlName.Namespace))); } return typeReference; @@ -596,7 +594,7 @@ private static CodeTypeDeclaration CreateTypeDeclaration(string typeName, DataCo return GetReferencedCollectionType(dataContract.As(DataContractType.CollectionDataContract)); } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private CodeTypeReference? GetReferencedCollectionType(DataContract? collectionContract) { if (collectionContract == null) @@ -611,7 +609,7 @@ private static CodeTypeDeclaration CreateTypeDeclaration(string typeName, DataCo { // ItemContract - aka BaseContract - is never null for CollectionDataContract DataContract itemContract = collectionContract.BaseContract!; - if (collectionContract.IsKeyValue(out _, out _, out _)) + if (collectionContract.IsDictionaryLike(out _, out _, out _)) { GenerateKeyValueType(itemContract.As(DataContractType.ClassDataContract)); } @@ -628,31 +626,31 @@ private static CodeTypeDeclaration CreateTypeDeclaration(string typeName, DataCo return null; } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private static bool HasDefaultCollectionNames(DataContract collectionContract) { Debug.Assert(collectionContract.Is(DataContractType.CollectionDataContract)); // ItemContract - aka BaseContract - is never null for CollectionDataContract DataContract itemContract = collectionContract.BaseContract!; - bool isDictionary = collectionContract.IsKeyValue(out string? keyName, out string? valueName, out string? itemName); - if (itemName != itemContract.StableName.Name) + bool isDictionary = collectionContract.IsDictionaryLike(out string? keyName, out string? valueName, out string? itemName); + if (itemName != itemContract.XmlName.Name) return false; - if (isDictionary && (keyName != Globals.KeyLocalName || valueName != Globals.ValueLocalName)) + if (isDictionary && (keyName != ImportGlobals.KeyLocalName || valueName != ImportGlobals.ValueLocalName)) return false; XmlQualifiedName expectedType = itemContract.GetArrayTypeName(collectionContract.IsItemTypeNullable()); - return (collectionContract.StableName.Name == expectedType.Name && collectionContract.StableName.Namespace == expectedType.Namespace); + return (collectionContract.XmlName.Name == expectedType.Name && collectionContract.XmlName.Namespace == expectedType.Namespace); } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private bool TryGetReferencedDictionaryType(DataContract collectionContract, [NotNullWhen(true)] out CodeTypeReference? typeReference) { Debug.Assert(collectionContract.Is(DataContractType.CollectionDataContract)); // Check if it is a dictionary and use referenced dictionary type if present - if (collectionContract.IsKeyValue(out _, out _, out _) + if (collectionContract.IsDictionaryLike(out _, out _, out _) && SupportsGenericTypeReference) { Type? type = _dataContractSet.GetReferencedType(GenericDictionaryName, GenericDictionaryContract, out DataContract? _, out object[]? _) ?? typeof(Dictionary<,>); @@ -680,7 +678,7 @@ private bool TryGetReferencedDictionaryType(DataContract collectionContract, [No return false; } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private bool TryGetReferencedListType(DataContract itemContract, bool isItemTypeNullable, out CodeTypeReference? typeReference) { if (SupportsGenericTypeReference) @@ -697,7 +695,7 @@ private bool TryGetReferencedListType(DataContract itemContract, bool isItemType return false; } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private CodeTypeReference? GetSurrogatedTypeReference(DataContract dataContract) { Type? type = GetReferencedTypeOnImport(dataContract); @@ -713,10 +711,10 @@ private bool TryGetReferencedListType(DataContract itemContract, bool isItemType private Type? GetReferencedTypeOnImport(DataContract dataContract) { Type? type = null; - if (_options?.SurrogateProvider is ISerializationExtendedSurrogateProvider surrogateProvider) + if (_options?.DataContractSurrogate is ISerializationSurrogateProvider2 surrogateProvider) { - if (DataContract.GetBuiltInDataContract(dataContract.StableName.Name, dataContract.StableName.Namespace) == null) - type = surrogateProvider.GetReferencedTypeOnImport(dataContract.StableName.Name, dataContract.StableName.Namespace, _dataContractSet.SurrogateData[dataContract]); + if (DataContract.GetBuiltInDataContract(dataContract.XmlName.Name, dataContract.XmlName.Namespace) == null) + type = surrogateProvider.GetReferencedTypeOnImport(dataContract.XmlName.Name, dataContract.XmlName.Namespace, _dataContractSet.SurrogateData[dataContract]); } return type; } @@ -762,7 +760,7 @@ private static string GetNameForAttribute(string name) string decodedName = XmlConvert.DecodeName(name); if (string.CompareOrdinal(name, decodedName) == 0) return name; - string reencodedName = DataContract.EncodeLocalName(decodedName); + string reencodedName = SchemaImportHelper.EncodeLocalName(decodedName); return (string.CompareOrdinal(name, reencodedName) == 0) ? decodedName : name; } @@ -775,7 +773,7 @@ private void AddSerializableAttribute(bool generateSerializable, CodeTypeDeclara } } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private void ExportClassDataContract(DataContract classDataContract, ContractCodeDomInfo contractCodeDomInfo) { Debug.Assert(classDataContract.Is(DataContractType.ClassDataContract)); @@ -795,12 +793,12 @@ private void ExportClassDataContract(DataContract classDataContract, ContractCod else type.IsClass = true; - string dataContractName = GetNameForAttribute(classDataContract.StableName.Name); + string dataContractName = GetNameForAttribute(classDataContract.XmlName.Name); CodeAttributeDeclaration dataContractAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(DataContractAttribute))); - dataContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.NameProperty, new CodePrimitiveExpression(dataContractName))); - dataContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.NamespaceProperty, new CodePrimitiveExpression(classDataContract.StableName.Namespace))); - if (classDataContract.IsReference != Globals.DefaultIsReference) - dataContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.IsReferenceProperty, new CodePrimitiveExpression(classDataContract.IsReference))); + dataContractAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.NameProperty, new CodePrimitiveExpression(dataContractName))); + dataContractAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.NamespaceProperty, new CodePrimitiveExpression(classDataContract.XmlName.Namespace))); + if (classDataContract.IsReference != ImportGlobals.DefaultIsReference) + dataContractAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.IsReferenceProperty, new CodePrimitiveExpression(classDataContract.IsReference))); type.CustomAttributes.Add(dataContractAttribute); AddImportStatement(typeof(DataContractAttribute).Namespace, contractCodeDomInfo.CodeNamespace); @@ -851,7 +849,7 @@ private void ExportClassDataContract(DataContract classDataContract, ContractCod string dataMemberName = GetNameForAttribute(dataMember.Name); string propertyName = GetMemberName(dataMemberName, contractCodeDomInfo); - string fieldName = GetMemberName(AppendToValidClrIdentifier(propertyName, Globals.DefaultFieldSuffix), contractCodeDomInfo); + string fieldName = GetMemberName(AppendToValidClrIdentifier(propertyName, ImportGlobals.DefaultFieldSuffix), contractCodeDomInfo); CodeMemberField field = new CodeMemberField(); field.Type = memberType; @@ -865,13 +863,13 @@ private void ExportClassDataContract(DataContract classDataContract, ContractCod CodeAttributeDeclaration dataMemberAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(DataMemberAttribute))); if (dataMemberName != property.Name) - dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(Globals.NameProperty, new CodePrimitiveExpression(dataMemberName))); - if (dataMember.IsRequired != Globals.DefaultIsRequired) - dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(Globals.IsRequiredProperty, new CodePrimitiveExpression(dataMember.IsRequired))); - if (dataMember.EmitDefaultValue != Globals.DefaultEmitDefaultValue) - dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(Globals.EmitDefaultValueProperty, new CodePrimitiveExpression(dataMember.EmitDefaultValue))); - if (dataMember.Order != Globals.DefaultOrder) - dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(Globals.OrderProperty, new CodePrimitiveExpression(dataMember.Order))); + dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.NameProperty, new CodePrimitiveExpression(dataMemberName))); + if (dataMember.IsRequired != ImportGlobals.DefaultIsRequired) + dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.IsRequiredProperty, new CodePrimitiveExpression(dataMember.IsRequired))); + if (dataMember.EmitDefaultValue != ImportGlobals.DefaultEmitDefaultValue) + dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.EmitDefaultValueProperty, new CodePrimitiveExpression(dataMember.EmitDefaultValue))); + if (dataMember.Order != ImportGlobals.DefaultOrder) + dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.OrderProperty, new CodePrimitiveExpression(dataMember.Order))); property.CustomAttributes.Add(dataMemberAttribute); if (GenerateSerializableTypes && !dataMember.IsRequired) @@ -893,10 +891,10 @@ private bool CanDeclareAssemblyAttribute(ContractCodeDomInfo contractCodeDomInfo private static bool NeedsExplicitNamespace(string dataContractNamespace, string clrNamespace) { - return (SchemaHelper.GetDefaultStableNamespace(clrNamespace) != dataContractNamespace); + return (SchemaImportHelper.GetDefaultXmlNamespace(clrNamespace) != dataContractNamespace); } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] internal ICollection? GetKnownTypeReferences(DataContract dataContract) { DataContractDictionary? knownTypeDictionary = GetKnownTypeContracts(dataContract); @@ -915,7 +913,7 @@ private static bool NeedsExplicitNamespace(string dataContractNamespace, string return knownTypeReferences; } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private DataContractDictionary? GetKnownTypeContracts(DataContract dataContract) { if (_dataContractSet.KnownTypesForObject != null && IsObjectContract(dataContract)) @@ -933,7 +931,7 @@ private static bool NeedsExplicitNamespace(string dataContractNamespace, string return null; } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private DataContractDictionary? GetKnownTypeContracts(DataContract classDataContract, Dictionary handledContracts) { Debug.Assert(classDataContract.Is(DataContractType.ClassDataContract)); @@ -969,24 +967,24 @@ private static bool NeedsExplicitNamespace(string dataContractNamespace, string return classDataContract.KnownDataContracts; } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private static void AddKnownTypeContracts(DataContract classDataContract, DataContractDictionary? knownContracts) { if (knownContracts == null || knownContracts.Count == 0) return; + // This is a ClassDataContract. As such, it's KnownDataContracts collection is always non-null. Debug.Assert(classDataContract.Is(DataContractType.ClassDataContract)); - - classDataContract.KnownDataContracts ??= new DataContractDictionary(); + Debug.Assert(classDataContract.KnownDataContracts != null); foreach (KeyValuePair pair in knownContracts) { - if (classDataContract.StableName != pair.Key && !classDataContract.KnownDataContracts.ContainsKey(pair.Key) && !pair.Value.IsBuiltInDataContract) + if (classDataContract.XmlName != pair.Key && !classDataContract.KnownDataContracts.ContainsKey(pair.Key) && !pair.Value.IsBuiltInDataContract) classDataContract.KnownDataContracts.Add(pair.Key, pair.Value); } } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private void AddKnownTypes(DataContract classDataContract, ContractCodeDomInfo contractCodeDomInfo) { Debug.Assert(classDataContract.Is(DataContractType.ClassDataContract)); @@ -1058,10 +1056,10 @@ private void AddPropertyChangedNotifier(ContractCodeDomInfo contractCodeDomInfo, private static void ThrowIfReferencedBaseTypeSealed(Type baseType, DataContract dataContract) { if (baseType.IsSealed) - throw ExceptionUtil.ThrowHelperError(new InvalidOperationException(SR.Format(SR.CannotDeriveFromSealedReferenceType, dataContract.StableName.Name, dataContract.StableName.Namespace, GetClrTypeFullName(baseType)))); + throw ExceptionUtil.ThrowHelperError(new InvalidOperationException(SR.Format(SR.CannotDeriveFromSealedReferenceType, dataContract.XmlName.Name, dataContract.XmlName.Namespace, GetClrTypeFullName(baseType)))); } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private void ExportEnumDataContract(DataContract enumDataContract, ContractCodeDomInfo contractCodeDomInfo) { Debug.Assert(enumDataContract.Is(DataContractType.EnumDataContract)); @@ -1084,10 +1082,10 @@ private void ExportEnumDataContract(DataContract enumDataContract, ContractCodeD AddImportStatement(typeof(FlagsAttribute).Namespace, contractCodeDomInfo.CodeNamespace); } - string dataContractName = GetNameForAttribute(enumDataContract.StableName.Name); + string dataContractName = GetNameForAttribute(enumDataContract.XmlName.Name); CodeAttributeDeclaration dataContractAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(DataContractAttribute))); - dataContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.NameProperty, new CodePrimitiveExpression(dataContractName))); - dataContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.NamespaceProperty, new CodePrimitiveExpression(enumDataContract.StableName.Namespace))); + dataContractAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.NameProperty, new CodePrimitiveExpression(dataContractName))); + dataContractAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.NamespaceProperty, new CodePrimitiveExpression(enumDataContract.XmlName.Namespace))); type.CustomAttributes.Add(dataContractAttribute); AddImportStatement(typeof(DataContractAttribute).Namespace, contractCodeDomInfo.CodeNamespace); @@ -1106,14 +1104,14 @@ private void ExportEnumDataContract(DataContract enumDataContract, ContractCodeD enumMember.Name = GetMemberName(stringValue, contractCodeDomInfo); CodeAttributeDeclaration enumMemberAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(EnumMemberAttribute))); if (enumMember.Name != stringValue) - enumMemberAttribute.Arguments.Add(new CodeAttributeArgument(Globals.ValueProperty, new CodePrimitiveExpression(stringValue))); + enumMemberAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.ValueProperty, new CodePrimitiveExpression(stringValue))); enumMember.CustomAttributes.Add(enumMemberAttribute); type.Members.Add(enumMember); } } } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private void ExportISerializableDataContract(DataContract classDataContract, ContractCodeDomInfo contractCodeDomInfo) { Debug.Assert(classDataContract.Is(DataContractType.ClassDataContract)); @@ -1122,10 +1120,10 @@ private void ExportISerializableDataContract(DataContract classDataContract, Con if (contractCodeDomInfo.ReferencedTypeExists) return; - if (SchemaHelper.GetDefaultStableNamespace(contractCodeDomInfo.ClrNamespace) != classDataContract.StableName.Namespace) - throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidClrNamespaceGeneratedForISerializable, classDataContract.StableName.Name, classDataContract.StableName.Namespace, SchemaHelper.GetDataContractNamespaceFromUri(classDataContract.StableName.Namespace), contractCodeDomInfo.ClrNamespace))); + if (SchemaImportHelper.GetDefaultXmlNamespace(contractCodeDomInfo.ClrNamespace) != classDataContract.XmlName.Namespace) + throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidClrNamespaceGeneratedForISerializable, classDataContract.XmlName.Name, classDataContract.XmlName.Namespace, SchemaImportHelper.GetDataContractNamespaceFromUri(classDataContract.XmlName.Namespace), contractCodeDomInfo.ClrNamespace))); - string dataContractName = GetNameForAttribute(classDataContract.StableName.Name); + string dataContractName = GetNameForAttribute(classDataContract.XmlName.Name); int nestedTypeIndex = dataContractName.LastIndexOf('.'); string expectedName = (nestedTypeIndex <= 0 || nestedTypeIndex == dataContractName.Length - 1) ? dataContractName : dataContractName.Substring(nestedTypeIndex + 1); @@ -1133,7 +1131,7 @@ private void ExportISerializableDataContract(DataContract classDataContract, Con Debug.Assert(contractCodeDomInfo.TypeDeclaration != null); if (contractCodeDomInfo.TypeDeclaration.Name != expectedName) - throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidClrNameGeneratedForISerializable, classDataContract.StableName.Name, classDataContract.StableName.Namespace, contractCodeDomInfo.TypeDeclaration.Name))); + throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.InvalidClrNameGeneratedForISerializable, classDataContract.XmlName.Name, classDataContract.XmlName.Namespace, contractCodeDomInfo.TypeDeclaration.Name))); CodeTypeDeclaration type = contractCodeDomInfo.TypeDeclaration; if (SupportsPartialTypes) @@ -1173,14 +1171,14 @@ private void ExportISerializableDataContract(DataContract classDataContract, Con } } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private void GenerateKeyValueType(DataContract? keyValueContract) { Debug.Assert(keyValueContract == null || keyValueContract.Is(DataContractType.ClassDataContract)); // Add code for KeyValue item type in the case where its usage is limited to dictionary // and dictionary is not found in referenced types - if (keyValueContract != null && _dataContractSet.GetDataContract(keyValueContract.StableName) == null) + if (keyValueContract != null && _dataContractSet.GetDataContract(keyValueContract.XmlName) == null) { ContractCodeDomInfo? contractCodeDomInfo = null; if (_dataContractSet.ProcessedContracts.TryGetValue(keyValueContract, out object? info)) @@ -1195,7 +1193,7 @@ private void GenerateKeyValueType(DataContract? keyValueContract) } } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private void ExportCollectionDataContract(DataContract collectionContract, ContractCodeDomInfo contractCodeDomInfo) { Debug.Assert(collectionContract.Is(DataContractType.CollectionDataContract)); @@ -1204,18 +1202,18 @@ private void ExportCollectionDataContract(DataContract collectionContract, Contr if (contractCodeDomInfo.ReferencedTypeExists) return; - string dataContractName = GetNameForAttribute(collectionContract.StableName.Name); + string dataContractName = GetNameForAttribute(collectionContract.XmlName.Name); // If type name is not expected, generate collection type that derives from referenced list type and uses [CollectionDataContract] if (!SupportsGenericTypeReference) throw ExceptionUtil.ThrowHelperError(new InvalidOperationException( SR.Format(SR.CannotUseGenericTypeAsBase, dataContractName, - collectionContract.StableName.Namespace))); + collectionContract.XmlName.Namespace))); // ItemContract - aka BaseContract - is never null for CollectionDataContract DataContract itemContract = collectionContract.BaseContract!; bool isItemTypeNullable = collectionContract.IsItemTypeNullable(); - bool isDictionary = collectionContract.IsKeyValue(out string? keyName, out string? valueName, out string? itemName); + bool isDictionary = collectionContract.IsDictionaryLike(out string? keyName, out string? valueName, out string? itemName); CodeTypeReference? baseTypeReference; bool foundDictionaryBase = TryGetReferencedDictionaryType(collectionContract, out baseTypeReference); @@ -1234,10 +1232,10 @@ private void ExportCollectionDataContract(DataContract collectionContract, Contr } else { - string expectedTypeName = Globals.ArrayPrefix + itemContract.StableName.Name; - string expectedTypeNs = SchemaHelper.GetCollectionNamespace(itemContract.StableName.Namespace); + string expectedTypeName = ImportGlobals.ArrayPrefix + itemContract.XmlName.Name; + string expectedTypeNs = SchemaImportHelper.GetCollectionNamespace(itemContract.XmlName.Namespace); throw ExceptionUtil.ThrowHelperError(new InvalidOperationException(SR.Format(SR.ReferencedBaseTypeDoesNotExist, - dataContractName, collectionContract.StableName.Namespace, + dataContractName, collectionContract.XmlName.Namespace, expectedTypeName, expectedTypeNs, GetClrTypeFullName(typeof(IList<>)), GetClrTypeFullName(typeof(ICollection<>))))); } } @@ -1249,25 +1247,25 @@ private void ExportCollectionDataContract(DataContract collectionContract, Contr CodeTypeDeclaration generatedType = contractCodeDomInfo.TypeDeclaration; generatedType.BaseTypes.Add(baseTypeReference); CodeAttributeDeclaration collectionContractAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(CollectionDataContractAttribute))); - collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.NameProperty, new CodePrimitiveExpression(dataContractName))); - collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.NamespaceProperty, new CodePrimitiveExpression(collectionContract.StableName.Namespace))); - if (collectionContract.IsReference != Globals.DefaultIsReference) - collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.IsReferenceProperty, new CodePrimitiveExpression(collectionContract.IsReference))); - collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.ItemNameProperty, new CodePrimitiveExpression(GetNameForAttribute(itemName!)))); // ItemName is never null for Collection contracts. + collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.NameProperty, new CodePrimitiveExpression(dataContractName))); + collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.NamespaceProperty, new CodePrimitiveExpression(collectionContract.XmlName.Namespace))); + if (collectionContract.IsReference != ImportGlobals.DefaultIsReference) + collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.IsReferenceProperty, new CodePrimitiveExpression(collectionContract.IsReference))); + collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.ItemNameProperty, new CodePrimitiveExpression(GetNameForAttribute(itemName!)))); // ItemName is never null for Collection contracts. if (foundDictionaryBase) { // These are not null if we are working with a dictionary. See CollectionDataContract.IsDictionary Debug.Assert(keyName != null); Debug.Assert(valueName != null); - collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.KeyNameProperty, new CodePrimitiveExpression(GetNameForAttribute(keyName)))); - collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(Globals.ValueNameProperty, new CodePrimitiveExpression(GetNameForAttribute(valueName)))); + collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.KeyNameProperty, new CodePrimitiveExpression(GetNameForAttribute(keyName)))); + collectionContractAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.ValueNameProperty, new CodePrimitiveExpression(GetNameForAttribute(valueName)))); } generatedType.CustomAttributes.Add(collectionContractAttribute); AddImportStatement(typeof(CollectionDataContractAttribute).Namespace, contractCodeDomInfo.CodeNamespace); AddSerializableAttribute(GenerateSerializableTypes, generatedType, contractCodeDomInfo); } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private void ExportXmlDataContract(XmlDataContract xmlDataContract, ContractCodeDomInfo contractCodeDomInfo) { GenerateType(xmlDataContract, contractCodeDomInfo); @@ -1299,31 +1297,31 @@ private void ExportXmlDataContract(XmlDataContract xmlDataContract, ContractCode if (xmlDataContract.IsAnonymous && !xmlDataContract.HasRoot) { type.CustomAttributes.Add(new CodeAttributeDeclaration( - GetClrTypeFullName(Globals.TypeOfXmlSchemaProviderAttribute), + GetClrTypeFullName(ImportGlobals.TypeOfXmlSchemaProviderAttribute), new CodeAttributeArgument(NullReference), - new CodeAttributeArgument(Globals.IsAnyProperty, new CodePrimitiveExpression(true))) + new CodeAttributeArgument(ImportGlobals.IsAnyProperty, new CodePrimitiveExpression(true))) ); } else { type.CustomAttributes.Add(new CodeAttributeDeclaration( - GetClrTypeFullName(Globals.TypeOfXmlSchemaProviderAttribute), - new CodeAttributeArgument(new CodePrimitiveExpression(Globals.ExportSchemaMethod))) + GetClrTypeFullName(ImportGlobals.TypeOfXmlSchemaProviderAttribute), + new CodeAttributeArgument(new CodePrimitiveExpression(ImportGlobals.ExportSchemaMethod))) ); - CodeMemberField typeNameField = new CodeMemberField(Globals.TypeOfXmlQualifiedName, TypeNameFieldName); + CodeMemberField typeNameField = new CodeMemberField(ImportGlobals.TypeOfXmlQualifiedName, TypeNameFieldName); typeNameField.Attributes |= MemberAttributes.Static | MemberAttributes.Private; XmlQualifiedName typeName = xmlDataContract.IsAnonymous - ? XsdDataContractImporter.ImportActualType(xmlDataContract.XsdType?.Annotation, xmlDataContract.StableName, xmlDataContract.StableName) - : xmlDataContract.StableName; - typeNameField.InitExpression = new CodeObjectCreateExpression(Globals.TypeOfXmlQualifiedName, new CodePrimitiveExpression(typeName.Name), new CodePrimitiveExpression(typeName.Namespace)); + ? XsdDataContractImporter.ImportActualType(xmlDataContract.XsdType?.Annotation, xmlDataContract.XmlName, xmlDataContract.XmlName) + : xmlDataContract.XmlName; + typeNameField.InitExpression = new CodeObjectCreateExpression(ImportGlobals.TypeOfXmlQualifiedName, new CodePrimitiveExpression(typeName.Name), new CodePrimitiveExpression(typeName.Namespace)); type.Members.Add(typeNameField); type.Members.Add(GetSchemaStaticMethod); bool isElementNameDifferent = - (xmlDataContract.TopLevelElementName != null && xmlDataContract.TopLevelElementName.Value != xmlDataContract.StableName.Name) || - (xmlDataContract.TopLevelElementNamespace != null && xmlDataContract.TopLevelElementNamespace.Value != xmlDataContract.StableName.Namespace); + (xmlDataContract.TopLevelElementName != null && xmlDataContract.TopLevelElementName.Value != xmlDataContract.XmlName.Name) || + (xmlDataContract.TopLevelElementNamespace != null && xmlDataContract.TopLevelElementNamespace.Value != xmlDataContract.XmlName.Namespace); if (isElementNameDifferent || xmlDataContract.IsTopLevelElementNullable == false) { CodeAttributeDeclaration xmlRootAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(XmlRootAttribute))); @@ -1369,7 +1367,7 @@ private CodeNamespace GetCodeNamespace(string clrNamespace, string dataContractN { CodeAttributeDeclaration namespaceAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(ContractNamespaceAttribute))); namespaceAttribute.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(dataContractNamespace))); - namespaceAttribute.Arguments.Add(new CodeAttributeArgument(Globals.ClrNamespaceProperty, new CodePrimitiveExpression(clrNamespace))); + namespaceAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.ClrNamespaceProperty, new CodePrimitiveExpression(clrNamespace))); _codeCompileUnit.AssemblyCustomAttributes.Add(namespaceAttribute); } contractCodeDomInfo.CodeNamespace = codeNamespace; @@ -1378,13 +1376,13 @@ private CodeNamespace GetCodeNamespace(string clrNamespace, string dataContractN private static string GetMemberName(string memberName, ContractCodeDomInfo contractCodeDomInfo) { - memberName = GetClrIdentifier(memberName, Globals.DefaultGeneratedMember); + memberName = GetClrIdentifier(memberName, ImportGlobals.DefaultGeneratedMember); // This is only called from Export* methods which have already called GenerateType to fill in this info. Debug.Assert(contractCodeDomInfo.TypeDeclaration != null); if (memberName == contractCodeDomInfo.TypeDeclaration.Name) - memberName = AppendToValidClrIdentifier(memberName, Globals.DefaultMemberSuffix); + memberName = AppendToValidClrIdentifier(memberName, ImportGlobals.DefaultMemberSuffix); if (contractCodeDomInfo.GetMemberNames().Contains(memberName)) { @@ -1462,7 +1460,7 @@ private string GetClrNamespace(DataContract dataContract, ContractCodeDomInfo co bool usesWildcardNamespace = false; if (clrNamespace == null) { - if (!Namespaces.TryGetValue(dataContract.StableName.Namespace, out clrNamespace)) + if (!Namespaces.TryGetValue(dataContract.XmlName.Namespace, out clrNamespace)) { if (Namespaces.TryGetValue(WildcardNamespaceMapping, out clrNamespace)) { @@ -1470,13 +1468,13 @@ private string GetClrNamespace(DataContract dataContract, ContractCodeDomInfo co } else { - clrNamespace = GetClrNamespace(dataContract.StableName.Namespace); + clrNamespace = GetClrNamespace(dataContract.XmlName.Namespace); if (ClrNamespaces.ContainsKey(clrNamespace)) { string uniqueNamespace; for (int i = 1;; i++) { - uniqueNamespace = ((clrNamespace.Length == 0) ? Globals.DefaultClrNamespace : clrNamespace) + i.ToString(NumberFormatInfo.InvariantInfo); + uniqueNamespace = ((clrNamespace.Length == 0) ? ImportGlobals.DefaultClrNamespace : clrNamespace) + i.ToString(NumberFormatInfo.InvariantInfo); if (!ClrNamespaces.ContainsKey(uniqueNamespace)) { clrNamespace = uniqueNamespace; @@ -1484,7 +1482,7 @@ private string GetClrNamespace(DataContract dataContract, ContractCodeDomInfo co } } } - AddNamespacePair(dataContract.StableName.Namespace, clrNamespace); + AddNamespacePair(dataContract.XmlName.Namespace, clrNamespace); } } contractCodeDomInfo.ClrNamespace = clrNamespace; @@ -1532,8 +1530,8 @@ private static string GetClrNamespace(string? dataContractNamespace) else { string uriString = uri.AbsoluteUri; - if (uriString.StartsWith(Globals.DataContractXsdBaseNamespace, StringComparison.Ordinal)) - AddToNamespace(builder, uriString.Substring(Globals.DataContractXsdBaseNamespace.Length), fragments); + if (uriString.StartsWith(ImportGlobals.DataContractXsdBaseNamespace, StringComparison.Ordinal)) + AddToNamespace(builder, uriString.Substring(ImportGlobals.DataContractXsdBaseNamespace.Length), fragments); else { string host = uri.Host; @@ -1616,7 +1614,7 @@ private static void AddNamespaceFragment(StringBuilder builder, int fragmentOffs fragments.Add(nsFragment, null); } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] internal static bool IsObjectContract(DataContract? dataContract) { Dictionary previousCollectionTypes = new Dictionary(); @@ -1687,12 +1685,12 @@ private static CodePrimitiveExpression NullReference private CodeParameterDeclarationExpression SerializationInfoParameter { - get { return new CodeParameterDeclarationExpression(GetCodeTypeReference(typeof(SerializationInfo)), Globals.SerializationInfoFieldName); } + get { return new CodeParameterDeclarationExpression(GetCodeTypeReference(typeof(SerializationInfo)), ImportGlobals.SerializationInfoFieldName); } } private CodeParameterDeclarationExpression StreamingContextParameter { - get { return new CodeParameterDeclarationExpression(GetCodeTypeReference(typeof(StreamingContext)), Globals.ContextFieldName); } + get { return new CodeParameterDeclarationExpression(GetCodeTypeReference(typeof(StreamingContext)), ImportGlobals.ContextFieldName); } } private CodeAttributeDeclaration SerializableAttribute @@ -1704,7 +1702,7 @@ private CodeMemberProperty NodeArrayProperty { get { - return CreateProperty(GetCodeTypeReference(Globals.TypeOfXmlNodeArray), Globals.NodeArrayPropertyName, Globals.NodeArrayFieldName, false/*isValueType*/); + return CreateProperty(GetCodeTypeReference(ImportGlobals.TypeOfXmlNodeArray), ImportGlobals.NodeArrayPropertyName, ImportGlobals.NodeArrayFieldName, false/*isValueType*/); } } @@ -1713,8 +1711,8 @@ private CodeMemberField NodeArrayField get { CodeMemberField nodeArrayField = new CodeMemberField(); - nodeArrayField.Type = GetCodeTypeReference(Globals.TypeOfXmlNodeArray); - nodeArrayField.Name = Globals.NodeArrayFieldName; + nodeArrayField.Type = GetCodeTypeReference(ImportGlobals.TypeOfXmlNodeArray); + nodeArrayField.Name = ImportGlobals.NodeArrayFieldName; nodeArrayField.Attributes = MemberAttributes.Private; return nodeArrayField; } @@ -1731,7 +1729,7 @@ private CodeMemberMethod ReadXmlMethod readXmlMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final; readXmlMethod.ImplementationTypes.Add(typeof(IXmlSerializable)); CodeAssignStatement setNode = new CodeAssignStatement(); - setNode.Left = new CodeFieldReferenceExpression(ThisReference, Globals.NodeArrayFieldName); + setNode.Left = new CodeFieldReferenceExpression(ThisReference, ImportGlobals.NodeArrayFieldName); setNode.Right = new CodeMethodInvokeExpression( new CodeTypeReferenceExpression(GetCodeTypeReference(typeof(XmlSerializableServices))), nameof(XmlSerializableServices.ReadNodes), @@ -1757,7 +1755,7 @@ private CodeMemberMethod WriteXmlMethod new CodeTypeReferenceExpression(GetCodeTypeReference(typeof(XmlSerializableServices))), nameof(XmlSerializableServices.WriteNodes), new CodeArgumentReferenceExpression(writerArg.Name), - new CodePropertyReferenceExpression(ThisReference, Globals.NodeArrayPropertyName) + new CodePropertyReferenceExpression(ThisReference, ImportGlobals.NodeArrayPropertyName) ) ); return writeXmlMethod; @@ -1783,8 +1781,8 @@ private CodeMemberMethod GetSchemaStaticMethod get { CodeMemberMethod getSchemaStaticMethod = new CodeMemberMethod(); - getSchemaStaticMethod.Name = Globals.ExportSchemaMethod; - getSchemaStaticMethod.ReturnType = GetCodeTypeReference(Globals.TypeOfXmlQualifiedName); + getSchemaStaticMethod.Name = ImportGlobals.ExportSchemaMethod; + getSchemaStaticMethod.ReturnType = GetCodeTypeReference(ImportGlobals.TypeOfXmlQualifiedName); CodeParameterDeclarationExpression paramDeclaration = new CodeParameterDeclarationExpression(typeof(XmlSchemaSet), "schemas"); getSchemaStaticMethod.Parameters.Add(paramDeclaration); getSchemaStaticMethod.Attributes = MemberAttributes.Static | MemberAttributes.Public; @@ -1814,8 +1812,8 @@ private CodeConstructor ISerializableBaseConstructor baseConstructor.Parameters.Add(SerializationInfoParameter); baseConstructor.Parameters.Add(StreamingContextParameter); CodeAssignStatement setObjectData = new CodeAssignStatement(); - setObjectData.Left = new CodePropertyReferenceExpression(ThisReference, Globals.SerializationInfoFieldName); - setObjectData.Right = new CodeArgumentReferenceExpression(Globals.SerializationInfoFieldName); + setObjectData.Left = new CodePropertyReferenceExpression(ThisReference, ImportGlobals.SerializationInfoFieldName); + setObjectData.Right = new CodeArgumentReferenceExpression(ImportGlobals.SerializationInfoFieldName); baseConstructor.Statements.Add(setObjectData); // Special-cased check for vb here since CodeGeneratorOptions does not provide information indicating that VB cannot initialize event member if (EnableDataBinding && SupportsDeclareEvents && string.CompareOrdinal(FileExtension, "vb") != 0) @@ -1834,8 +1832,8 @@ private CodeConstructor ISerializableDerivedConstructor derivedConstructor.Attributes = MemberAttributes.Public; derivedConstructor.Parameters.Add(SerializationInfoParameter); derivedConstructor.Parameters.Add(StreamingContextParameter); - derivedConstructor.BaseConstructorArgs.Add(new CodeVariableReferenceExpression(Globals.SerializationInfoFieldName)); - derivedConstructor.BaseConstructorArgs.Add(new CodeVariableReferenceExpression(Globals.ContextFieldName)); + derivedConstructor.BaseConstructorArgs.Add(new CodeVariableReferenceExpression(ImportGlobals.SerializationInfoFieldName)); + derivedConstructor.BaseConstructorArgs.Add(new CodeVariableReferenceExpression(ImportGlobals.ContextFieldName)); return derivedConstructor; } } @@ -1846,7 +1844,7 @@ private CodeMemberField SerializationInfoField { CodeMemberField serializationInfoField = new CodeMemberField(); serializationInfoField.Type = GetCodeTypeReference(typeof(SerializationInfo)); - serializationInfoField.Name = Globals.SerializationInfoFieldName; + serializationInfoField.Name = ImportGlobals.SerializationInfoFieldName; serializationInfoField.Attributes = MemberAttributes.Private; return serializationInfoField; } @@ -1856,7 +1854,7 @@ private CodeMemberProperty SerializationInfoProperty { get { - return CreateProperty(GetCodeTypeReference(typeof(SerializationInfo)), Globals.SerializationInfoPropertyName, Globals.SerializationInfoFieldName, false/*isValueType*/); + return CreateProperty(GetCodeTypeReference(typeof(SerializationInfo)), ImportGlobals.SerializationInfoPropertyName, ImportGlobals.SerializationInfoFieldName, false/*isValueType*/); } } @@ -1865,7 +1863,7 @@ private CodeMemberMethod GetObjectDataMethod get { CodeMemberMethod getObjectDataMethod = new CodeMemberMethod(); - getObjectDataMethod.Name = Globals.GetObjectDataMethodName; + getObjectDataMethod.Name = ImportGlobals.GetObjectDataMethodName; getObjectDataMethod.Parameters.Add(SerializationInfoParameter); getObjectDataMethod.Parameters.Add(StreamingContextParameter); getObjectDataMethod.Attributes = MemberAttributes.Public | MemberAttributes.Final; @@ -1874,7 +1872,7 @@ private CodeMemberMethod GetObjectDataMethod // Generates: if (this.SerializationInfo == null) return; CodeConditionStatement returnIfNull = new CodeConditionStatement(); returnIfNull.Condition = new CodeBinaryOperatorExpression( - new CodePropertyReferenceExpression(ThisReference, Globals.SerializationInfoPropertyName), + new CodePropertyReferenceExpression(ThisReference, ImportGlobals.SerializationInfoPropertyName), CodeBinaryOperatorType.IdentityEquality, NullReference); returnIfNull.TrueStatements.Add(new CodeMethodReturnStatement()); @@ -1882,37 +1880,37 @@ private CodeMemberMethod GetObjectDataMethod // Generates: SerializationInfoEnumerator enumerator = this.SerializationInfo.GetEnumerator(); CodeVariableDeclarationStatement getEnumerator = new CodeVariableDeclarationStatement(); getEnumerator.Type = GetCodeTypeReference(typeof(SerializationInfoEnumerator)); - getEnumerator.Name = Globals.EnumeratorFieldName; + getEnumerator.Name = ImportGlobals.EnumeratorFieldName; getEnumerator.InitExpression = new CodeMethodInvokeExpression( - new CodePropertyReferenceExpression(ThisReference, Globals.SerializationInfoPropertyName), - Globals.GetEnumeratorMethodName); + new CodePropertyReferenceExpression(ThisReference, ImportGlobals.SerializationInfoPropertyName), + ImportGlobals.GetEnumeratorMethodName); //Generates: SerializationEntry entry = enumerator.Current; CodeVariableDeclarationStatement getCurrent = new CodeVariableDeclarationStatement(); getCurrent.Type = GetCodeTypeReference(typeof(SerializationEntry)); - getCurrent.Name = Globals.SerializationEntryFieldName; + getCurrent.Name = ImportGlobals.SerializationEntryFieldName; getCurrent.InitExpression = new CodePropertyReferenceExpression( - new CodeVariableReferenceExpression(Globals.EnumeratorFieldName), - Globals.CurrentPropertyName); + new CodeVariableReferenceExpression(ImportGlobals.EnumeratorFieldName), + ImportGlobals.CurrentPropertyName); //Generates: info.AddValue(entry.Name, entry.Value); CodeExpressionStatement addValue = new CodeExpressionStatement(); CodePropertyReferenceExpression getCurrentName = new CodePropertyReferenceExpression( - new CodeVariableReferenceExpression(Globals.SerializationEntryFieldName), - Globals.NameProperty); + new CodeVariableReferenceExpression(ImportGlobals.SerializationEntryFieldName), + ImportGlobals.NameProperty); CodePropertyReferenceExpression getCurrentValue = new CodePropertyReferenceExpression( - new CodeVariableReferenceExpression(Globals.SerializationEntryFieldName), - Globals.ValueProperty); + new CodeVariableReferenceExpression(ImportGlobals.SerializationEntryFieldName), + ImportGlobals.ValueProperty); addValue.Expression = new CodeMethodInvokeExpression( - new CodeArgumentReferenceExpression(Globals.SerializationInfoFieldName), - Globals.AddValueMethodName, + new CodeArgumentReferenceExpression(ImportGlobals.SerializationInfoFieldName), + ImportGlobals.AddValueMethodName, new CodeExpression[] { getCurrentName, getCurrentValue }); //Generates: for (; enumerator.MoveNext(); ) CodeIterationStatement loop = new CodeIterationStatement(); loop.TestExpression = new CodeMethodInvokeExpression( - new CodeVariableReferenceExpression(Globals.EnumeratorFieldName), - Globals.MoveNextMethodName); + new CodeVariableReferenceExpression(ImportGlobals.EnumeratorFieldName), + ImportGlobals.MoveNextMethodName); loop.InitStatement = loop.IncrementStatement = new CodeSnippetStatement(string.Empty); loop.Statements.Add(getCurrent); loop.Statements.Add(addValue); @@ -1931,7 +1929,7 @@ private CodeMemberField ExtensionDataObjectField { CodeMemberField extensionDataObjectField = new CodeMemberField(); extensionDataObjectField.Type = GetCodeTypeReference(typeof(ExtensionDataObject)); - extensionDataObjectField.Name = Globals.ExtensionDataObjectFieldName; + extensionDataObjectField.Name = ImportGlobals.ExtensionDataObjectFieldName; extensionDataObjectField.Attributes = MemberAttributes.Private; return extensionDataObjectField; } @@ -1943,16 +1941,16 @@ private CodeMemberProperty ExtensionDataObjectProperty { CodeMemberProperty extensionDataObjectProperty = new CodeMemberProperty(); extensionDataObjectProperty.Type = GetCodeTypeReference(typeof(ExtensionDataObject)); - extensionDataObjectProperty.Name = Globals.ExtensionDataObjectPropertyName; + extensionDataObjectProperty.Name = ImportGlobals.ExtensionDataObjectPropertyName; extensionDataObjectProperty.Attributes = MemberAttributes.Public | MemberAttributes.Final; extensionDataObjectProperty.ImplementationTypes.Add(typeof(IExtensibleDataObject)); CodeMethodReturnStatement propertyGet = new CodeMethodReturnStatement(); - propertyGet.Expression = new CodeFieldReferenceExpression(ThisReference, Globals.ExtensionDataObjectFieldName); + propertyGet.Expression = new CodeFieldReferenceExpression(ThisReference, ImportGlobals.ExtensionDataObjectFieldName); extensionDataObjectProperty.GetStatements.Add(propertyGet); CodeAssignStatement propertySet = new CodeAssignStatement(); - propertySet.Left = new CodeFieldReferenceExpression(ThisReference, Globals.ExtensionDataObjectFieldName); + propertySet.Left = new CodeFieldReferenceExpression(ThisReference, ImportGlobals.ExtensionDataObjectFieldName); propertySet.Right = new CodePropertySetValueReferenceExpression(); extensionDataObjectProperty.SetStatements.Add(propertySet); diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs index 5872baa78c1c5..36b4bee087693 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs @@ -7,9 +7,9 @@ using System.Xml; using System.Xml.Schema; -using ExceptionUtil = System.Runtime.Serialization.Schema.DiagnosticUtility.ExceptionUtility; +using ExceptionUtil = System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility; -namespace System.Runtime.Serialization.Schema +namespace System.Runtime.Serialization { internal sealed class ContractCodeDomInfo { diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/DiagnosticUtility.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/DiagnosticUtility.cs index 2cb5317fae40c..6064c043bfceb 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/DiagnosticUtility.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/DiagnosticUtility.cs @@ -4,7 +4,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -namespace System.Runtime.Serialization.Schema +namespace System.Runtime.Serialization { internal static class DiagnosticUtility { diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ExportOptions.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ExportOptions.cs deleted file mode 100644 index beacbdbbf04fa..0000000000000 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ExportOptions.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.ObjectModel; - -namespace System.Runtime.Serialization.Schema -{ - // NOTE TODO smolloy - ExportOptions, ImportOptions, XsdDataContractExporter, XsdDataContractImporter... they all have the same - // names in this library as they did in 4.8... and as the two 'Export' classes currently have in Core. The namespace is - // different here so there isn't a collision. But should we consider using different names for these classes? - // (The 'SurrogateProvider' property is named differently from previous versions. Should we align that property with whatever - // decision we make on the class names?) - /// - /// Represents the options that can be set for an . - /// - /// - /// The is used to generate XSD schemas from a type or assembly. You can also use the to generate .NET Framework code from a schema document. - /// - /// The property is used by the to include types that can be read in an object graph. - /// - public sealed class ExportOptions - { - /// - /// Gets or sets a serialization surrogate provider. - /// - public ISerializationSurrogateProvider? SurrogateProvider { get; set; } - - private Collection? _knownTypes; - /// - /// Gets the collection of types that may be encountered during serialization or deserialization. - /// - public Collection KnownTypes => _knownTypes ??= new Collection(); - } -} diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ISerializationCodeDomSurrogateProvider.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ISerializationCodeDomSurrogateProvider.cs new file mode 100644 index 0000000000000..2fcf279dc6f1a --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ISerializationCodeDomSurrogateProvider.cs @@ -0,0 +1,21 @@ +// 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.CodeDom; +using System.CodeDom.Compiler; +using System.Collections.Generic; + +namespace System.Runtime.Serialization +{ + /// + /// Represents a DataContract surrogate provider that is capable of modifying generated type code using . + /// + public interface ISerializationCodeDomSurrogateProvider + { + /// + /// A method to processes the type that has been generated from imported schema. + /// + CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit); + } +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/Globals.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ImportGlobals.cs similarity index 96% rename from src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/Globals.cs rename to src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ImportGlobals.cs index 755dbec7fdcaa..59392aed8b04f 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/Globals.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ImportGlobals.cs @@ -6,9 +6,9 @@ using System.Xml.Schema; using System.Xml.Serialization; -namespace System.Runtime.Serialization.Schema +namespace System.Runtime.Serialization { - internal static class Globals + internal static class ImportGlobals { internal const string SerializerTrimmerWarning = "Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the " + "required types are preserved."; @@ -88,10 +88,10 @@ internal static class Globals internal static Uri DataContractXsdBaseNamespaceUri => s_dataContractXsdBaseNamespaceUri ??= new Uri(DataContractXsdBaseNamespace); private static XmlQualifiedName? s_idQualifiedName; - internal static XmlQualifiedName IdQualifiedName => s_idQualifiedName ??= new XmlQualifiedName(Globals.IdLocalName, Globals.SerializationNamespace); + internal static XmlQualifiedName IdQualifiedName => s_idQualifiedName ??= new XmlQualifiedName(ImportGlobals.IdLocalName, ImportGlobals.SerializationNamespace); private static XmlQualifiedName? s_refQualifiedName; - internal static XmlQualifiedName RefQualifiedName => s_refQualifiedName ??= new XmlQualifiedName(Globals.RefLocalName, Globals.SerializationNamespace); + internal static XmlQualifiedName RefQualifiedName => s_refQualifiedName ??= new XmlQualifiedName(ImportGlobals.RefLocalName, ImportGlobals.SerializationNamespace); private static Type? s_typeOfXmlElement; internal static Type TypeOfXmlElement => s_typeOfXmlElement ??= typeof(XmlElement); diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ImportOptions.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ImportOptions.cs index 1497a64117325..0e8fab9d0df5b 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ImportOptions.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ImportOptions.cs @@ -5,9 +5,8 @@ using System.CodeDom; using System.CodeDom.Compiler; using System.Collections.Generic; -using System.Runtime.Serialization; -namespace System.Runtime.Serialization.Schema +namespace System.Runtime.Serialization { /// /// Represents the options that can be set on an . @@ -15,7 +14,7 @@ namespace System.Runtime.Serialization.Schema /// /// The is used to generate code from XML schema using the .NET CodeDOM. To generate an XML schema from an assembly, use the . /// - public sealed class ImportOptions + public class ImportOptions { private ICollection? _referencedTypes; private ICollection? _referencedCollectionTypes; @@ -36,9 +35,9 @@ public sealed class ImportOptions /// /// /// The interface type for this option is ISerializationSurrogateProvider, but to take full advantage of the imported code modification - /// abilities, using an ISerializationExtendedSurrogateProvider is recommended. + /// abilities, using an ISerializationSurrogateProvider2 that also implements is recommended. /// - public ISerializationSurrogateProvider? SurrogateProvider { get; set; } + public ISerializationSurrogateProvider? DataContractSurrogate { get; set; } /// /// Gets or sets a value that specifies whether generated code will be marked internal or public. @@ -69,10 +68,5 @@ public sealed class ImportOptions /// Gets a containing types referenced in generated code. /// public ICollection ReferencedTypes => _referencedTypes ??= new List(); - - /// - /// A Func to processes the type that has been generated from the imported schema. - /// - public Func? ProcessImportedType; } } diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaHelper.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaHelper.cs deleted file mode 100644 index 9f833c0b4476b..0000000000000 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaHelper.cs +++ /dev/null @@ -1,109 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Xml.Schema; - -namespace System.Runtime.Serialization.Schema -{ - internal enum DataContractType - { - ClassDataContract, - CollectionDataContract, - EnumDataContract, - PrimitiveDataContract, - XmlDataContract, - Unknown = -1 - } - - internal static class DataContractExtensions - { - internal static DataContractType GetContractType(this DataContract dataContract) => dataContract.ContractType switch - { - "ClassDataContract" => Schema.DataContractType.ClassDataContract, - "CollectionDataContract" => Schema.DataContractType.CollectionDataContract, - "EnumDataContract" => Schema.DataContractType.EnumDataContract, - "PrimitiveDataContract" => Schema.DataContractType.PrimitiveDataContract, - "XmlDataContract" => Schema.DataContractType.XmlDataContract, - _ => Schema.DataContractType.Unknown - }; - - internal static bool Is(this DataContract dataContract, DataContractType dcType) - { - return (dataContract.GetContractType() == dcType); - } - - internal static DataContract? As(this DataContract dataContract, DataContractType dcType) - { - if (dataContract.GetContractType() == dcType) - return dataContract; - return null; - } - - internal static bool IsItemTypeNullable(this DataContract collectionDataContract) - { - if (collectionDataContract.GetContractType() == DataContractType.CollectionDataContract) - { - // ItemContract - aka BaseContract - is never null for CollectionDataContract - return SchemaHelper.IsTypeNullable(collectionDataContract.BaseContract!.UnderlyingType); - } - - return false; - } - } - - internal static class SchemaHelper - { - internal static void CompileSchemaSet(XmlSchemaSet schemaSet) - { - if (schemaSet.Contains(XmlSchema.Namespace)) - schemaSet.Compile(); - else - { - // Add base XSD schema with top level element named "schema" - XmlSchema xsdSchema = new XmlSchema(); - xsdSchema.TargetNamespace = XmlSchema.Namespace; - XmlSchemaElement element = new XmlSchemaElement(); - element.Name = Globals.SchemaLocalName; - element.SchemaType = new XmlSchemaComplexType(); - xsdSchema.Items.Add(element); - schemaSet.Add(xsdSchema); - schemaSet.Compile(); - } - } - - internal static bool IsTypeNullable(Type type) - { - return !type.IsValueType || - (type.IsGenericType && - type.GetGenericTypeDefinition() == typeof(Nullable<>)); - } - - internal static string GetCollectionNamespace(string elementNs) - { - return IsBuiltInNamespace(elementNs) ? Globals.CollectionsNamespace : elementNs; - } - - internal static string GetDataContractNamespaceFromUri(string uriString) - { - return uriString.StartsWith(Globals.DataContractXsdBaseNamespace, StringComparison.Ordinal) ? uriString.Substring(Globals.DataContractXsdBaseNamespace.Length) : uriString; - } - - internal static string GetDefaultStableNamespace(Type type) - { - if (type.IsGenericParameter) - return "{ns}"; - return GetDefaultStableNamespace(type.Namespace); - } - - internal static string GetDefaultStableNamespace(string? clrNs) - { - if (clrNs == null) clrNs = string.Empty; - return new Uri(Globals.DataContractXsdBaseNamespaceUri, clrNs).AbsoluteUri; - } - - internal static bool IsBuiltInNamespace(string ns) - { - return (ns == Globals.SchemaNamespace || ns == Globals.SerializationNamespace); - } - } -} diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaImportHelper.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaImportHelper.cs new file mode 100644 index 0000000000000..5803fadc077ac --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaImportHelper.cs @@ -0,0 +1,125 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.Serialization.DataContracts; +using System.Xml; + +namespace System.Runtime.Serialization +{ + internal enum DataContractType + { + ClassDataContract, + CollectionDataContract, + EnumDataContract, + PrimitiveDataContract, + XmlDataContract, + Unknown = -1 + } + + internal static class DataContractExtensions + { + internal static DataContractType GetContractType(this DataContract dataContract) => dataContract.ContractType switch + { + "ClassDataContract" => DataContractType.ClassDataContract, + "CollectionDataContract" => DataContractType.CollectionDataContract, + "EnumDataContract" => DataContractType.EnumDataContract, + "PrimitiveDataContract" => DataContractType.PrimitiveDataContract, + "XmlDataContract" => DataContractType.XmlDataContract, + _ => DataContractType.Unknown + }; + + internal static bool Is(this DataContract dataContract, DataContractType dcType) + { + return (dataContract.GetContractType() == dcType); + } + + internal static DataContract? As(this DataContract dataContract, DataContractType dcType) + { + if (dataContract.GetContractType() == dcType) + return dataContract; + return null; + } + + internal static bool IsItemTypeNullable(this DataContract collectionDataContract) + { + if (collectionDataContract.GetContractType() == DataContractType.CollectionDataContract) + { + // ItemContract - aka BaseContract - is never null for CollectionDataContract + return SchemaImportHelper.IsTypeNullable(collectionDataContract.BaseContract!.UnderlyingType); + } + + return false; + } + } + + internal static class SchemaImportHelper + { + internal static bool IsTypeNullable(Type type) + { + return !type.IsValueType || + (type.IsGenericType && + type.GetGenericTypeDefinition() == typeof(Nullable<>)); + } + + internal static string GetCollectionNamespace(string elementNs) + { + return IsBuiltInNamespace(elementNs) ? ImportGlobals.CollectionsNamespace : elementNs; + } + + internal static string GetDataContractNamespaceFromUri(string uriString) + { + return uriString.StartsWith(ImportGlobals.DataContractXsdBaseNamespace, StringComparison.Ordinal) ? uriString.Substring(ImportGlobals.DataContractXsdBaseNamespace.Length) : uriString; + } + + internal static string GetDefaultXmlNamespace(string? clrNs) + { + if (clrNs == null) clrNs = string.Empty; + return new Uri(ImportGlobals.DataContractXsdBaseNamespaceUri, clrNs).AbsoluteUri; + } + + internal static bool IsBuiltInNamespace(string ns) + { + return (ns == ImportGlobals.SchemaNamespace || ns == ImportGlobals.SerializationNamespace); + } + + // This should match the behavior of DataContract.EncodeLocalName + internal static string EncodeLocalName(string localName) + { + if (IsAsciiLocalName(localName)) + return localName; + + if (IsValidNCName(localName)) + return localName; + + return XmlConvert.EncodeLocalName(localName); + } + + private static bool IsAsciiLocalName(string localName) + { + if (localName.Length == 0) + return false; + if (!char.IsAsciiLetter(localName[0])) + return false; + for (int i = 1; i < localName.Length; i++) + { + char ch = localName[i]; + if (!char.IsAsciiLetterOrDigit(ch)) + return false; + } + return true; + } + + private static bool IsValidNCName(string name) + { + try + { + XmlConvert.VerifyNCName(name); + return true; + } + catch (XmlException) + { + return false; + } + } + } +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs deleted file mode 100644 index 07accbceac432..0000000000000 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractExporter.cs +++ /dev/null @@ -1,393 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Xml; -using System.Xml.Schema; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Reflection; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; - -using ExceptionUtil = System.Runtime.Serialization.Schema.DiagnosticUtility.ExceptionUtility; - -namespace System.Runtime.Serialization.Schema -{ - /// - /// Allows the transformation of a set of .NET types that are used in data contracts into an XML schema file (.xsd). - /// - /// - /// Use the class when you have created a Web service that incorporates data represented by - /// common language runtime (CLR) types and when you need to export XML schemas for each type to be consumed by other Web services. - /// That is, transforms a set of CLR types into XML schemas. The schemas can then be exposed - /// through a Web Services Description Language (WSDL) document for use by others who need to interoperate with your service. - /// - /// Conversely, if you are creating a Web service that must interoperate with an existing Web service, use the - /// to transform XML schemas and create the CLR types that represent the data in a selected programming language. - /// - /// The generates an object that contains the collection of schemas. - /// Access the set of schemas through the property. - /// - public sealed class XsdDataContractExporter - { - private ExportOptions? _options; - private XmlSchemaSet? _schemas; - private DataContractSet? _dataContractSet; - - /// - /// Initializes a new instance of the class. - /// - public XsdDataContractExporter() - { - } - - /// - /// Initializes a new instance of the class with the specified set of schemas. - /// - /// An that contains the schemas to be exported. - public XsdDataContractExporter(XmlSchemaSet? schemas) - { - this._schemas = schemas; - } - - /// - /// Gets or sets an that contains options that can be set for the export operation. - /// - public ExportOptions? Options - { - get { return _options; } - set { _options = value; } - } - - /// - /// Gets the collection of exported XML schemas. - /// - public XmlSchemaSet Schemas - { - get - { - XmlSchemaSet schemaSet = GetSchemaSet(); - SchemaHelper.CompileSchemaSet(schemaSet); - return schemaSet; - } - } - - private XmlSchemaSet GetSchemaSet() - { - if (_schemas == null) - { - _schemas = new XmlSchemaSet(); - _schemas.XmlResolver = null; - } - return _schemas; - } - - private DataContractSet DataContractSet - { - get - { - if (_dataContractSet == null) - { - _dataContractSet = new DataContractSet(Options?.SurrogateProvider, null, null); - } - return _dataContractSet; - } - } - - private static void EnsureTypeNotGeneric(Type type) - { - if (type.ContainsGenericParameters) - throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.GenericTypeNotExportable, type))); - } - - /// - /// Transforms the types contained in the specified collection of assemblies. - /// - /// A (of ) that contains the types to export. - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - public void Export(ICollection assemblies) - { - ArgumentNullException.ThrowIfNull(assemblies); - - DataContractSet? oldValue = (_dataContractSet == null) ? null : new DataContractSet(_dataContractSet); - try - { - foreach (Assembly assembly in assemblies) - { - if (assembly == null) - throw ExceptionUtil.ThrowHelperError(new ArgumentException(SR.Format(SR.CannotExportNullAssembly, nameof(assemblies)))); - - Type[] types = assembly.GetTypes(); - for (int j = 0; j < types.Length; j++) - CheckAndAddType(types[j]); - } - - Export(); - } - catch - { - _dataContractSet = oldValue; - throw; - } - } - - /// - /// Transforms the types contained in the passed to this method. - /// - /// A (of ) that contains the types to export. - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - public void Export(ICollection types) - { - ArgumentNullException.ThrowIfNull(types); - - DataContractSet? oldValue = (_dataContractSet == null) ? null : new DataContractSet(_dataContractSet); - try - { - foreach (Type type in types) - { - if (type == null) - throw ExceptionUtil.ThrowHelperError(new ArgumentException(SR.Format(SR.CannotExportNullType, nameof(types)))); - AddType(type); - } - - Export(); - } - catch - { - _dataContractSet = oldValue; - throw; - } - } - - /// - /// Transforms the specified .NET Framework type into an XML schema definition language (XSD) schema. - /// - /// The to transform into an XML schema. - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - public void Export(Type type) - { - ArgumentNullException.ThrowIfNull(type); - - DataContractSet? oldValue = (_dataContractSet == null) ? null : new DataContractSet(_dataContractSet); - try - { - AddType(type); - Export(); - } - catch - { - _dataContractSet = oldValue; - throw; - } - } - - /// - /// Returns the contract name and contract namespace for the . - /// - /// The that was exported. - /// An that represents the contract name of the type and its namespace. - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - public XmlQualifiedName GetSchemaTypeName(Type type) - { - ArgumentNullException.ThrowIfNull(type); - - type = GetSurrogatedType(type); - DataContract dataContract = DataContract.GetDataContract(type); - EnsureTypeNotGeneric(dataContract.UnderlyingType); - if (dataContract is XmlDataContract xmlDataContract && xmlDataContract.IsAnonymous) - return XmlQualifiedName.Empty; - return dataContract.StableName; - } - - /// - /// Returns the XML schema type for the specified type. - /// - /// The type to return a schema for. - /// An that contains the XML schema. - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - public XmlSchemaType? GetSchemaType(Type type) - { - ArgumentNullException.ThrowIfNull(type); - - type = GetSurrogatedType(type); - DataContract dataContract = DataContract.GetDataContract(type); - EnsureTypeNotGeneric(dataContract.UnderlyingType); - if (dataContract is XmlDataContract xmlDataContract && xmlDataContract.IsAnonymous) - return xmlDataContract.XsdType; - return null; - } - - /// - /// Returns the top-level name and namespace for the . - /// - /// The to query. - /// The that represents the top-level name and namespace for this Type, which is written to the stream when writing this object. - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - public XmlQualifiedName? GetRootElementName(Type type) - { - ArgumentNullException.ThrowIfNull(type); - - type = GetSurrogatedType(type); - DataContract dataContract = DataContract.GetDataContract(type); - EnsureTypeNotGeneric(dataContract.UnderlyingType); - if (dataContract is not XmlDataContract xdc || xdc.HasRoot) // All non-XmlDataContracts "have root". - { - return new XmlQualifiedName(dataContract.TopLevelElementName!.Value, dataContract.TopLevelElementNamespace!.Value); - } - else - { - return null; - } - } - - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - private Type GetSurrogatedType(Type type) - { - ISerializationSurrogateProvider? surrogate = Options?.SurrogateProvider; - if (surrogate != null) - type = DataContract.GetSurrogateType(surrogate, type); - return type; - } - - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - private void CheckAndAddType(Type type) - { - type = GetSurrogatedType(type); - if (!type.ContainsGenericParameters && DataContract.IsTypeSerializable(type)) - AddType(type); - } - - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - private void AddType(Type type) - { - DataContractSet.Add(type); - } - - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - private void Export() - { - AddKnownTypes(); - DataContractSet.ExportSchemaSet(GetSchemaSet()); - } - - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - private void AddKnownTypes() - { - if (Options != null) - { - Collection knownTypes = Options.KnownTypes; - - if (knownTypes != null) - { - for (int i = 0; i < knownTypes.Count; i++) - { - Type type = knownTypes[i]; - if (type == null) - throw ExceptionUtil.ThrowHelperError(new ArgumentException(SR.CannotExportNullKnownType)); - AddType(type); - } - } - } - } - - /// - /// Gets a value that indicates whether the set of .common language runtime (CLR) types contained in a set of assemblies can be exported. - /// - /// A of that contains the assemblies with the types to export. - /// true if the types can be exported; otherwise, false. - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - public bool CanExport(ICollection assemblies) - { - ArgumentNullException.ThrowIfNull(assemblies); - - DataContractSet? oldValue = (_dataContractSet == null) ? null : new DataContractSet(_dataContractSet); - try - { - foreach (Assembly assembly in assemblies) - { - if (assembly == null) - throw ExceptionUtil.ThrowHelperError(new ArgumentException(SR.Format(SR.CannotExportNullAssembly, nameof(assemblies)))); - - Type[] types = assembly.GetTypes(); - for (int j = 0; j < types.Length; j++) - CheckAndAddType(types[j]); - } - AddKnownTypes(); - return true; - } - catch (InvalidDataContractException) - { - _dataContractSet = oldValue; - return false; - } - catch - { - _dataContractSet = oldValue; - throw; - } - } - - /// - /// Gets a value that indicates whether the set of .common language runtime (CLR) types contained in a can be exported. - /// - /// A that contains the specified types to export. - /// true if the types can be exported; otherwise, false. - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - public bool CanExport(ICollection types) - { - ArgumentNullException.ThrowIfNull(types); - - DataContractSet? oldValue = (_dataContractSet == null) ? null : new DataContractSet(_dataContractSet); - try - { - foreach (Type type in types) - { - if (type == null) - throw ExceptionUtil.ThrowHelperError(new ArgumentException(SR.Format(SR.CannotExportNullType, nameof(types)))); - AddType(type); - } - AddKnownTypes(); - return true; - } - catch (InvalidDataContractException) - { - _dataContractSet = oldValue; - return false; - } - catch - { - _dataContractSet = oldValue; - throw; - } - } - - /// - /// Gets a value that indicates whether the specified common language runtime (CLR) type can be exported. - /// - /// The to export. - /// true if the type can be exported; otherwise, false. - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] - public bool CanExport(Type type) - { - ArgumentNullException.ThrowIfNull(type); - - DataContractSet? oldValue = (_dataContractSet == null) ? null : new DataContractSet(_dataContractSet); - try - { - AddType(type); - AddKnownTypes(); - return true; - } - catch (InvalidDataContractException) - { - _dataContractSet = oldValue; - return false; - } - catch - { - _dataContractSet = oldValue; - throw; - } - } - } -} diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs index 6785fa14d2c46..24b3db31024fa 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs @@ -6,12 +6,13 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Runtime.Serialization.DataContracts; using System.Xml; using System.Xml.Schema; -using ExceptionUtil = System.Runtime.Serialization.Schema.DiagnosticUtility.ExceptionUtility; +using ExceptionUtil = System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility; -namespace System.Runtime.Serialization.Schema +namespace System.Runtime.Serialization { /// /// Allows the transformation of a set of XML schema files (.xsd) into common language runtime (CLR) types. @@ -26,7 +27,7 @@ namespace System.Runtime.Serialization.Schema /// data represented by CLR types and when you need to export XML schemas for each data type to be consumed by other Web /// services.That is, transforms a set of CLR types into a set of XML schemas. /// - public sealed class XsdDataContractImporter + public class XsdDataContractImporter { private CodeCompileUnit _codeCompileUnit = null!; // Not directly referenced. Always lazy initialized by property getter. private DataContractSet? _dataContractSet; @@ -68,7 +69,7 @@ private DataContractSet DataContractSet if (_dataContractSet == null) { _dataContractSet = Options == null ? new DataContractSet(null, null, null) : - new DataContractSet(Options.SurrogateProvider, Options.ReferencedTypes, Options.ReferencedCollectionTypes); + new DataContractSet(Options.DataContractSurrogate, Options.ReferencedTypes, Options.ReferencedCollectionTypes); } return _dataContractSet; } @@ -78,7 +79,7 @@ private DataContractSet DataContractSet /// Transforms the specified set of XML schemas contained in an into a . /// /// A that contains the schema representations to generate CLR types for. - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] public void Import(XmlSchemaSet schemas) { if (schemas == null) @@ -92,7 +93,7 @@ public void Import(XmlSchemaSet schemas) /// /// A that contains the schema representations. /// A (of ) that represents the set of schema types to import. - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] public void Import(XmlSchemaSet schemas, ICollection typeNames) { if (schemas == null) @@ -109,7 +110,7 @@ public void Import(XmlSchemaSet schemas, ICollection typeNames /// /// A that contains the schema representations. /// A that represents a specific schema type to import. - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] public void Import(XmlSchemaSet schemas, XmlQualifiedName typeName) { if (schemas == null) @@ -129,7 +130,7 @@ public void Import(XmlSchemaSet schemas, XmlQualifiedName typeName) /// An that contains the schemas to transform. /// An that represents the specific schema element to transform. /// An that represents the specified element. - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] public XmlQualifiedName? Import(XmlSchemaSet schemas, XmlSchemaElement element) { if (schemas == null) @@ -149,7 +150,7 @@ public void Import(XmlSchemaSet schemas, XmlQualifiedName typeName) /// /// A that contains the schemas to transform. /// true if the schemas can be transformed to data contract types; otherwise, false. - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] public bool CanImport(XmlSchemaSet schemas) { if (schemas == null) @@ -164,7 +165,7 @@ public bool CanImport(XmlSchemaSet schemas) /// A that contains the schemas to transform. /// An of that represents the set of schema types to import. /// true if the schemas can be transformed; otherwise, false. - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] public bool CanImport(XmlSchemaSet schemas, ICollection typeNames) { if (schemas == null) @@ -182,7 +183,7 @@ public bool CanImport(XmlSchemaSet schemas, ICollection typeNa /// A that contains the schema representations. /// An that specifies the names of the schema types that need to be imported from the . /// true if the schemas can be transformed to data contract types; otherwise, false. - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] public bool CanImport(XmlSchemaSet schemas, XmlQualifiedName typeName) { if (schemas == null) @@ -200,7 +201,7 @@ public bool CanImport(XmlSchemaSet schemas, XmlQualifiedName typeName) /// An to import. /// A specific to check in the set of schemas. /// true if the element can be imported; otherwise, false. - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] public bool CanImport(XmlSchemaSet schemas, XmlSchemaElement element) { if (schemas == null) @@ -218,7 +219,7 @@ public bool CanImport(XmlSchemaSet schemas, XmlSchemaElement element) /// /// The that specifies the schema type to look up. /// A reference to the CLR type generated for the schema type with the typeName specified. - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] public CodeTypeReference GetCodeTypeReference(XmlQualifiedName typeName) { DataContract dataContract = FindDataContract(typeName); @@ -232,7 +233,7 @@ public CodeTypeReference GetCodeTypeReference(XmlQualifiedName typeName) /// An that specifies the XML qualified name of the schema type to look up. /// An that specifies an element in an XML schema. /// A that represents the type that was generated for the specified schema type. - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] public CodeTypeReference GetCodeTypeReference(XmlQualifiedName typeName, XmlSchemaElement element) { if (element == null) @@ -244,7 +245,7 @@ public CodeTypeReference GetCodeTypeReference(XmlQualifiedName typeName, XmlSche return codeExporter.GetElementTypeReference(dataContract, element.IsNillable); } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] internal DataContract FindDataContract(XmlQualifiedName typeName) { if (typeName == null) @@ -265,7 +266,7 @@ internal DataContract FindDataContract(XmlQualifiedName typeName) /// /// An that represents the schema type to look up known types for. /// A collection of type . - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] public ICollection? GetKnownTypeReferences(XmlQualifiedName typeName) { if (typeName == null) @@ -303,7 +304,7 @@ private XmlSchemaElement[] SingleElementArray } } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private IList? InternalImport(XmlSchemaSet schemas, ICollection? typeNames, ICollection? elements) { DataContractSet? oldValue = (_dataContractSet == null) ? null : new DataContractSet(_dataContractSet); @@ -335,7 +336,7 @@ private bool ImportXmlDataType } } - [RequiresUnreferencedCode(Globals.SerializerTrimmerWarning)] + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private bool InternalCanImport(XmlSchemaSet schemas, ICollection? typeNames, ICollection? elements) { DataContractSet? oldValue = (_dataContractSet == null) ? null : new DataContractSet(_dataContractSet); @@ -347,7 +348,7 @@ private bool InternalCanImport(XmlSchemaSet schemas, ICollection s_actualTypeAnnotationName ??= new XmlQualifiedName(Globals.ActualTypeLocalName, Globals.SerializationNamespace); + internal static XmlQualifiedName ActualTypeAnnotationName => s_actualTypeAnnotationName ??= new XmlQualifiedName(ImportGlobals.ActualTypeLocalName, ImportGlobals.SerializationNamespace); internal static XmlQualifiedName ImportActualType(XmlSchemaAnnotation? annotation, XmlQualifiedName defaultTypeName, XmlQualifiedName typeName) { @@ -368,12 +369,12 @@ internal static XmlQualifiedName ImportActualType(XmlSchemaAnnotation? annotatio if (actualTypeElement == null) return defaultTypeName; - XmlNode? nameAttribute = actualTypeElement.Attributes.GetNamedItem(Globals.ActualTypeNameAttribute); + XmlNode? nameAttribute = actualTypeElement.Attributes.GetNamedItem(ImportGlobals.ActualTypeNameAttribute); if (nameAttribute?.Value == null) - throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.AnnotationAttributeNotFound, ActualTypeAnnotationName.Name, typeName.Name, typeName.Namespace, Globals.ActualTypeNameAttribute))); - XmlNode? nsAttribute = actualTypeElement.Attributes.GetNamedItem(Globals.ActualTypeNamespaceAttribute); + throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.AnnotationAttributeNotFound, ActualTypeAnnotationName.Name, typeName.Name, typeName.Namespace, ImportGlobals.ActualTypeNameAttribute))); + XmlNode? nsAttribute = actualTypeElement.Attributes.GetNamedItem(ImportGlobals.ActualTypeNamespaceAttribute); if (nsAttribute?.Value == null) - throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.AnnotationAttributeNotFound, ActualTypeAnnotationName.Name, typeName.Name, typeName.Namespace, Globals.ActualTypeNamespaceAttribute))); + throw ExceptionUtil.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.AnnotationAttributeNotFound, ActualTypeAnnotationName.Name, typeName.Name, typeName.Namespace, ImportGlobals.ActualTypeNamespaceAttribute))); return new XmlQualifiedName(nameAttribute.Value, nsAttribute.Value); } diff --git a/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs b/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs index bbb0a59660cf7..b42c43aa1f64a 100644 --- a/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs +++ b/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs @@ -6,46 +6,6 @@ namespace System.Runtime.Serialization { - public abstract partial class DataContract - { - public virtual DataContract? BaseContract { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } } - public virtual string? ContractType { get { throw null; } } - internal DataContract(DataContractCriticalHelper helper) { } - internal const System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes DataContractPreserveMemberTypes = - System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods | - System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicMethods | - System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | - System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicConstructors | - System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | - System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties; - public static string EncodeLocalName(string localName) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public virtual System.Xml.XmlQualifiedName GetArrayTypeName(bool isNullable) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public static DataContract? GetBuiltInDataContract(string name, string ns) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public static DataContract GetDataContract(Type type) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public static System.Xml.XmlQualifiedName GetStableName(Type type) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public static Type GetSurrogateType(ISerializationSurrogateProvider surrogateProvider, Type type) { throw null; } - public virtual bool IsBuiltInDataContract { get { throw null; } } - public virtual bool IsISerializable { get { throw null; } } - public virtual bool IsKeyValue(out string? keyName, out string? valueName, out string? itemName) { throw null; } - public virtual bool IsReference { get { throw null; } } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public static bool IsTypeSerializable(Type type) { throw null; } - public virtual bool IsValueType { get { throw null; } } - public virtual System.Collections.Generic.Dictionary? KnownDataContracts { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } set { throw null; } } - public virtual System.Collections.Generic.List? Members { get { throw null; } } - public virtual Type OriginalUnderlyingType { get { throw null; } } - public virtual System.Xml.XmlQualifiedName StableName { get { throw null; } } - [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(DataContract.DataContractPreserveMemberTypes)] - public virtual Type UnderlyingType { get { throw null; } } - public virtual System.Xml.XmlDictionaryString? TopLevelElementName { get { throw null; } } - public virtual System.Xml.XmlDictionaryString? TopLevelElementNamespace { get { throw null; } } - } - internal abstract partial class DataContractCriticalHelper { } public abstract partial class DataContractResolver { protected DataContractResolver() { } @@ -115,44 +75,11 @@ public DataContractSerializerSettings() { } public System.Xml.XmlDictionaryString? RootNamespace { get { throw null; } set { } } public bool SerializeReadOnlyTypes { get { throw null; } set { } } } - public sealed partial class DataContractSet - { - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public void Add(Type type) { throw null; } - public System.Collections.Generic.Dictionary Contracts { get { throw null; } } - public DataContractSet(ISerializationSurrogateProvider? dataContractSurrogate, System.Collections.Generic.ICollection? referencedTypes, System.Collections.Generic.ICollection? referencedCollectionTypes) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public DataContractSet(DataContractSet dataContractSet) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public void ExportSchemaSet(System.Xml.Schema.XmlSchemaSet schemaSet) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public DataContract GetDataContract(Type type) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public DataContract? GetDataContract(System.Xml.XmlQualifiedName key) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public Type? GetReferencedType(System.Xml.XmlQualifiedName stableName, DataContract dataContract, out DataContract? referencedContract, out object[]? genericParameters, bool? supportGenericTypes = null) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public void ImportSchemaSet(System.Xml.Schema.XmlSchemaSet schemaSet, System.Collections.Generic.ICollection? typeNames, bool importXmlDataType) { throw null; } - [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] - public System.Collections.Generic.IList ImportSchemaSet(System.Xml.Schema.XmlSchemaSet schemaSet, System.Collections.Generic.ICollection elements, bool importXmlDataType) { throw null; } - public System.Collections.Generic.Dictionary? KnownTypesForObject { get { throw null; } } - public System.Collections.Generic.Dictionary ProcessedContracts { get { throw null; } } - public System.Collections.Hashtable SurrogateData { get { throw null; } } - } - public sealed partial class DataMember - { - internal DataMember() { } - public bool EmitDefaultValue { get { throw null; } } - public bool IsNullable { get { throw null; } } - public bool IsRequired { get { throw null; } } - public DataContract MemberTypeContract { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } } - public string Name { get { throw null; } } - public long Order { get { throw null; } } - } public partial class ExportOptions { public ExportOptions() { } public System.Collections.ObjectModel.Collection KnownTypes { get { throw null; } } + public ISerializationSurrogateProvider? DataContractSurrogate { get { throw null; } set { throw null; } } } public sealed partial class ExtensionDataObject { @@ -162,16 +89,6 @@ public partial interface IExtensibleDataObject { System.Runtime.Serialization.ExtensionDataObject? ExtensionData { get; set; } } - public sealed partial class XmlDataContract : DataContract - { - public bool HasRoot { get { throw null; } } - public bool IsAnonymous { get { throw null; } } - public bool IsTopLevelElementNullable { get { throw null; } } - public bool IsTypeDefinedOnImport { get { throw null; } set { throw null; } } - public new bool IsValueType { get { throw null; } set { throw null; } } - internal XmlDataContract(Type type) : base(default) { } - public System.Xml.Schema.XmlSchemaType? XsdType { get { throw null; } } - } public abstract partial class XmlObjectSerializer { protected XmlObjectSerializer() { } @@ -554,3 +471,87 @@ public virtual void WriteXmlnsAttribute(string? prefix, string namespaceUri) { } public virtual void WriteXmlnsAttribute(string? prefix, System.Xml.XmlDictionaryString namespaceUri) { } } } +namespace System.Runtime.Serialization.DataContracts +{ + public abstract partial class DataContract + { + internal const System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes DataContractPreserveMemberTypes = + System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicMethods | + System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicMethods | + System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors | + System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicConstructors | + System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicFields | + System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicProperties; + + internal DataContract(DataContractCriticalHelper helper) { } + + public virtual DataContract? BaseContract { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } } + public virtual string? ContractType { get { throw null; } } + public virtual bool IsBuiltInDataContract { get { throw null; } } + public virtual bool IsISerializable { get { throw null; } } + public virtual bool IsReference { get { throw null; } } + public virtual bool IsValueType { get { throw null; } } + public virtual System.Collections.Generic.Dictionary? KnownDataContracts { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } } + public virtual System.Collections.Generic.List? Members { get { throw null; } } + public virtual Type OriginalUnderlyingType { get { throw null; } } + public virtual System.Xml.XmlQualifiedName XmlName { get { throw null; } } + [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(DataContract.DataContractPreserveMemberTypes)] + public virtual Type UnderlyingType { get { throw null; } } + public virtual System.Xml.XmlDictionaryString? TopLevelElementName { get { throw null; } } + public virtual System.Xml.XmlDictionaryString? TopLevelElementNamespace { get { throw null; } } + + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public static DataContract? GetBuiltInDataContract(string name, string ns) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public static System.Xml.XmlQualifiedName GetXmlName(Type type) { throw null; } + + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public virtual System.Xml.XmlQualifiedName GetArrayTypeName(bool isNullable) { throw null; } + public virtual bool IsDictionaryLike([Diagnostics.CodeAnalysis.NotNullWhen(true)] out string? keyName, [Diagnostics.CodeAnalysis.NotNullWhen(true)] out string? valueName, [Diagnostics.CodeAnalysis.NotNullWhen(true)] out string? itemName) { throw null; } + } + internal abstract partial class DataContractCriticalHelper { } + public sealed partial class DataContractSet + { + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public DataContractSet(DataContractSet dataContractSet) { throw null; } + public DataContractSet(ISerializationSurrogateProvider? dataContractSurrogate, System.Collections.Generic.IEnumerable? referencedTypes, System.Collections.Generic.IEnumerable? referencedCollectionTypes) { throw null; } + + public System.Collections.Generic.Dictionary Contracts { get { throw null; } } + public System.Collections.Generic.Dictionary? KnownTypesForObject { get { throw null; } } + public System.Collections.Generic.Dictionary ProcessedContracts { get { throw null; } } + public System.Collections.Hashtable SurrogateData { get { throw null; } } + + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public DataContract GetDataContract(Type type) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public DataContract? GetDataContract(System.Xml.XmlQualifiedName key) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public Type? GetReferencedType(System.Xml.XmlQualifiedName xmlName, DataContract dataContract, out DataContract? referencedContract, out object[]? genericParameters, bool? supportGenericTypes = null) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public void ImportSchemaSet(System.Xml.Schema.XmlSchemaSet schemaSet, System.Collections.Generic.IEnumerable? typeNames, bool importXmlDataType) { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] + public System.Collections.Generic.List ImportSchemaSet(System.Xml.Schema.XmlSchemaSet schemaSet, System.Collections.Generic.IEnumerable elements, bool importXmlDataType) { throw null; } + } + public sealed partial class DataMember + { + internal DataMember() { } + + public bool EmitDefaultValue { get { throw null; } } + public bool IsNullable { get { throw null; } } + public bool IsRequired { get { throw null; } } + public DataContract MemberTypeContract { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } } + public string Name { get { throw null; } } + public long Order { get { throw null; } } + } + public sealed partial class XmlDataContract : DataContract + { + internal XmlDataContract(Type type) : base(default) { } + + public bool HasRoot { get { throw null; } } + public bool IsAnonymous { get { throw null; } } + public bool IsTopLevelElementNullable { get { throw null; } } + public bool IsTypeDefinedOnImport { get { throw null; } set { throw null; } } + public new bool IsValueType { get { throw null; } set { throw null; } } + public System.Xml.Schema.XmlSchemaType? XsdType { get { throw null; } } + } +} diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/DataContractSerializer.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/DataContractSerializer.cs index a6fb375e8ad21..8f7c973033dae 100644 --- a/src/libraries/System.Runtime.Serialization.Xml/tests/DataContractSerializer.cs +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/DataContractSerializer.cs @@ -2727,14 +2727,6 @@ static string GenerateaAndGetXPath(Type t, MemberInfo[] mi) t, mi, out xname); } - [Fact] - public static void XsdDataContractExporterTest() - { - XsdDataContractExporter exporter = new XsdDataContractExporter(); - Assert.Throws(() => exporter.CanExport(typeof(Employee))); - Assert.Throws(() => exporter.Export(typeof(Employee))); - } - [Fact] public static void DCS_MyISerializableType() { From e868642ae8be42742db2715f5d36cb32d806c32c Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Tue, 2 Aug 2022 16:40:05 -0700 Subject: [PATCH 22/33] Port NetFx Export/Import test suites to Serializer test projects. --- .../tests/Expected.ImportedType.cs | 86 -- ....Runtime.Serialization.Schema.Tests.csproj | 13 +- .../Runtime/Serialization/Schema/Contracts.cs | 32 - .../Serialization/Schema/DataContracts.cs | 160 ++++ .../Runtime/Serialization/Schema/Export.cs | 47 - .../Runtime/Serialization/Schema/Import.cs | 58 -- .../Schema/Import/ImportOptionsTests.cs | 160 ++++ .../Schema/Import/ImporterTests.cs | 415 +++++++++ .../Schema/Import/SurrogateTests.cs | 220 +++++ .../Serialization/Schema/RoundTripTest.cs | 332 +++++++ .../Serialization/Schema/SchemaUtils.cs | 370 ++++++++ ...tem.Runtime.Serialization.Xml.Tests.csproj | 21 +- .../ExportOptionsTests.cs | 58 ++ .../ExporterApiTests.cs | 331 +++++++ .../ExporterTypesTests.cs | 842 ++++++++++++++++++ .../SchemaUtils.cs | 54 ++ .../SerializationTypes/ArrayTypes.cs | 102 +++ .../SerializationTypes/ConfigTypes.cs | 52 ++ .../ConflictingNameTypes.cs | 72 ++ .../DataContractSurrogate.cs | 98 ++ .../SerializationTypes/DataContractTypes.cs | 607 +++++++++++++ .../SerializationTypes/Enums.cs | 138 +++ .../SerializationTypes/GenericTypes.cs | 97 ++ .../SerializationTypes/ISerializableTypes.cs | 113 +++ .../IXmlSerializableTypes.cs | 399 +++++++++ .../SerializationTypes/LegacyTypes.cs | 42 + .../SerializationTypes/NullableTypes.cs | 66 ++ .../SerializationTypes/PartialTrust.cs | 110 +++ .../SerializationTypes/SerializableTypes.cs | 67 ++ .../SerializationTypes.csproj | 21 + .../SurrogateTests.cs | 525 +++++++++++ .../XsdDataContractExporterTests/Types.cs | 138 +++ 32 files changed, 5615 insertions(+), 231 deletions(-) delete mode 100644 src/libraries/System.Runtime.Serialization.Schema/tests/Expected.ImportedType.cs delete mode 100644 src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Contracts.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/DataContracts.cs delete mode 100644 src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Export.cs delete mode 100644 src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import/ImportOptionsTests.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import/ImporterTests.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import/SurrogateTests.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/RoundTripTest.cs create mode 100644 src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/SchemaUtils.cs create mode 100644 src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExportOptionsTests.cs create mode 100644 src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExporterApiTests.cs create mode 100644 src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExporterTypesTests.cs create mode 100644 src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SchemaUtils.cs create mode 100644 src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/ArrayTypes.cs create mode 100644 src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/ConfigTypes.cs create mode 100644 src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/ConflictingNameTypes.cs create mode 100644 src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/DataContractSurrogate.cs create mode 100644 src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/DataContractTypes.cs create mode 100644 src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/Enums.cs create mode 100644 src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/GenericTypes.cs create mode 100644 src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/ISerializableTypes.cs create mode 100644 src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/IXmlSerializableTypes.cs create mode 100644 src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/LegacyTypes.cs create mode 100644 src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/NullableTypes.cs create mode 100644 src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/PartialTrust.cs create mode 100644 src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/SerializableTypes.cs create mode 100644 src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/SerializationTypes.csproj create mode 100644 src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SurrogateTests.cs create mode 100644 src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/Types.cs diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/Expected.ImportedType.cs b/src/libraries/System.Runtime.Serialization.Schema/tests/Expected.ImportedType.cs deleted file mode 100644 index 636f23927e195..0000000000000 --- a/src/libraries/System.Runtime.Serialization.Schema/tests/Expected.ImportedType.cs +++ /dev/null @@ -1,86 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -[assembly: System.Runtime.Serialization.ContractNamespaceAttribute("www.Contoso.com/Examples/", ClrNamespace="www.Contoso.com.Examples")] - -namespace www.Contoso.com.Examples -{ - using System.Runtime.Serialization; - - - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization.Schema", "7.0.0.0")] - [System.Runtime.Serialization.DataContractAttribute(Name="Employee", Namespace="www.Contoso.com/Examples/")] - internal partial class Employee : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged - { - - private System.Runtime.Serialization.ExtensionDataObject extensionDataField; - - private string EmployeeNameField; - - private string IDField; - - public System.Runtime.Serialization.ExtensionDataObject ExtensionData - { - get - { - return this.extensionDataField; - } - set - { - this.extensionDataField = value; - } - } - - [System.Runtime.Serialization.DataMemberAttribute()] - internal string EmployeeName - { - get - { - return this.EmployeeNameField; - } - set - { - if ((object.ReferenceEquals(this.EmployeeNameField, value) != true)) - { - this.EmployeeNameField = value; - this.RaisePropertyChanged("EmployeeName"); - } - } - } - - [System.Runtime.Serialization.DataMemberAttribute()] - internal string ID - { - get - { - return this.IDField; - } - set - { - if ((object.ReferenceEquals(this.IDField, value) != true)) - { - this.IDField = value; - this.RaisePropertyChanged("ID"); - } - } - } - - public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; - - protected void RaisePropertyChanged(string propertyName) - { - System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged; - if ((propertyChanged != null)) - { - propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); - } - } - } -} diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/System.Runtime.Serialization.Schema.Tests.csproj b/src/libraries/System.Runtime.Serialization.Schema/tests/System.Runtime.Serialization.Schema.Tests.csproj index 760c6abace0ae..6515ccf393647 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/tests/System.Runtime.Serialization.Schema.Tests.csproj +++ b/src/libraries/System.Runtime.Serialization.Schema/tests/System.Runtime.Serialization.Schema.Tests.csproj @@ -5,13 +5,12 @@ - - - - - - - + + + + + + diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Contracts.cs b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Contracts.cs deleted file mode 100644 index 78fe56f0b5e4a..0000000000000 --- a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Contracts.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Runtime.Serialization.Schema.Tests -{ - internal class ContractUtils - { - internal const string ExpectedImportedTypeFile = "Expected.ImportedType.cs"; - internal const string TestNamespace = "www.Contoso.com/Examples/"; - internal const string ExpectedEmployeeSchema = @" - - - - - - - - -"; - } - -#pragma warning disable CS0169, IDE0051, IDE1006 - [DataContract(Namespace = ContractUtils.TestNamespace)] - public class Employee - { - [DataMember] - public string EmployeeName; - [DataMember] - private string ID; - } -#pragma warning restore CS0169, IDE0051, IDE1006 -} diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/DataContracts.cs b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/DataContracts.cs new file mode 100644 index 0000000000000..77d12cf9e6d4c --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/DataContracts.cs @@ -0,0 +1,160 @@ +using System.Runtime.Serialization; +using System.Xml.Serialization; + +[assembly: ContractNamespace("http://special1.tempuri.org", ClrNamespace = "System.Runtime.Serialization.Schema.Tests.DataContracts")] + +namespace System.Runtime.Serialization.Schema.Tests.DataContracts +{ + [DataContract(Namespace = "http://basic")] + public class Point + { + [DataMember] + public int X = 42; + [DataMember] + public int Y = 43; + } + + [DataContract(Namespace = "http://shapes")] + public class Circle + { + [DataMember] + public Point Center = new Point(); + [DataMember] + public int Radius = 5; + } + + [DataContract(Namespace = "http://shapes")] + public class Square + { + [DataMember] + public Point BottomLeft = new Point(); + [DataMember] + public int Side = 5; + } + + public struct NonAttributedPersonStruct + { + public string firstName; + public string lastName; + } + + public class NonAttributedPersonClass + { + public string firstName = "John"; + public string lastName = "Smith"; + + internal NonAttributedPersonClass() + { + } + } + + public class ExtendedSquare : Square + { + public string lineColor = "black"; + } + + [DataContract(Name = "AnotherValidType", Namespace = "http://schemas.datacontract.org/2004/07/barNs")] + public class AnotherValidType + { + [DataMember] + public string member; + } + + [DataContract(Name = "AnotherValidType", Namespace = "http://schemas.datacontract.org/2004/07/barNs")] + public class ConflictingAnotherValidType + { + [DataMember] + public string member; + } + + public class NonAttributedType + { + public NonAttributedSquare Length; + } + + public class NonAttributedSquare + { + public int Length; + } + + [DataContract(IsReference = true)] + public class RefType1 + { + } + + [DataContract] + public class NonRefType + { + } + + [Serializable] + public class ISerializableFormatClass : ISerializable + { + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + } + } + +#pragma warning disable CS0169, IDE0051, IDE1006 + #region SurrogateTests + [XmlRoot("XmlSerializerPersonElement")] + public class XmlSerializerPerson + { + public XmlSerializerPerson() { } + [XmlAttribute] + public string Name; + [XmlAttribute] + public int Age; + } + + [DataContract] + public class CircleContainer + { + [DataMember] + public SerializableCircle Circle { get { return null; } set { } } + [DataMember] + SerializableCircle[] circles; + } + + [Serializable] + public class SerializableCircle + { + public int Radius; + } + + [Serializable] + public class SerializableSquare + { + public int Side; + } + + public class Node + { + Node next; + } + + [Serializable] + public class SerializableNode + { + SerializableNode next; + } + #endregion + + [DataContract] + public class SerializableClass + { + [DataMember] + string member; + + [DataMember(Order = 3)] + string v3member; + } + + [DataContract] + public class DerivedClass : SerializableClass + { + [DataMember] + SerializableClass[] derivedMember; + } +#pragma warning restore CS0169, IDE0051, IDE1006 +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Export.cs b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Export.cs deleted file mode 100644 index a57540c967bda..0000000000000 --- a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Export.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.IO; -using System.Runtime.Serialization.Schema; -using System.Xml; -using System.Xml.Schema; -using Xunit; - -namespace System.Runtime.Serialization.Schema.Tests -{ - public class ExportTests - { - [Fact] - static void ExportXSD() - { - XsdDataContractExporter exporter = new XsdDataContractExporter(); - Assert.True(exporter.CanExport(typeof(Employee))); - exporter.Export(typeof(Employee)); - Assert.Equal(3, exporter.Schemas.Count); - - XmlSchemaSet mySchemas = exporter.Schemas; - XmlQualifiedName XmlNameValue = exporter.GetRootElementName(typeof(Employee)); - string EmployeeNameSpace = XmlNameValue.Namespace; - Assert.Equal(ContractUtils.TestNamespace, EmployeeNameSpace); - - var employeeSchemas = mySchemas.Schemas(EmployeeNameSpace); - Assert.Single(employeeSchemas); - foreach (XmlSchema schema in employeeSchemas) - { - StringWriter sw = new StringWriter(); - schema.Write(sw); - Assert.Equal(ContractUtils.ExpectedEmployeeSchema, sw.ToString()); - } - } - - [Fact] - static void GetXmlElementName() - { - XsdDataContractExporter myExporter = new XsdDataContractExporter(); - XmlQualifiedName xmlElementName = myExporter.GetRootElementName(typeof(Employee)); - Assert.False(xmlElementName.IsEmpty); - Assert.Equal(ContractUtils.TestNamespace, xmlElementName.Namespace); - Assert.Equal("Employee", xmlElementName.Name); - } - } -} diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import.cs b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import.cs deleted file mode 100644 index 2fa2ee75c3ae7..0000000000000 --- a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.CodeDom; -using System.CodeDom.Compiler; -using System.Globalization; -using System.IO; -using System.Reflection; -using System.Runtime.Serialization.Schema; -using System.Xml; -using System.Xml.Schema; -using Xunit; - -namespace System.Runtime.Serialization.Schema.Tests -{ - public class ImportTests - { - [Fact] - [SkipOnPlatform(TestPlatforms.Browser, "ExpectedImportedTypeFile not available in browser.")] - static void ImportXSD() - { - XsdDataContractExporter exporter = new XsdDataContractExporter(); - exporter.Export(typeof(Employee)); - XmlSchemaSet schemas = exporter.Schemas; - - ImportOptions opts = new ImportOptions() - { - EnableDataBinding = true, - GenerateInternal = true, - }; - XsdDataContractImporter importer = new XsdDataContractImporter() { Options = opts }; - Assert.True(importer.CanImport(schemas)); - importer.Import(schemas); - - CodeCompileUnit ccu = importer.CodeCompileUnit; - Assert.NotNull(ccu); - - string importedTypeCodeCS = CompileCode(ccu, new Microsoft.CSharp.CSharpCodeProvider()); - Assert.Equal(LineEndingsHelper.Normalize(File.ReadAllText(ContractUtils.ExpectedImportedTypeFile)), importedTypeCodeCS); - - //string importedTypeCodeVB = CompileCode(ccu, new Microsoft.VisualBasic.VBCodeProvider()); - } - - - static string CompileCode(CodeCompileUnit ccu, CodeDomProvider provider) - { - CodeGeneratorOptions options = new CodeGeneratorOptions() - { - BlankLinesBetweenMembers = true, - BracingStyle = "C", - }; - - StringWriter sw = new StringWriter(); - provider.GenerateCodeFromCompileUnit(ccu, sw, options); - return sw.ToString(); - } - } -} diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import/ImportOptionsTests.cs b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import/ImportOptionsTests.cs new file mode 100644 index 0000000000000..49867cc07ba88 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import/ImportOptionsTests.cs @@ -0,0 +1,160 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Runtime.Serialization.Schema; +using System.Runtime.Serialization.Schema.Tests.DataContracts; +using System.Xml; +using System.Xml.Schema; +using Xunit; +using Xunit.Abstractions; + +namespace System.Runtime.Serialization.Schema.Tests +{ + public class ImportOptionsTests + { + private readonly ITestOutputHelper _output; + + public ImportOptionsTests(ITestOutputHelper output) + { + _output = output; + } + + [Fact] + public void DefaultOptions() + { + XsdDataContractImporter importer = SchemaUtils.CreateImporterWithDefaultOptions(); + Assert.NotNull(importer); + Assert.NotNull(importer.Options); + Assert.False(importer.Options.EnableDataBinding); + Assert.False(importer.Options.GenerateInternal); + Assert.False(importer.Options.GenerateSerializable); + Assert.False(importer.Options.ImportXmlType); + Assert.Null(importer.Options.CodeProvider); + Assert.NotNull(importer.Options.Namespaces); + Assert.Empty(importer.Options.Namespaces); + Assert.NotNull(importer.Options.ReferencedCollectionTypes); + Assert.Empty(importer.Options.ReferencedCollectionTypes); + Assert.NotNull(importer.Options.ReferencedTypes); + Assert.Empty(importer.Options.ReferencedTypes); + Assert.Null(importer.Options.DataContractSurrogate); + } + + [Fact] + public void GetImportOptions() + { + XsdDataContractImporter importer = new XsdDataContractImporter(); + importer.Options = new ImportOptions(); + Assert.NotNull(importer.Options); + } + + [Fact] + public void SetImportOptions() + { + XsdDataContractImporter e = new XsdDataContractImporter(); + e.Options = new ImportOptions(); + e.Options.Namespaces.Add("Test", "http://schemas.datacontract.org/2004/07/fooNs"); + Assert.Single(e.Options.Namespaces); + } + + [Fact] + public void GenerateInternal() + { + XsdDataContractImporter importer = SchemaUtils.CreateImporterWithDefaultOptions(); + importer.Options.GenerateInternal = true; + importer.Import(SchemaUtils.PositiveSchemas, SchemaUtils.ValidTypeNames[0]); + _output.WriteLine(SchemaUtils.DumpCode(importer.CodeCompileUnit)); + Assert.True(importer.Options.GenerateInternal); + } + + [Fact] + public void EnableDataBinding() + { + XsdDataContractImporter importer = SchemaUtils.CreateImporterWithDefaultOptions(); + importer.Options.EnableDataBinding = true; + importer.Import(SchemaUtils.PositiveSchemas, SchemaUtils.ValidTypeNames[0]); + _output.WriteLine(SchemaUtils.DumpCode(importer.CodeCompileUnit)); + Assert.True(importer.Options.EnableDataBinding); + } + + [Fact] + public void GenerateSerializable() + { + XsdDataContractImporter importer = SchemaUtils.CreateImporterWithDefaultOptions(); + importer.Options.GenerateSerializable = true; + importer.Import(SchemaUtils.PositiveSchemas, SchemaUtils.ValidTypeNames[0]); + _output.WriteLine(SchemaUtils.DumpCode(importer.CodeCompileUnit)); + Assert.True(importer.Options.GenerateSerializable); + } + + [Fact] + public void ImportXmlType() + { + XsdDataContractImporter importer = SchemaUtils.CreateImporterWithDefaultOptions(); + importer.Options.ImportXmlType = true; + importer.Import(SchemaUtils.PositiveSchemas, SchemaUtils.ValidTypeNames[0]); + _output.WriteLine(SchemaUtils.DumpCode(importer.CodeCompileUnit)); + Assert.True(importer.Options.ImportXmlType); + } + + [Fact] + public void CodeProvider() + { + XsdDataContractImporter importer = SchemaUtils.CreateImporterWithDefaultOptions(); + CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("csharp"); + importer.Options.CodeProvider = codeProvider; + Console.WriteLine(importer.Options.CodeProvider.GetType().FullName); + importer.Import(SchemaUtils.PositiveSchemas, SchemaUtils.ValidTypeNames[0]); + _output.WriteLine(SchemaUtils.DumpCode(importer.CodeCompileUnit)); + Assert.Equal(codeProvider, importer.Options.CodeProvider); + } + + [Theory] + [InlineData("http://schemas.datacontract.org/2004/07/fooNs", "customizedNamespace")] + [InlineData("*", "customizedNamespace")] + [InlineData("null", "customizedNamespace")] + public void Namespaces(string dcns, string clrns) + { + XsdDataContractImporter importer = SchemaUtils.CreateImporterWithDefaultOptions(); + Assert.NotNull(importer.Options.Namespaces); + Assert.Empty(importer.Options.Namespaces); + + importer.Options.Namespaces.Add(dcns, clrns); + importer.Import(SchemaUtils.PositiveSchemas, SchemaUtils.ValidTypeNames[0]); + _output.WriteLine(SchemaUtils.DumpCode(importer.CodeCompileUnit)); + } + + [Theory] + [MemberData(nameof(ReferencedTypes_MemberData))] + public void ReferencedTypes(XmlSchemaSet schemas, XmlQualifiedName qname, Type[] referencedTypes, Type expectedExceptionType = null, string msg = null) + { + XsdDataContractImporter importer = SchemaUtils.CreateImporterWithDefaultOptions(); + for (int i = 0; i < referencedTypes.Length; i++) + importer.Options.ReferencedTypes.Add(referencedTypes[i]); + + if (expectedExceptionType == null) + { + importer.Import(schemas, qname); + _output.WriteLine(SchemaUtils.DumpCode(importer.CodeCompileUnit)); + } + else + { + var ex = Assert.Throws(expectedExceptionType, () => importer.Import(schemas, qname)); + + if (!string.IsNullOrEmpty(msg)) + Assert.StartsWith(msg, ex.Message); + } + } + public static IEnumerable ReferencedTypes_MemberData() + { + yield return new object[] { SchemaUtils.PositiveSchemas, SchemaUtils.ValidTypeNames[1], new Type[] { typeof(AnotherValidType) } }; + yield return new object[] { SchemaUtils.PositiveSchemas, SchemaUtils.ValidTypeNames[2], new Type[] { typeof(NonAttributedSquare) } }; + yield return new object[] { SchemaUtils.PositiveSchemas, SchemaUtils.ValidTypeNames[1], new Type[] { typeof(AnotherValidType), typeof(ConflictingAnotherValidType) }, + typeof(InvalidOperationException), @"List of referenced types contains more than one type with data contract name 'AnotherValidType' in namespace 'http://schemas.datacontract.org/2004/07/barNs'. Need to exclude all but one of the following types. Only matching types can be valid references:"}; + // These last two are described as "negative" in the original NetFx XsdDCImporterApi test code... but they don't fail here or there. + yield return new object[] { SchemaUtils.IsReferenceSchemas, SchemaUtils.ValidTypeNames[3], new Type[] { typeof(NonRefType) } }; + yield return new object[] { SchemaUtils.IsReferenceSchemas, SchemaUtils.ValidTypeNames[4], new Type[] { typeof(RefType1) } }; + } + } +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import/ImporterTests.cs b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import/ImporterTests.cs new file mode 100644 index 0000000000000..cb951fd10dc29 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import/ImporterTests.cs @@ -0,0 +1,415 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.CodeDom; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Reflection; +using System.Runtime.Serialization.Schema; +using System.Runtime.Serialization.Schema.Tests.DataContracts; +using System.Xml; +using System.Xml.Schema; +using Xunit; +using Xunit.Abstractions; + +namespace System.Runtime.Serialization.Schema.Tests +{ + public class ImporterTests + { + private readonly ITestOutputHelper _output; + public ImporterTests(ITestOutputHelper output) + { + _output = output; + } + + [Fact] + public void Ctor_Default() + { + XsdDataContractImporter xci = new XsdDataContractImporter(); + Assert.NotNull(xci); + Assert.Null(xci.Options); + } + + [Fact] + public void Ctor_CCU() + { + CodeCompileUnit ccu = new CodeCompileUnit(); + XsdDataContractImporter xci = new XsdDataContractImporter(ccu); + Assert.NotNull(xci); + Assert.Equal(ccu, xci.CodeCompileUnit); + } + + [Theory] + [MemberData(nameof(CanImport_MemberData))] + public void CanImport(bool expectedResult, Func canImport, Type expectedExceptionType = null, string msg = null) + { + XsdDataContractImporter importer = SchemaUtils.CreateImporterWithDefaultOptions(); + if (expectedExceptionType == null) + { + Assert.Equal(expectedResult, canImport(importer)); + } + else + { + var ex = Assert.Throws(expectedExceptionType, () => canImport(importer)); + + if (!string.IsNullOrEmpty(msg)) + Assert.Equal(msg, ex.Message); + } + } + public static IEnumerable CanImport_MemberData() + { + // CanImport(XmlSchemaSet) + yield return new object[] { true, (XsdDataContractImporter imp) => imp.CanImport(SchemaUtils.PositiveSchemas) }; + yield return new object[] { false, (XsdDataContractImporter imp) => imp.CanImport(null), typeof(ArgumentNullException), @"Value cannot be null. (Parameter 'schemas')" }; + yield return new object[] { false, (XsdDataContractImporter imp) => imp.CanImport(SchemaUtils.MixedSchemas) }; + + // CanImport(XmlSchemaSet, ICollection) + yield return new object[] { true, (XsdDataContractImporter imp) => imp.CanImport(SchemaUtils.PositiveSchemas, new XmlQualifiedName[] { SchemaUtils.ValidTypeNames[0] }) }; + yield return new object[] { false, (XsdDataContractImporter imp) => imp.CanImport(null, SchemaUtils.InvalidTypeNames), typeof(ArgumentNullException), @"Value cannot be null. (Parameter 'schemas')" }; + yield return new object[] { false, (XsdDataContractImporter imp) => imp.CanImport(SchemaUtils.MixedSchemas, (ICollection)null), typeof(ArgumentNullException), @"Value cannot be null. (Parameter 'typeNames')" }; + yield return new object[] { false, (XsdDataContractImporter imp) => imp.CanImport(SchemaUtils.MixedSchemas, new XmlQualifiedName[] { null }), typeof(ArgumentException), @"Cannot import type for null XmlQualifiedName specified via parameter." }; + yield return new object[] { false, (XsdDataContractImporter imp) => imp.CanImport(SchemaUtils.MixedSchemas, SchemaUtils.InvalidTypeNames) }; + + // CanImport(XmlSchemaSet, XmlQualifiedName) + yield return new object[] { true, (XsdDataContractImporter imp) => imp.CanImport(SchemaUtils.PositiveSchemas, SchemaUtils.ValidTypeNames[0]) }; + yield return new object[] { false, (XsdDataContractImporter imp) => imp.CanImport(null, SchemaUtils.InvalidTypeNames[0]), typeof(ArgumentNullException), @"Value cannot be null. (Parameter 'schemas')" }; + yield return new object[] { false, (XsdDataContractImporter imp) => imp.CanImport(SchemaUtils.MixedSchemas, (XmlQualifiedName)null), typeof(ArgumentNullException), @"Value cannot be null. (Parameter 'typeName')" }; + yield return new object[] { false, (XsdDataContractImporter imp) => imp.CanImport(SchemaUtils.MixedSchemas, SchemaUtils.InvalidTypeNames[0]) }; + + // CanImport(XmlSchemaSet, XmlSchemaElement) + // TODO + + // CanImportTests.cs + foreach (var citArgs in SchemaUtils.CanImportTests) + { + XmlSchemaSet schemaSet = SchemaUtils.ReadStringsIntoSchemaSet(citArgs.schemaString); + if (citArgs.qnames == null) + yield return new object[] { citArgs.expectedResult, (XsdDataContractImporter imp) => imp.CanImport(schemaSet) }; + else if (citArgs.qnames.Length == 1 && citArgs.isElement) + yield return new object[] { citArgs.expectedResult, (XsdDataContractImporter imp) => imp.CanImport(schemaSet, SchemaUtils.GetSchemaElement(schemaSet, citArgs.qnames[0])) }; + else if (citArgs.qnames.Length == 1) + yield return new object[] { citArgs.expectedResult, (XsdDataContractImporter imp) => imp.CanImport(schemaSet, citArgs.qnames[0]) }; + else + yield return new object[] { citArgs.expectedResult, (XsdDataContractImporter imp) => imp.CanImport(schemaSet, citArgs.qnames) }; + } + } + + [Theory] + [MemberData(nameof(Import_MemberData))] + public void Import(Action import, int codeLength = -1) + { + XsdDataContractImporter importer = SchemaUtils.CreateImporterWithDefaultOptions(); + import(importer); + string code = SchemaUtils.DumpCode(importer.CodeCompileUnit); + _output.WriteLine(code); + if (codeLength >= 0) + Assert.Equal(codeLength, code.Length); + } + public static IEnumerable Import_MemberData() + { + // Import(XmlSchemaSet) + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.PositiveSchemas), 5396 }; + + // Import(XmlSchemaSet, ICollection) + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.PositiveSchemas, new XmlQualifiedName[] { SchemaUtils.ValidTypeNames[0] }), 1615 }; + + // Import(XmlSchemaSet, XmlQualifiedName) + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.PositiveSchemas, SchemaUtils.ValidTypeNames[0]), 1615 }; + + // Import(XmlSchemaSet, XmlSchemaElement) + // TODO + + // From CanImportTests.cs + foreach (var citArgs in SchemaUtils.CanImportTests) + { + if (citArgs.expectedResult) + { + XmlSchemaSet schemaSet = SchemaUtils.ReadStringsIntoSchemaSet(citArgs.schemaString); + if (citArgs.qnames == null) + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(schemaSet) }; + else if (citArgs.qnames.Length == 1 && citArgs.isElement) + yield return new object[] { (XsdDataContractImporter imp) => { imp.Import(schemaSet, SchemaUtils.GetSchemaElement(schemaSet, citArgs.qnames[0])); } }; + else if (citArgs.qnames.Length == 1 && !citArgs.isElement) + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(schemaSet, citArgs.qnames[0]) }; + else + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(schemaSet, citArgs.qnames) }; + } + } + + // From FormatVersioning.cs : Positive tests + (string msg, Type type, string xpath, string xmlFrag)[] formatVersioningArgs = new (string, Type, string, string)[] { + ("Optional Serialization Attribute in class", + typeof(SerializableFormatClass), @"//xs:schema/xs:complexType[@name='ImporterTests.SerializableFormatClass']/xs:sequence", @""), + ("Optional Serialization Attribute in ISerializable", + typeof(ISerializableFormatClass), @"//xs:schema/xs:complexType[@name='ISerializableFormatClass']/xs:sequence", @""), + ("Optional Serialization Attribute in Array", + typeof(SerializableFormatClass), @"//xs:schema/xs:complexType[@name='ArrayOfImporterTests.SerializableFormatClass']/xs:sequence", @""), + ("Optional Serialization Element in class", + typeof(SerializableFormatClass), @"//xs:schema/xs:complexType[@name='ImporterTests.SerializableFormatClass']/xs:sequence/xs:element", @""), + ("Optional Serialization Element in ISerializable", + typeof(ISerializableFormatClass), @"//xs:schema/xs:complexType[@name='ISerializableFormatClass']/xs:sequence/xs:any", @""), + ("Optional Serialization Element in Array", + typeof(SerializableFormatClass), @"//xs:schema/xs:complexType[@name='ArrayOfImporterTests.SerializableFormatClass']/xs:sequence/xs:element", @""), + }; + foreach (var fvArg in formatVersioningArgs) + { + (XmlSchemaSet schemaSet, XmlQualifiedName typeName) = PrepareFormatVersioningTest(fvArg.type, fvArg.xpath, fvArg.xmlFrag); + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(schemaSet, typeName) }; + } + } + static (XmlSchemaSet, XmlQualifiedName) PrepareFormatVersioningTest(Type type, string xpath, string xmlFrag) + { + XsdDataContractExporter exporter = new XsdDataContractExporter(); + exporter.Export(type); + XmlSchemaSet schemaSet = exporter.Schemas; + XmlQualifiedName typeName = exporter.GetSchemaTypeName(type); + string schemaString = SchemaUtils.GetSchemaString(schemaSet, typeName.Namespace); + schemaString = SchemaUtils.InsertElement(schemaString, xpath, xmlFrag, true); + schemaString = SchemaUtils.InsertElement(schemaString, @"//xs:schema/xs:complexType", @"", false); + schemaString = SchemaUtils.InsertElement(schemaString, @"//xs:schema/xs:complexType", @"", false); + schemaString = SchemaUtils.InsertAttribute(schemaString, @"//xs:schema", "xmlns", @"ser", @"http://www.w3.org/2000/xmlns/", "http://schemas.microsoft.com/2003/10/Serialization/"); + SchemaUtils.SetSchemaString(schemaSet, typeName.Namespace, schemaString); + schemaSet.Add(XmlSchema.Read(new StringReader(SchemaUtils.GlobalSchema), null)); + + XmlSchema v2SerializationSchema = SchemaUtils.GetSchema(schemaSet, "http://schemas.microsoft.com/2003/10/Serialization/"); + XmlSchemaElement v2Element = new XmlSchemaElement(); + v2Element.Name = "V2Element"; + v2SerializationSchema.Items.Add(v2Element); + XmlSchemaAttribute v2Attribute = new XmlSchemaAttribute(); + v2Attribute.Name = "V2Attribute"; + v2SerializationSchema.Items.Add(v2Attribute); + schemaSet.Reprocess(v2SerializationSchema); + + return (schemaSet, typeName); + } + + [Theory] + [MemberData(nameof(Import_NegativeCases_MemberData))] + public void Import_NegativeCases(Action import, Type expectedExceptionType, string msg = null) + { + XsdDataContractImporter importer = SchemaUtils.CreateImporterWithDefaultOptions(); + var ex = Assert.Throws(expectedExceptionType, () => import(importer)); + + if (!string.IsNullOrEmpty(msg)) + Assert.Equal(msg, ex.Message); + } + public static IEnumerable Import_NegativeCases_MemberData() + { + // Import(XmlSchemaSet) + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(null), typeof(ArgumentNullException), @"Value cannot be null. (Parameter 'schemas')" }; + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.MixedSchemas), typeof(InvalidDataContractException), @"Type 'InvalidType' in namespace 'http://schemas.datacontract.org/2004/07/fooNs' cannot be imported. The root particle must be a sequence. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer." }; + + // Import(XmlSchemaSet, ICollection) + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(null, SchemaUtils.InvalidTypeNames), typeof(ArgumentNullException), @"Value cannot be null. (Parameter 'schemas')" }; + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.MixedSchemas, (ICollection)null), typeof(ArgumentNullException), @"Value cannot be null. (Parameter 'typeNames')" }; + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.MixedSchemas, new XmlQualifiedName[] { null }), typeof(ArgumentException), @"Cannot import type for null XmlQualifiedName specified via parameter." }; + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.MixedSchemas, SchemaUtils.InvalidTypeNames), typeof(InvalidDataContractException), @"Type 'InvalidType' in namespace 'http://schemas.datacontract.org/2004/07/fooNs' cannot be imported. The root particle must be a sequence. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer." }; + + // Import(XmlSchemaSet, XmlQualifiedName) + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(null, SchemaUtils.InvalidTypeNames[0]), typeof(ArgumentNullException), @"Value cannot be null. (Parameter 'schemas')" }; + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.MixedSchemas, (XmlQualifiedName)null), typeof(ArgumentNullException), @"Value cannot be null. (Parameter 'typeName')" }; + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.MixedSchemas, SchemaUtils.InvalidTypeNames[0]), typeof(InvalidDataContractException), @"Type 'InvalidType' in namespace 'http://schemas.datacontract.org/2004/07/fooNs' cannot be imported. The root particle must be a sequence. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer." }; + + // Import(XmlSchemaSet, XmlSchemaElement) + // TODO + + // NegativeTests.cs, part 1 : Bad schema + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.ReadStringsIntoSchemaSet(SchemaUtils.NegativeSchemaStrings[1]), SchemaUtils.NegativeTypeNames[1]), + typeof(InvalidDataContractException), @"Invalid type specified. Type with name 'FooType' not found in schema with namespace 'http://EmptySchema'." }; + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.ReadStringsIntoSchemaSet(SchemaUtils.NegativeSchemaStrings[2]), SchemaUtils.NegativeTypeNames[2]), + typeof(InvalidDataContractException), @"Invalid type specified. Type with name 'FooType' not found in schema with namespace 'http://NonExistantSchema'." }; + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.ReadStringsIntoSchemaSet(SchemaUtils.NegativeSchemaStrings[3])), + typeof(InvalidDataContractException), @"Type 'InvalidTopLevelElementType' in namespace 'http://schemas.datacontract.org/2004/07/foo' cannot be imported. The global element found in the schema with same name references a different type 'int' in namespace 'http://www.w3.org/2001/XMLSchema'. Data contract types must have the same name as their root element name. Consider removing the global element or changing its type. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer." }; + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.ReadStringsIntoSchemaSet(SchemaUtils.NegativeSchemaStrings[4])), + typeof(InvalidDataContractException), @"Type 'ExtraAttributesType' in namespace 'http://schemas.datacontract.org/2004/07/foo' cannot be imported. Attributes must be optional and from namespace 'http://schemas.microsoft.com/2003/10/Serialization/'. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer." }; + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.ReadStringsIntoSchemaSet(SchemaUtils.NegativeSchemaStrings[5]), SchemaUtils.NegativeTypeNames[5]), + typeof(InvalidDataContractException), @"Type 'ExtraAttributeWildcardType' in namespace 'http://schemas.datacontract.org/2004/07/foo' cannot be imported. 'anyAttribute' is not supported. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer." }; + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.ReadStringsIntoSchemaSet(SchemaUtils.NegativeSchemaStrings[6])), + typeof(InvalidDataContractException), @"Type 'InvalidRootParticleType' in namespace 'http://schemas.datacontract.org/2004/07/foo' cannot be imported. The root particle must be a sequence. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer." }; + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.ReadStringsIntoSchemaSet(SchemaUtils.NegativeSchemaStrings[7])), + typeof(InvalidDataContractException), @"Type 'InvalidTopLevelElement' in namespace 'http://schemas.datacontract.org/2004/07/foo' cannot be imported. The global element found in the schema with same name references a different type 'string' in namespace 'http://www.w3.org/2001/XMLSchema'. Data contract types must have the same name as their root element name. Consider removing the global element or changing its type. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer." }; + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.ReadStringsIntoSchemaSet(SchemaUtils.NegativeSchemaStrings[8])), + typeof(InvalidDataContractException), @"Type 'TypeWithElementsOfSameName' in namespace 'http://schemas.datacontract.org/2004/07/foo' cannot be imported. The type contains two elements with the same name 'DuplicatedName'. Multiple elements with the same name in one type are not supported because members marked with DataMemberAttribute attribute must have unique names. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer." }; + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.ReadStringsIntoSchemaSet(SchemaUtils.NegativeSchemaStrings[9])), + typeof(InvalidDataContractException), @"Type 'SimpleTypeUnion' in namespace 'http://schemas.datacontract.org/2004/07/foo' cannot be imported. Simple types with content are not supported. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer." }; + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.ReadStringsIntoSchemaSet(SchemaUtils.NegativeSchemaStrings[10])), + typeof(InvalidDataContractException), @"Enum type 'EnumOnlyList' in namespace 'http://schemas.datacontract.org/2004/07/foo' cannot be imported. Simple type list must contain an anonymous type specifying enumeration facets. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer." }; + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.ReadStringsIntoSchemaSet(SchemaUtils.NegativeSchemaStrings[11])), + typeof(InvalidDataContractException), @"Enum type 'EnumNonStringBaseType' in namespace 'http://schemas.datacontract.org/2004/07/foo' cannot be imported. Anonymous type with cannot be used to create Flags enumeration because it is not a valid enum type. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer." }; + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.ReadStringsIntoSchemaSet(SchemaUtils.NegativeSchemaStrings[12])), + typeof(InvalidDataContractException), @"Type 'ComplexTypeWithSimpleContent' in namespace 'http://schemas.datacontract.org/2004/07/foo' cannot be imported. Complex types with simple content extension are not supported. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer." }; + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.ReadStringsIntoSchemaSet(SchemaUtils.NegativeSchemaStrings[13])), + typeof(InvalidDataContractException), @"Array type 'ArrayOfBar' in namespace 'http://schemas.datacontract.org/2004/07/foo' cannot be imported. Form for element 'Bar' must be qualified. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer." }; + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.ReadStringsIntoSchemaSet(SchemaUtils.NegativeSchemaStrings[14])), + typeof(InvalidDataContractException), @"Type 'DataSet.datasetType' in namespace 'http://tempuri.org/' cannot be imported. The root sequence must contain only local elements. Group ref, choice, any and nested sequences are not supported. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer." }; + + // NegativeTests.cs, part 2 : Bad attribute + (Type type, string xpath, string prefix, string localName, string ns, string value, string exMsg)[] badAttributeCases = new (Type, string, string, string, string, string, string)[] { + (typeof(SerializableClass), @"//xs:schema/xs:complexType[@name='SerializableClass']", "", @"abstract", "", @"true", @"Type 'SerializableClass' in namespace 'http://special1.tempuri.org' cannot be imported. The type cannot have 'abstract' set to 'true'. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer."), + (typeof(SerializableClass), @"//xs:schema/xs:complexType[@name='SerializableClass']", null, @"mixed", "", @"true", @"Type 'SerializableClass' in namespace 'http://special1.tempuri.org' cannot be imported. Complex type with mixed content is not supported. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer."), + (typeof(SerializableClass), @"//xs:schema/xs:complexType[@name='SerializableClass']/xs:sequence/xs:element[@name='member']", "", @"fixed", "", @"xxx", @"Type 'SerializableClass' in namespace 'http://special1.tempuri.org' cannot be imported. Fixed value on element 'member' is not supported. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer."), + (typeof(SerializableClass), @"//xs:schema/xs:complexType[@name='SerializableClass']/xs:sequence/xs:element[@name='member']", "", @"default", "", @"yyy", @"Type 'SerializableClass' in namespace 'http://special1.tempuri.org' cannot be imported. Default value on element 'member' is not supported. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer."), + (typeof(SerializableClass), @"//xs:schema/xs:element[@name='SerializableClass']", "", @"abstract", "", @"true", @"Type 'SerializableClass' in namespace 'http://special1.tempuri.org' cannot be imported. The element cannot have 'abstract' set to 'true'. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer."), + (typeof(SerializableClass), @"//xs:schema/xs:element[@name='SerializableClass']", "", @"substitutionGroup", "", @"tns:Head", @"Type 'SerializableClass' in namespace 'http://special1.tempuri.org' cannot be imported. Substitution group on element 'SerializableClass' is not supported. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer."), + }; + foreach (var bac in badAttributeCases) + { + XsdDataContractExporter exporter = new XsdDataContractExporter(); + exporter.Export(bac.type); + XmlSchemaSet schemaSet = exporter.Schemas; + XmlQualifiedName typeName = exporter.GetSchemaTypeName(bac.type); + string schemaString = SchemaUtils.GetSchemaString(schemaSet, typeName.Namespace); + schemaString = SchemaUtils.InsertElement(schemaString, @"//xs:schema/xs:element[@name='SerializableClass']", @"", true); + schemaString = SchemaUtils.InsertAttribute(schemaString, bac.xpath, bac.prefix, bac.localName, bac.ns, bac.value); + XmlSchemaSet schema = SchemaUtils.ReadStringsIntoSchemaSet(schemaString); + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(schema), typeof(InvalidDataContractException), bac.exMsg }; + } + + // NegativeTests.cs, part 3 : Bad element + (Type type, string xpath, string xmlFrag, bool insertAfter, string exMsg)[] badElementCases = new(Type, string, string, bool, string)[] { + (typeof(SerializableClass), @"//xs:schema/xs:complexType[@name='SerializableClass']/xs:sequence/xs:element", @"", true, @"Type 'SerializableClass' in namespace 'http://special1.tempuri.org' cannot be imported. Ref to element 'SerializableClass' in 'http://special1.tempuri.org' namespace is not supported. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer."), + (typeof(DerivedClass), @"//xs:schema/xs:complexType[@name='DerivedClass']/xs:complexContent/xs:extension/xs:sequence/xs:element", @"", false, @"Type 'DerivedClass' in namespace 'http://special1.tempuri.org' cannot be imported. The root sequence must contain only local elements. Group ref, choice, any and nested sequences are not supported. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer."), + (typeof(DerivedClass), @"//xs:schema/xs:complexType[@name='DerivedClass']/xs:complexContent/xs:extension/xs:sequence/xs:element", @"", false, @"Type 'DerivedClass' in namespace 'http://special1.tempuri.org' cannot be imported. Ref to element 'int' in 'http://schemas.microsoft.com/2003/10/Serialization/' namespace is not supported. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer."), + }; + foreach (var bec in badElementCases) + { + XsdDataContractExporter exporter = new XsdDataContractExporter(); + exporter.Export(bec.type); + XmlSchemaSet schemaSet = exporter.Schemas; + XmlQualifiedName typeName = exporter.GetSchemaTypeName(bec.type); + string schemaString = SchemaUtils.GetSchemaString(schemaSet, typeName.Namespace); + schemaString = SchemaUtils.InsertElement(schemaString, bec.xpath, bec.xmlFrag, bec.insertAfter); + XmlSchemaSet schema = SchemaUtils.ReadStringsIntoSchemaSet(schemaString); + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(schema), typeof(InvalidDataContractException), bec.exMsg }; + } + + // FormatVersioning.cs : Negative tests + (string msg, Type type, string xpath, string xmlFrag, string exMsg)[] formatVersioningNegativeArgs = new (string, Type, string, string, string)[] { + ("Required Serialization Attribute in class", + typeof(SerializableFormatClass), @"//xs:schema/xs:complexType[@name='ImporterTests.SerializableFormatClass']/xs:sequence", @"", + @"Type 'ImporterTests.SerializableFormatClass' in namespace 'http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Schema.Tests' cannot be imported. Attributes must be optional and from namespace 'http://schemas.microsoft.com/2003/10/Serialization/'. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer."), + ("Required Serialization Attribute in ISerializable", + typeof(ISerializableFormatClass), @"//xs:schema/xs:complexType[@name='ISerializableFormatClass']/xs:sequence", @"", + @"Type 'ISerializableFormatClass' in namespace 'http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Schema.Tests.DataContracts' cannot be imported. Attributes must be optional and from namespace 'http://schemas.microsoft.com/2003/10/Serialization/'. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer."), + ("Required Serialization Attribute in Array", + typeof(SerializableFormatClass), @"//xs:schema/xs:complexType[@name='ArrayOfImporterTests.SerializableFormatClass']/xs:sequence", @"", + @"Type 'ArrayOfImporterTests.SerializableFormatClass' in namespace 'http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Schema.Tests' cannot be imported. Attributes must be optional and from namespace 'http://schemas.microsoft.com/2003/10/Serialization/'. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer."), + ("Required Serialization Element in class", + typeof(SerializableFormatClass), @"//xs:schema/xs:complexType[@name='ImporterTests.SerializableFormatClass']/xs:sequence/xs:element", @"", + @"Type 'ImporterTests.SerializableFormatClass' in namespace 'http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Schema.Tests' cannot be imported. Ref to element 'V2Element' in 'http://schemas.microsoft.com/2003/10/Serialization/' namespace is not supported. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer."), + ("Required Serialization Element in ISerializable", + typeof(ISerializableFormatClass), @"//xs:schema/xs:complexType[@name='ISerializableFormatClass']/xs:sequence/xs:any", @"", + @"Type 'ISerializableFormatClass' in namespace 'http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Schema.Tests.DataContracts' cannot be imported. The root sequence must contain only local elements. Group ref, choice, any and nested sequences are not supported. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer."), + ("Required Serialization Element in Array", + typeof(SerializableFormatClass), @"//xs:schema/xs:complexType[@name='ArrayOfImporterTests.SerializableFormatClass']/xs:sequence/xs:element", @"", + @"Type 'ArrayOfImporterTests.SerializableFormatClass' in namespace 'http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Schema.Tests' cannot be imported. 'maxOccurs' on element 'ImporterTests.SerializableFormatClass' must be 1. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer."), + ("Optional Global Attribute in class", + typeof(SerializableFormatClass), @"//xs:schema/xs:complexType[@name='ImporterTests.SerializableFormatClass']/xs:sequence", @"", + @"Type 'ImporterTests.SerializableFormatClass' in namespace 'http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Schema.Tests' cannot be imported. Attributes must be optional and from namespace 'http://schemas.microsoft.com/2003/10/Serialization/'. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer."), + ("Optional Global Attribute in ISerializable", + typeof(ISerializableFormatClass), @"//xs:schema/xs:complexType[@name='ISerializableFormatClass']/xs:sequence", @"", + @"Type 'ISerializableFormatClass' in namespace 'http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Schema.Tests.DataContracts' cannot be imported. Attributes must be optional and from namespace 'http://schemas.microsoft.com/2003/10/Serialization/'. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer."), + ("Optional Global Attribute in Array", + typeof(SerializableFormatClass), @"//xs:schema/xs:complexType[@name='ArrayOfImporterTests.SerializableFormatClass']/xs:sequence", @"", + @"Type 'ArrayOfImporterTests.SerializableFormatClass' in namespace 'http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Schema.Tests' cannot be imported. Attributes must be optional and from namespace 'http://schemas.microsoft.com/2003/10/Serialization/'. Either change the schema so that the types can map to data contract types or use ImportXmlType or use a different serializer."), + }; + foreach (var fvArg in formatVersioningNegativeArgs) + { + (XmlSchemaSet schemaSet, XmlQualifiedName typeName) = PrepareFormatVersioningTest(fvArg.type, fvArg.xpath, fvArg.xmlFrag); + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(schemaSet, typeName), typeof(InvalidDataContractException), fvArg.exMsg }; + } + } +#pragma warning disable CS0169, IDE0051, IDE1006 + [Serializable] + public class SerializableFormatClass + { + SerializableFormatClass[] array; + } +#pragma warning restore CS0169, IDE0051, IDE1006 + + [Theory] + [MemberData(nameof(GetCodeTypeReference_MemberData))] + public void GetCodeTypeReference(XmlSchemaSet schemas, XmlQualifiedName qname, string exptectedType, Type expectedExceptionType = null, string msg = null) + { + XsdDataContractImporter importer = SchemaUtils.CreateImporterWithDefaultOptions(); + + if (schemas != null) + importer.Import(schemas); + + if (expectedExceptionType == null) + { + CodeTypeReference ctr = importer.GetCodeTypeReference(qname); + Assert.NotNull(ctr); + + string typeString = SchemaUtils.GetString(ctr); + _output.WriteLine(typeString); + Assert.Equal(exptectedType, typeString); + } + else + { + var ex = Assert.Throws(expectedExceptionType, () => importer.GetCodeTypeReference(qname)); + + if (!string.IsNullOrEmpty(msg)) + Assert.Equal(msg, ex.Message); + } + } + public static IEnumerable GetCodeTypeReference_MemberData() + { + // GetCodeTypeReference(XmlQualifiedName) + yield return new object[] { SchemaUtils.PositiveSchemas, SchemaUtils.ValidTypeNames[0], "fooNs.ValidType" }; + yield return new object[] { SchemaUtils.PositiveSchemas, SchemaUtils.ValidTypeNames[2], "Suites.SchemaImport.NonAttributedType" }; + yield return new object[] { null, null, null, typeof(ArgumentNullException), @"Value cannot be null. (Parameter 'typeName')" }; + yield return new object[] { null, SchemaUtils.InvalidTypeNames[0], null, typeof(InvalidOperationException), @"Type 'InvalidType' from namespace 'http://schemas.datacontract.org/2004/07/fooNs' has not been imported from schema. Consider first importing this type by calling one of the Import methods on XsdDataContractImporter." }; + yield return new object[] { SchemaUtils.PositiveSchemas, SchemaUtils.InvalidTypeNames[0], null, typeof(InvalidOperationException), @"Type 'InvalidType' from namespace 'http://schemas.datacontract.org/2004/07/fooNs' has not been imported from schema. Consider first importing this type by calling one of the Import methods on XsdDataContractImporter." }; + + // GetCodeTypeReference(XmlQualifiedName, XmlSchemaElement) + // TODO + } + + + [Theory] + [MemberData(nameof(GetKnownTypeReferences_MemberData))] + public void GetKnownTypeReferences(XmlSchemaSet schemas, XmlQualifiedName qname, int expectedRefCount, Type expectedExceptionType = null, string msg = null) + { + XsdDataContractImporter importer = SchemaUtils.CreateImporterWithDefaultOptions(); + + if (schemas != null) + importer.Import(schemas); + + if (expectedExceptionType == null) + { + ICollection knownTypeReferences = importer.GetKnownTypeReferences(qname); + + if (knownTypeReferences == null) + { + _output.WriteLine("KnownType count: null"); + Assert.Equal(0, expectedRefCount); + } + else + { + _output.WriteLine("KnownType count: {0}", knownTypeReferences.Count); + foreach (CodeTypeReference knownTypeReference in knownTypeReferences) + _output.WriteLine(SchemaUtils.GetString(knownTypeReference)); + Assert.Equal(expectedRefCount, knownTypeReferences.Count); + } + } + else + { + var ex = Assert.Throws(expectedExceptionType, () => importer.GetKnownTypeReferences(qname)); + + if (!string.IsNullOrEmpty(msg)) + Assert.Equal(msg, ex.Message); + } + } + public static IEnumerable GetKnownTypeReferences_MemberData() + { + // GetKnownTypeReferences(XmlQualifiedName) + yield return new object[] { SchemaUtils.PositiveSchemas, SchemaUtils.ValidTypeNames[0], 0 }; + yield return new object[] { null, null, -1, typeof(ArgumentNullException), @"Value cannot be null. (Parameter 'typeName')" }; + yield return new object[] { null, SchemaUtils.ValidTypeNames[0], -1, typeof(InvalidOperationException), @"Type 'ValidType' from namespace 'http://schemas.datacontract.org/2004/07/fooNs' has not been imported from schema. Consider first importing this type by calling one of the Import methods on XsdDataContractImporter." }; + // TODO - a positive case with non-zero ref count. + } + } +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import/SurrogateTests.cs b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import/SurrogateTests.cs new file mode 100644 index 0000000000000..35d64bde333ba --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import/SurrogateTests.cs @@ -0,0 +1,220 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.CodeDom; +using System.Collections.ObjectModel; +using System.Reflection; +using System.Runtime.Serialization.Schema; +using System.Runtime.Serialization.Schema.Tests.DataContracts; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; +using Xunit; +using Xunit.Abstractions; + +namespace System.Runtime.Serialization.Schema.Tests +{ + // TODO - Add a test covering 'ISerializationCodeDomSurrogateProvider'/ProcessImportedType - There was nothing in NetFx test suites for this. + public class SurrogateTests + { + static Type[] testTypes = new Type[] + { + typeof(CircleContainer), + typeof(Node), + typeof(XmlSerializerPerson), + }; + + private readonly ITestOutputHelper _output; + public SurrogateTests(ITestOutputHelper output) + { + _output = output; + } + + [Fact] + public void DefaultScenario() + { + XsdDataContractExporter exporter = new XsdDataContractExporter(); + exporter.Options = new ExportOptions(); + exporter.Options.DataContractSurrogate = new SurrogateProvider(false); + for (int i = 0; i < testTypes.Length; i++) + exporter.Export((Type)testTypes[i]); + + XsdDataContractImporter importer = new XsdDataContractImporter(); + importer.Options = new ImportOptions(); + importer.Options.DataContractSurrogate = exporter.Options.DataContractSurrogate; + importer.Options.ImportXmlType = true; + importer.Import(exporter.Schemas); + + string code = SchemaUtils.DumpCode(importer.CodeCompileUnit); + _output.WriteLine(code); + + Assert.Contains(@"[assembly: System.Runtime.Serialization.ContractNamespaceAttribute(""http://special1.tempuri.org"", ClrNamespace=""special1.tempuri.org"")]", code); + Assert.Contains(@"[assembly: System.Runtime.Serialization.ContractNamespaceAttribute("""", ClrNamespace="""")]", code); + + Assert.Contains(@"namespace special1.tempuri.org", code); + Assert.Matches(@"\[System.Runtime.Serialization.DataContractAttribute\(Name=""CircleContainer"", Namespace=""http://special1.tempuri.org""\)\]\s*public partial class CircleContainer : object, System.Runtime.Serialization.IExtensibleDataObject", code); + Assert.Contains(@"private System.Runtime.Serialization.Schema.Tests.DataContracts.SerializableSquare[] circlesField;", code); + Assert.Contains(@"private System.Runtime.Serialization.Schema.Tests.DataContracts.SerializableSquare CircleField;", code); + Assert.Matches(@"\[System.Runtime.Serialization.DataMemberAttribute\(\)\]\s*public System.Runtime.Serialization.Schema.Tests.DataContracts.SerializableSquare Circle", code); + Assert.Contains(@"public partial class SerializableSquare : object, System.Runtime.Serialization.IExtensibleDataObject", code); + + Assert.Contains(@"namespace System.Runtime.Serialization.Schema.Tests.DataContracts", code); + Assert.Matches(@"\[System.Runtime.Serialization.DataContractAttribute\(Name\s*=\s*""SerializableNode"", Namespace\s*=\s*""http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Schema.Tests""\s*\+\s*"".DataContracts""\)\]\s*public partial class SerializableNode : object, System.Runtime.Serialization.IExtensibleDataObject", code); + Assert.Matches(@"\[System.Xml.Serialization.XmlSchemaProviderAttribute\(""ExportSchema""\)\]\s*\[System.Xml.Serialization.XmlRootAttribute\(ElementName\s*=\s*""XmlSerializerPersonElement"", Namespace\s*=\s*""""\)\]\s*public partial class XmlSerializerPerson : object, System.Xml.Serialization.IXmlSerializable", code); + } + + [Fact] + public void WithReferencedType() + { + XsdDataContractExporter exporter = new XsdDataContractExporter(); + exporter.Options = new ExportOptions(); + exporter.Options.DataContractSurrogate = new SurrogateProvider(false); + for (int i = 0; i < testTypes.Length; i++) + exporter.Export((Type)testTypes[i]); + + XsdDataContractImporter importer = new XsdDataContractImporter(); + importer.Options = new ImportOptions(); + importer.Options.DataContractSurrogate = exporter.Options.DataContractSurrogate; + importer.Options.ImportXmlType = true; + importer.Options.ReferencedTypes.Add(typeof(SerializableCircle)); + importer.Import(exporter.Schemas); + + string code = SchemaUtils.DumpCode(importer.CodeCompileUnit); + _output.WriteLine(code); + + Assert.Contains(@"[assembly: System.Runtime.Serialization.ContractNamespaceAttribute(""http://special1.tempuri.org"", ClrNamespace=""special1.tempuri.org"")]", code); + Assert.Contains(@"[assembly: System.Runtime.Serialization.ContractNamespaceAttribute("""", ClrNamespace="""")]", code); + + Assert.Contains(@"namespace special1.tempuri.org", code); + Assert.Matches(@"\[System.Runtime.Serialization.DataContractAttribute\(Name=""CircleContainer"", Namespace=""http://special1.tempuri.org""\)\]\s*public partial class CircleContainer : object, System.Runtime.Serialization.IExtensibleDataObject", code); + Assert.Contains(@"private System.Runtime.Serialization.Schema.Tests.DataContracts.SerializableSquare[] circlesField;", code); + Assert.Contains(@"private System.Runtime.Serialization.Schema.Tests.DataContracts.SerializableCircle CircleField;", code); + Assert.Matches(@"\[System.Runtime.Serialization.DataMemberAttribute\(\)\]\s*public System.Runtime.Serialization.Schema.Tests.DataContracts.SerializableCircle Circle", code); + + Assert.Contains(@"namespace System.Runtime.Serialization.Schema.Tests.DataContracts", code); + Assert.Matches(@"\[System.Runtime.Serialization.DataContractAttribute\(Name\s*=\s*""SerializableNode"", Namespace\s*=\s*""http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Schema.Tests""\s*\+\s*"".DataContracts""\)\]\s*public partial class SerializableNode : object, System.Runtime.Serialization.IExtensibleDataObject", code); + Assert.Matches(@"\[System.Xml.Serialization.XmlSchemaProviderAttribute\(""ExportSchema""\)\]\s*\[System.Xml.Serialization.XmlRootAttribute\(ElementName\s*=\s*""XmlSerializerPersonElement"", Namespace\s*=\s*""""\)\]\s*public partial class XmlSerializerPerson : object, System.Xml.Serialization.IXmlSerializable", code); + Assert.DoesNotContain(@"public partial class SerializableSquare : object, System.Runtime.Serialization.IExtensibleDataObject", code); + } + + [Fact] + public void WithSurrogateBinding() + { + XsdDataContractExporter exporter = new XsdDataContractExporter(); + exporter.Options = new ExportOptions(); + exporter.Options.DataContractSurrogate = new SurrogateProvider(true); + for (int i = 0; i < testTypes.Length; i++) + exporter.Export((Type)testTypes[i]); + + XsdDataContractImporter importer = new XsdDataContractImporter(); + importer = new XsdDataContractImporter(); + importer.Options = new ImportOptions(); + importer.Options.DataContractSurrogate = exporter.Options.DataContractSurrogate; + importer.Options.ImportXmlType = true; + importer.Options.ReferencedTypes.Add(typeof(Circle)); + importer.Import(exporter.Schemas); + + string code = SchemaUtils.DumpCode(importer.CodeCompileUnit); + _output.WriteLine(code); + + Assert.Contains(@"[assembly: System.Runtime.Serialization.ContractNamespaceAttribute(""http://special1.tempuri.org"", ClrNamespace=""special1.tempuri.org"")]", code); + Assert.DoesNotContain(@"[assembly: System.Runtime.Serialization.ContractNamespaceAttribute("""", ClrNamespace="""")]", code); + + Assert.Contains(@"namespace special1.tempuri.org", code); + Assert.Matches(@"\[System.Runtime.Serialization.DataContractAttribute\(Name=""CircleContainer"", Namespace=""http://special1.tempuri.org""\)\]\s*public partial class CircleContainer : object, System.Runtime.Serialization.IExtensibleDataObject", code); + Assert.Contains(@"private System.Runtime.Serialization.Schema.Tests.DataContracts.SerializableCircle[] circlesField;", code); + Assert.Contains(@"private System.Runtime.Serialization.Schema.Tests.DataContracts.SerializableCircle CircleField;", code); + Assert.Matches(@"\[System.Runtime.Serialization.DataMemberAttribute\(\)\]\s*public System.Runtime.Serialization.Schema.Tests.DataContracts.SerializableCircle Circle", code); + + Assert.DoesNotContain(@"namespace System.Runtime.Serialization.Schema.Tests.DataContracts", code); + Assert.DoesNotContain(@"class SerializableSquare", code); + Assert.DoesNotContain(@"class SerializableNode", code); + Assert.DoesNotContain(@"class XmlSerializerPerson", code); + } + } + + internal class SurrogateProvider : ISerializationSurrogateProvider2 + { + static XmlQualifiedName s_circleList = new XsdDataContractExporter().GetSchemaTypeName(typeof(SerializableCircle[])); + static XmlQualifiedName s_square = new XsdDataContractExporter().GetSchemaTypeName(typeof(SerializableSquare)); + static XmlQualifiedName s_serializableNode = new XsdDataContractExporter().GetSchemaTypeName(typeof(SerializableNode)); + static XmlQualifiedName s_xmlSerializerPersonAdapter = new XsdDataContractExporter().GetSchemaTypeName(typeof(XmlSerializerAdapter)); + + bool _surrogateBinding; + public SurrogateProvider(bool surrogateBinding) { _surrogateBinding = surrogateBinding; } + + public object? GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType) => memberInfo.MemberType.ToString(); + public object? GetCustomDataToExport(Type runtimeType, Type dataContractType) => runtimeType.Name; + public object GetDeserializedObject(object obj, Type targetType) => throw new NotImplementedException(); + public void GetKnownCustomDataTypes(Collection customDataTypes) { } + public object GetObjectToSerialize(object obj, Type targetType) => throw new NotImplementedException(); + public Type GetSurrogateType(Type type) // Formerly Known As GetDataContractType(Type)... but this was in the first interface, so we can't change this name. + { + if (type == typeof(Node)) + return typeof(SerializableNode); + if (type == typeof(SerializableCircle)) + return typeof(SerializableSquare); + if (type == typeof(XmlSerializerPerson)) + return typeof(XmlSerializerAdapter); + return type; + } + public Type? GetReferencedTypeOnImport(string name, string ns, object? customData) + { + if (!_surrogateBinding) + { + // Collection item and type name mismatch must be handled by surrogate to avoid exception + return (name == s_circleList.Name && ns == s_circleList.Namespace) ? typeof(SerializableSquare[]) : null; + } + + if (name == s_square.Name && ns == s_square.Namespace) + return typeof(SerializableCircle); + if (name == s_circleList.Name && ns == s_circleList.Namespace) + return typeof(SerializableCircle[]); + if (name == s_serializableNode.Name && ns == s_serializableNode.Namespace) + return typeof(Node); + if (name == s_xmlSerializerPersonAdapter.Name && ns == s_xmlSerializerPersonAdapter.Namespace) + return typeof(XmlSerializerPerson); + return null; + } + + [XmlSchemaProvider("StaticGetSchema")] + public class XmlSerializerAdapter : IXmlSerializable + { + public XmlSchema GetSchema() + { + throw new NotImplementedException(); + } + + public void ReadXml(XmlReader reader) + { + throw new NotImplementedException(); + } + + public void WriteXml(XmlWriter writer) + { + throw new NotImplementedException(); + } + + static XmlQualifiedName StaticGetSchema(XmlSchemaSet schemaSet) + { + XmlReflectionImporter importer = new XmlReflectionImporter(); + XmlTypeMapping xmlTypeMapping = importer.ImportTypeMapping(typeof(T)); + XmlSchemas schemas = new XmlSchemas(); + XmlSchemaExporter exporter = new XmlSchemaExporter(schemas); + exporter.ExportTypeMapping(xmlTypeMapping); + schemas.Compile(new ValidationEventHandler(ValidationCallbackWithErrorCode), true); + for (int i = 0; i < schemas.Count; i++) + { + XmlSchema schema = schemas[i]; + schemaSet.Add(schema); + } + return new XmlQualifiedName(xmlTypeMapping.TypeName, xmlTypeMapping.Namespace); + } + + private static void ValidationCallbackWithErrorCode(object sender, ValidationEventArgs args) + { + Console.WriteLine("Schema warning: " + args.Message); + } + } + } +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/RoundTripTest.cs b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/RoundTripTest.cs new file mode 100644 index 0000000000000..b39e1c79d8f5a --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/RoundTripTest.cs @@ -0,0 +1,332 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Data; +using System.Runtime.Serialization.Schema; +using System.Xml; +using Xunit; +using Xunit.Abstractions; + +namespace System.Runtime.Serialization.Schema.Tests +{ + public class RoundTripTest + { + private readonly ITestOutputHelper _output; + + public RoundTripTest(ITestOutputHelper output) + { + _output = output; + } + + [Fact] + public void RountTripTest() + { + XsdDataContractExporter exporter = new XsdDataContractExporter(); + exporter.Export(typeof(RootClass)); + XsdDataContractImporter importer = new XsdDataContractImporter(); + importer.Options = new ImportOptions(); + importer.Options.ImportXmlType = true; + importer.Options.ReferencedTypes.Add(typeof(DBNull)); + importer.Options.ReferencedTypes.Add(typeof(DateTimeOffset)); + importer.Import(exporter.Schemas); + string code = SchemaUtils.DumpCode(importer.CodeCompileUnit); + _output.WriteLine(code); + + Assert.Contains(@"This code was generated by a tool.", code); + Assert.Contains(@"namespace System.Runtime.Serialization.Schema.Tests", code); + Assert.Contains(@"public partial class RoundTripTestRootClass : object, System.Runtime.Serialization.IExtensibleDataObject", code); + Assert.Contains(@"[System.Xml.Serialization.XmlRootAttribute(ElementName=""SchemaDefinedType"", Namespace=""http://schemas.datacontract.org/2004/07/System.Runtime.Serialization"")]", code); + Assert.Contains(@"public partial class dataSetType : object, System.Xml.Serialization.IXmlSerializable", code); + Assert.Contains(@"[System.Runtime.Serialization.DataContractAttribute(Name=""RoundTripTest.DataContractClass"", Namespace=""http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Schema.Tests""", code); + Assert.Contains(@"public partial class RoundTripTestDataContractClass : object, System.Runtime.Serialization.IExtensibleDataObject", code); + Assert.Contains(@"[System.Runtime.Serialization.DataContractAttribute(Name=""RoundTripTest.DataContractStruct"", Namespace=""http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Schema.Tests""", code); + Assert.Contains(@"public partial struct RoundTripTestDataContractStruct : System.Runtime.Serialization.IExtensibleDataObject", code); + Assert.Contains(@"[System.Runtime.Serialization.DataContractAttribute(Name=""RoundTripTest.EmitDefaultClass"", Namespace=""http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Schema.Tests""", code); + Assert.Contains(@"public partial class RoundTripTestEmitDefaultClass : object, System.Runtime.Serialization.IExtensibleDataObject", code); + Assert.Contains(@"public System.Nullable NullableDataContractStruct2", code); + Assert.Contains(@"[System.Runtime.Serialization.DataContractAttribute(Name=""RoundTripTest.EncodingMismatchClass"", Namespace=""http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Schema.Tests""", code); + Assert.Contains(@"public partial class RoundTripTestEncodingMismatchClass : object, System.Runtime.Serialization.IExtensibleDataObject", code); + Assert.Contains(@"public enum RoundTripTestMyEnum : int", code); + Assert.Contains(@"TwoHundred = 200", code); + Assert.Contains(@"public enum RoundTripTestMyFlagsEnum : int", code); + Assert.Contains(@"Four = 4,", code); + Assert.Contains(@"public class ArrayOfNullableOfRoundTripTestMyEnumho3BZmza : System.Collections.Generic.List", code); + Assert.Contains(@"namespace schemas.microsoft.com._2003._10.Serialization.Arrays", code); + Assert.Contains(@"public partial class ArrayOfKeyValueOfintArrayOfstringty7Ep6D1 : object, System.Xml.Serialization.IXmlSerializable", code); + Assert.Contains(@"private static System.Xml.XmlQualifiedName typeName = new System.Xml.XmlQualifiedName(""ArrayOfKeyValueOfintArrayOfstringty7Ep6D1"", ""http://schemas.microsoft.com/2003/10/Serialization/Arrays"");", code); + Assert.Contains(@"public partial class ArrayOfKeyValueOfNullableOfunsignedByteNullableOfunsignedByte_ShTDFhl_P : object, System.Xml.Serialization.IXmlSerializable", code); + Assert.Contains(@"[System.Runtime.Serialization.DataContractAttribute(Name=""KeyValuePairOfstringNullableOfintU6ho3Bhd"", Namespace=""http://schemas.datacontract.org/2004/07/System.Collections.Generic"")]", code); + } + + [Fact] + public void IsReferenceType() + { + XsdDataContractExporter exporter = new XsdDataContractExporter(); + exporter.Export(typeof(RootIsReferenceContainer)); + XsdDataContractImporter importer = new XsdDataContractImporter(); + importer.Options = new ImportOptions(); + importer.Options.ImportXmlType = true; + importer.Import(exporter.Schemas); + string code = SchemaUtils.DumpCode(importer.CodeCompileUnit); + _output.WriteLine(code); + + Assert.True(code.Length > 616); + } + + +#pragma warning disable CS0169, CS0414, IDE0051, IDE1006 + #region RoundTripTest DataContracts + [DataContract] + public class RootClass + { + [DataMember] MyEnum myEnum; + [DataMember] MyEnum[] arrayOfMyEnum; + [DataMember] MyEnum? nullableOfMyEnum; + [DataMember] MyEnum?[] arrayOfNullableOfMyEnum; + [DataMember] MyFlagsEnum myFlagsEnum; + [DataMember] XmlNode[] xmlNodes; + [DataMember] XmlElement xmlElement; + [DataMember] DataContractClass dataContractClass; + [DataMember] DataContractClass[] arrayOfDataContractClass; + [DataMember] DataContractStruct dataContractStruct; + [DataMember] DataContractStruct[] arrayOfDataContractStruct; + [DataMember] DataContractStruct? nullableOfDataContractStruct; + [DataMember] DataContractStruct?[] arrayOfNullableOfDataContractStruct; + [DataMember] DataSet dataSet; + [DataMember] IList> intLists; + [DataMember] IList>> dictionaries; + [DataMember] IDictionary nullableValues; + [DataMember] IDictionary nullableKeyAndValues; + [DataMember] EmitDefaultClass emitDefaultClass; + [DataMember] EncodingMismatchClass encodingMismatchClass; + [DataMember] DBNull dbnull; + } + + public enum MyEnum { Hundred = 100, TwoHundred = 200 }; + [Flags] + public enum MyFlagsEnum { Four = 4, Eight = 8 }; + + [DataContract] + public class DataContractClass + { + [DataMember] public int IntValue; + [DataMember] public Guid GuidValue; + [DataMember] TimeSpan timeSpanValue; + } + + [DataContract] + public struct DataContractStruct + { + [DataMember] public char CharValue; + [DataMember] Decimal decimalValue; + [DataMember] XmlQualifiedName qname; + } + + + [DataContract] + public class EmitDefaultClass + { + [DataMember(EmitDefaultValue = false)] + public string Name1; + [DataMember(EmitDefaultValue = false)] + public int Age1; + [DataMember(EmitDefaultValue = false)] + public int? Salary1; + [DataMember(EmitDefaultValue = false)] + public DataContractStruct DataContractStruct1; + [DataMember(EmitDefaultValue = false)] + public DataContractStruct? NullableDataContractStruct1; + [DataMember(EmitDefaultValue = false)] + public DateTime DateTime1; + [DataMember(EmitDefaultValue = false)] + public DateTimeOffset DateTimeOffset1; + [DataMember(EmitDefaultValue = false)] + public Guid Guid1; + [DataMember(EmitDefaultValue = false)] + public Decimal Decimal1; + [DataMember(EmitDefaultValue = false)] + public TimeSpan TimeSpan1; + + [DataMember(IsRequired = true, EmitDefaultValue = false)] + public string Name2; + [DataMember(IsRequired = true, EmitDefaultValue = false)] + public int Age2; + [DataMember(IsRequired = true, EmitDefaultValue = false)] + public int? Salary2; + [DataMember(IsRequired = true, EmitDefaultValue = false)] + public DataContractStruct DataContractStruct2; + [DataMember(IsRequired = true, EmitDefaultValue = false)] + public DataContractStruct? NullableDataContractStruct2; + [DataMember(IsRequired = true, EmitDefaultValue = false)] + public DateTime DateTime2; + [DataMember(IsRequired = true, EmitDefaultValue = false)] + public DateTimeOffset DateTimeOffset2; + [DataMember(IsRequired = true, EmitDefaultValue = false)] + public Guid Guid2; + [DataMember(IsRequired = true, EmitDefaultValue = false)] + public Decimal Decimal2; + [DataMember(IsRequired = true, EmitDefaultValue = false)] + public TimeSpan TimeSpan2; + + } + + [DataContract] + public class EncodingMismatchClass + { + [DataMember(Name = "a:b")] + public int a; + [DataMember(Name = "a_x003A_bc_x003C__x003B_")] + public int b; + [DataMember(Name = "a_x003a_bc_x003b__x003c_")] + public int c; + } + #endregion + + #region IsReferenceType DataContracts + [DataContract] + class RootIsReferenceContainer + { + [DataMember] + RefEdibleItem r = new RefEdibleItem(); + [DataMember] + Fruit w = new Fruit(); + [DataMember] + RefApple x = new RefApple(); + [DataMember] + public RefCustomer customer = RefCustomer.CreateInstance(); + [DataMember] + RefGrades grades = new RefGrades(); + [DataMember] + CircularLinkedList_ContainsBackpointingRef clcb = new CircularLinkedList_ContainsBackpointingRef(); + [DataMember] + RefCircularLinks_ContainsBackpointer rccb = new RefCircularLinks_ContainsBackpointer(); + [DataMember] + RefCircularNodeA_ContainsRefWithBackpointer rcnacr = new RefCircularNodeA_ContainsRefWithBackpointer(); + } + + [DataContract(IsReference = true)] + class RefEdibleItem + { + } + + [DataContract] + class Fruit : RefEdibleItem + { + } + + [DataContract(IsReference = true)] + class RefApple : Fruit + { + } + + [CollectionDataContract(IsReference = true)] + public class RefGrades : List + { + } + + [DataContract(IsReference = true)] + class RefCustomer + { + [DataMember] + string Name; + [DataMember] + int ZipCode; + + internal static RefCustomer CreateInstance() + { + RefCustomer x = new RefCustomer(); + x.Name = "Bill Gates"; + x.ZipCode = 98052; + return x; + } + } + + + [DataContract] + public class CircularLinkedList_ContainsBackpointingRef + { + [DataMember] + RefNode start; + + [DataMember] + int numberOfNodes; + + public CircularLinkedList_ContainsBackpointingRef() + { + numberOfNodes = 4; + RefNode currentNode = null, prevNode = null; + start = null; + for (int i = 0; i < numberOfNodes; i++) + { + currentNode = new RefNode(i, "Hello World"); + if (i == 0) + start = currentNode; + if (prevNode != null) + prevNode.Next = currentNode; + prevNode = currentNode; + } + currentNode.Next = start; + } + } + + [DataContract(IsReference = true)] + public class RefNode + { + [DataMember] + public RefNode Next; + + [DataMember] + int id; + + [DataMember] + string name; + + public RefNode(int id, string name) + { + this.id = id; + this.name = name; + } + } + + + [DataContract(IsReference = true)] + public class RefCircularLinks_ContainsBackpointer + { + [DataMember] + RefCircularLinks_ContainsBackpointer link; + + public RefCircularLinks_ContainsBackpointer() + { + link = this; + } + } + + + [DataContract(IsReference = true)] + public class RefCircularNodeA_ContainsRefWithBackpointer + { + [DataMember] + RefCircularNodeB_ContainsRefWithBackpointer linkToB; + + public RefCircularNodeA_ContainsRefWithBackpointer() + { + linkToB = new RefCircularNodeB_ContainsRefWithBackpointer(this); + } + } + + [DataContract(IsReference = true)] + public class RefCircularNodeB_ContainsRefWithBackpointer + { + [DataMember] + RefCircularNodeA_ContainsRefWithBackpointer linkToA; + + public RefCircularNodeB_ContainsRefWithBackpointer(RefCircularNodeA_ContainsRefWithBackpointer nodeA) + { + linkToA = nodeA; + } + } + #endregion +#pragma warning restore CS0169, CS0414, IDE0051, IDE1006 + } +} diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/SchemaUtils.cs b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/SchemaUtils.cs new file mode 100644 index 0000000000000..cea8d7333ccb7 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/SchemaUtils.cs @@ -0,0 +1,370 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.CodeDom; +using System.CodeDom.Compiler; +using System.IO; +using System.Xml; +using System.Xml.Schema; + +namespace System.Runtime.Serialization.Schema.Tests +{ + internal class SchemaUtils + { + static XmlWriterSettings writerSettings = new XmlWriterSettings() { Indent = true }; + + #region Test Data + internal static XmlSchemaSet PositiveSchemas = SchemaUtils.ReadStringsIntoSchemaSet( + new string[] { + @" + + + ", + @" + + + ", + @" + + + + + ", + }); + + internal static XmlSchemaSet IsReferenceSchemas = SchemaUtils.ReadStringsIntoSchemaSet( + new string[] { + @" + + + + + + + + + ", + @" + + + + + + + + ", + }); + + internal static XmlSchemaSet MixedSchemas = SchemaUtils.ReadStringsIntoSchemaSet( + new string[] { + @" + + + + + ", + @" + + + ", + }); + + internal static string[] NegativeSchemaStrings = + new string[] { + @"", // null + @" + ", // new XmlQualifiedName("FooType", "http://EmptySchema"), + @" + ", // new XmlQualifiedName("FooType", "http://NonExistantSchema"), + @" + + + ", // null + @" + + + ", // null + @" + + + ", // new XmlQualifiedName("ExtraAttributeWildcardType", "http://schemas.datacontract.org/2004/07/foo"), + @" + + + ", // null + @" + + + ", // null + @" + + + ", // null + @" + + + ", // null + @" + + + ", // null + @" + + + ", // null + @" + + + ", // null + @" + + + + + ", // null + @" + + ", // null + }; + + internal static (bool expectedResult, bool isElement, XmlQualifiedName[] qnames, string schemaString)[] CanImportTests = new (bool, bool, XmlQualifiedName[], string)[] { + (false, false, new XmlQualifiedName[] { new XmlQualifiedName("InvalidTopLevelElementType", "http://schemas.datacontract.org/2004/07/foo") }, + @" + + + + "), + (true, false, new XmlQualifiedName[] { new XmlQualifiedName("ValidType", "http://schemas.datacontract.org/2004/07/foo") }, + @" + + + + "), + (true, false, new XmlQualifiedName[] { + new XmlQualifiedName("Address", "http://schemas.datacontract.org/2004/07/Suites.SchemaImport.Classes"), + new XmlQualifiedName("Person", "http://schemas.datacontract.org/2004/07/Suites.SchemaImport.Classes"), + new XmlQualifiedName("ArrayOfAddress", "http://schemas.datacontract.org/2004/07/Suites.SchemaImport.Classes"), + new XmlQualifiedName("ArrayOfArrayOfAddress", "http://schemas.datacontract.org/2004/07/Suites.SchemaImport.Classes"), + }, + @" + + + + + + + + + "), + (true, false, null, + @" + + + + "), + (true, false, null, + @" + + + "), + (false, false, new XmlQualifiedName[] { new XmlQualifiedName("TypeWithExtraAttributes", "http://schemas.datacontract.org/2004/07/foo") }, + @" + + + "), + (true, true, new XmlQualifiedName[] { new XmlQualifiedName("Address", "http://schemas.datacontract.org/2004/07/Suites.SchemaImport.Classes") }, + @" + + + + + + + + "), + }; + + internal static XmlQualifiedName[] ValidTypeNames = new XmlQualifiedName[] { + new XmlQualifiedName("ValidType", "http://schemas.datacontract.org/2004/07/fooNs"), + new XmlQualifiedName("AnotherValidType", "http://schemas.datacontract.org/2004/07/barNs"), + new XmlQualifiedName("NonAttributedType", "http://schemas.datacontract.org/2004/07/Suites.SchemaImport"), + new XmlQualifiedName("NonRefType", "http://schemas.datacontract.org/2004/07/Suites.SchemaImport.ReferencedTypes"), + new XmlQualifiedName("RefType1", "http://schemas.datacontract.org/2004/07/Suites.SchemaImport.ReferencedTypes"), + }; + + internal static XmlQualifiedName[] InvalidTypeNames = new XmlQualifiedName[] { + new XmlQualifiedName("InvalidType", "http://schemas.datacontract.org/2004/07/fooNs"), + }; + + // These correspond with the set in 'NegativeSchemaStrings' + internal static XmlQualifiedName[] NegativeTypeNames = new XmlQualifiedName[] { + null, + new XmlQualifiedName("FooType", "http://EmptySchema"), + new XmlQualifiedName("FooType", "http://NonExistantSchema"), + null, + null, + new XmlQualifiedName("ExtraAttributeWildcardType", "http://schemas.datacontract.org/2004/07/foo"), + null, + null, + null, + null, + null, + null, + null, + null, + null, + }; + + internal static string GlobalSchema = @" + + + "; + #endregion + + + internal static XsdDataContractImporter CreateImporterWithDefaultOptions() + { + XsdDataContractImporter importer = new XsdDataContractImporter(); + importer.Options = new ImportOptions(); + return importer; + } + + internal static string DumpCode(CodeCompileUnit ccu, CodeDomProvider provider = null) + { + provider ??= CodeDomProvider.CreateProvider("csharp"); + + CodeGeneratorOptions options = new CodeGeneratorOptions() + { + BlankLinesBetweenMembers = true, + BracingStyle = "C", + }; + + StringWriter sw = new StringWriter(); + provider.GenerateCodeFromCompileUnit(ccu, sw, options); + return sw.ToString(); + } + + internal static XmlSchema GetSchema(XmlSchemaSet schemaSet, string targetNs) + { + XmlSchema schema = null; + foreach (XmlSchema ctSchema in schemaSet.Schemas()) + { + if (ctSchema.TargetNamespace == targetNs) + { + schema = ctSchema; + break; + } + } + return schema; + } + + internal static XmlSchemaElement GetSchemaElement(XmlSchemaSet schemaSet, XmlQualifiedName qname) + { + foreach (XmlSchema schema in schemaSet.Schemas(qname.Namespace)) + { + XmlSchemaElement schemaElement = (XmlSchemaElement)schema.Elements[qname]; + if (schemaElement != null) + return schemaElement; + } + throw new Exception(String.Format("Element {0} is not found", qname)); + } + + internal static string GetSchemaString(XmlSchemaSet schemaSet, string targetNs) + { + XmlSchema schema = GetSchema(schemaSet, targetNs); + StringWriter stringWriter = new StringWriter(); + XmlWriter xmlWriter = XmlWriter.Create(stringWriter, writerSettings); + schema.Write(xmlWriter); + xmlWriter.Flush(); + return stringWriter.ToString(); + } + + internal static void SetSchemaString(XmlSchemaSet schemaSet, string targetNs, string schemaString) + { + XmlSchema schema = null; + foreach (XmlSchema ctSchema in schemaSet.Schemas()) + { + if (ctSchema.TargetNamespace == targetNs) + { + schema = ctSchema; + break; + } + } + schemaSet.Remove(schema); + schema = XmlSchema.Read(new StringReader(schemaString), null); + schemaSet.Add(schema); + } + + internal static string GetString(CodeTypeReference typeReference) + { + if (typeReference.ArrayRank > 0) + { + CodeTypeReference arrayType = typeReference; + string arrayString = String.Empty; + for (; ; ) + { + int rank = typeReference.ArrayRank; + arrayString += "["; + for (int r = 1; r < rank; r++) + arrayString += ","; + arrayString += "]"; + + typeReference = typeReference.ArrayElementType; + if (typeReference.ArrayRank == 0) + break; + } + return String.Format("Array of {0}{1}", typeReference.BaseType, arrayString); + } + else + return typeReference.BaseType; + } + + internal static string InsertAttribute(string xml, string xpath, string prefix, string localName, string ns, string value) + { + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.Load(XmlReader.Create(new StringReader(xml))); + XmlNamespaceManager nsMgr = new XmlNamespaceManager(xmlDoc.NameTable); + nsMgr.AddNamespace("xs", XmlSchema.Namespace); + XmlElement xmlElement = (XmlElement)xmlDoc.SelectSingleNode(xpath, nsMgr); + XmlAttribute xmlAttribute = xmlDoc.CreateAttribute(prefix, localName, ns); + xmlAttribute.Value = value; + xmlElement.Attributes.Append(xmlAttribute); + + StringWriter stringWriter = new StringWriter(); + xmlDoc.Save(XmlWriter.Create(stringWriter, writerSettings)); + return stringWriter.ToString(); + } + + internal static string InsertElement(string xml, string xpath, string xmlFrag, bool insertAfter) + { + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.Load(XmlReader.Create(new StringReader(xml))); + XmlNamespaceManager nsMgr = new XmlNamespaceManager(xmlDoc.NameTable); + nsMgr.AddNamespace("xs", XmlSchema.Namespace); + XmlNode xmlNode = xmlDoc.SelectSingleNode(xpath, nsMgr); + if (insertAfter) + xmlNode.ParentNode.InsertAfter(xmlDoc.ReadNode(XmlReader.Create(new StringReader(xmlFrag))), xmlNode); + else + xmlNode.ParentNode.InsertBefore(xmlDoc.ReadNode(XmlReader.Create(new StringReader(xmlFrag))), xmlNode); + + StringWriter stringWriter = new StringWriter(); + xmlDoc.Save(XmlWriter.Create(stringWriter, writerSettings)); + return stringWriter.ToString(); + } + + + internal static XmlSchemaSet ReadStringsIntoSchemaSet(params string[] schemaStrings) + { + XmlSchemaSet schemaSet = new XmlSchemaSet(); + foreach (string schemaString in schemaStrings) + { + StringReader reader = new StringReader(schemaString); + XmlSchema schema = XmlSchema.Read(reader, null); + if (schema == null) + throw new Exception("Could not read schema"); + schemaSet.Add(schema); + } + return schemaSet; + } + } +} diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/System.Runtime.Serialization.Xml.Tests.csproj b/src/libraries/System.Runtime.Serialization.Xml/tests/System.Runtime.Serialization.Xml.Tests.csproj index 5c8b68affe3cc..2a1c771fe38b6 100644 --- a/src/libraries/System.Runtime.Serialization.Xml/tests/System.Runtime.Serialization.Xml.Tests.csproj +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/System.Runtime.Serialization.Xml.Tests.csproj @@ -28,10 +28,29 @@ + + + + + + + + + + + + + + + + + + + - + diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExportOptionsTests.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExportOptionsTests.cs new file mode 100644 index 0000000000000..7f33e82eb3b26 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExportOptionsTests.cs @@ -0,0 +1,58 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Xunit; +using Xunit.Abstractions; + +namespace System.Runtime.Serialization.Xml.XsdDataContractExporterTests +{ + public class ExportOptionsTests + { + private readonly ITestOutputHelper _output; + + public ExportOptionsTests(ITestOutputHelper output) + { + _output = output; + } + + [Fact] + public void DefaultOptions() + { + ExportOptions options = new ExportOptions(); + Assert.NotNull(options); + Assert.Null(options.DataContractSurrogate); + Assert.NotNull(options.KnownTypes); + Assert.Empty(options.KnownTypes); + } + + [Fact] + public void GetImportOptions() + { + XsdDataContractExporter exporter = new XsdDataContractExporter(); + var options = new ExportOptions(); + exporter.Options = options; + Assert.NotNull(exporter.Options); + Assert.Equal(options, exporter.Options); + } + + [Fact] + public void SetImportOptions() + { + XsdDataContractExporter e = new XsdDataContractExporter(); + e.Options = new ExportOptions(); + Assert.Empty(e.Options.KnownTypes); + e.Options.KnownTypes.Add(typeof(Types.Point)); + Assert.Single(e.Options.KnownTypes); + } + + [Fact] + public void KnownTypes_Negative() + { + XsdDataContractExporter e = new XsdDataContractExporter(); + e.Options = new ExportOptions(); + e.Options.KnownTypes.Add(null); + var ex = Assert.Throws(() => e.Export(typeof(Types.Point))); + Assert.Equal(@"Cannot export null type provided via KnownTypesCollection.", ex.Message); + } + } +} diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExporterApiTests.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExporterApiTests.cs new file mode 100644 index 0000000000000..75d6950630c74 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExporterApiTests.cs @@ -0,0 +1,331 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Reflection; +using System.Xml; +using System.Xml.Schema; +using Xunit; +using Xunit.Abstractions; + +using SerializableTypes.XsdDataContractExporterTests; + +namespace System.Runtime.Serialization.Xml.XsdDataContractExporterTests +{ + public class ExporterApiTests + { + private readonly ITestOutputHelper _output; + public ExporterApiTests(ITestOutputHelper output) + { + _output = output; + } + + [Fact] + public void Ctor_Default() + { + XsdDataContractExporter xce = new XsdDataContractExporter(); + Assert.NotNull(xce); + Assert.Null(xce.Options); + } + + [Fact] + public void Ctor_Schemas() + { + XmlSchemaSet schemaSet = new XmlSchemaSet(); + XsdDataContractExporter xce = new XsdDataContractExporter(schemaSet); + Assert.NotNull(xce); + Assert.Null(xce.Options); + Assert.Equal(schemaSet, xce.Schemas); + } + + [Theory] + [MemberData(nameof(CanExport_MemberData))] + public void CanExport(bool expectedResult, string testname, Func canExport, Type expectedExceptionType = null, string msg = null) + { + _output.WriteLine($"=============== {testname} ==============="); + XsdDataContractExporter importer = new XsdDataContractExporter(); + if (expectedExceptionType == null) + { + Assert.Equal(expectedResult, canExport(importer)); + } + else + { + var ex = Assert.Throws(expectedExceptionType, () => canExport(importer)); + + if (!string.IsNullOrEmpty(msg)) + Assert.Equal(msg, ex.Message); + } + } + public static IEnumerable CanExport_MemberData() + { + //yield return new object[] { true, "", (XsdDataContractExporter exp) => exp.CanExport() }; + //yield return new object[] { false, "", (XsdDataContractExporter exp) => exp.CanExport(), typeof(), @"" }; + + // CanExport(Type) + yield return new object[] { true, "t1+", (XsdDataContractExporter exp) => exp.CanExport(typeof(Types.Point)) }; + yield return new object[] { false, "t2-", (XsdDataContractExporter exp) => exp.CanExport((Type)null), typeof(ArgumentNullException), @"Value cannot be null. (Parameter 'type')" }; + yield return new object[] { false, "t3-", (XsdDataContractExporter exp) => exp.CanExport(typeof(Types.NonSerializableSquare)) }; + yield return new object[] { true, "t4+", (XsdDataContractExporter exp) => exp.CanExport(typeof(Types.NonAttributedPersonStruct)) }; + yield return new object[] { true, "t5+", (XsdDataContractExporter exp) => exp.CanExport(typeof(Types.NonAttributedPersonClass)) }; + yield return new object[] { true, "t6+", (XsdDataContractExporter exp) => exp.CanExport(typeof(Types.ExtendedSquare)) }; + yield return new object[] { false, "t7-", (XsdDataContractExporter exp) => exp.CanExport(typeof(Types.RecursiveCollection1)) }; + yield return new object[] { false, "t8-", (XsdDataContractExporter exp) => exp.CanExport(typeof(Types.RecursiveCollection2)) }; + yield return new object[] { false, "t9-", (XsdDataContractExporter exp) => exp.CanExport(typeof(Types.RecursiveCollection3)) }; + yield return new object[] { false, "t10-", (XsdDataContractExporter exp) => exp.CanExport(typeof(Types.RecursiveCollection4)) }; + + // CanExport(ICollection) + yield return new object[] { true, "ca1+", (XsdDataContractExporter exp) => exp.CanExport(new Assembly[] { typeof(DataContractTypes).Assembly }) }; + yield return new object[] { false, "ca2-", (XsdDataContractExporter exp) => exp.CanExport((ICollection)null), typeof(ArgumentNullException), @"Value cannot be null. (Parameter 'assemblies')" }; + yield return new object[] { false, "ca3-", (XsdDataContractExporter exp) => exp.CanExport(new Assembly[] { null }), typeof(ArgumentException), @"Cannot export null assembly provided via 'assemblies' parameter." }; + yield return new object[] { false, "ca4-", (XsdDataContractExporter exp) => exp.CanExport(new Assembly[] { typeof(ExporterApiTests).Assembly }) }; + + // CanExport(ICollection) + yield return new object[] { true, "ct1+", (XsdDataContractExporter exp) => exp.CanExport(new Type[] { typeof(Types.Point), typeof(Types.Circle) }) }; + yield return new object[] { false, "ct2-", (XsdDataContractExporter exp) => exp.CanExport((ICollection)null), typeof(ArgumentNullException), @"Value cannot be null. (Parameter 'types')" }; + yield return new object[] { false, "ct3-", (XsdDataContractExporter exp) => exp.CanExport(new Type[] { null }), typeof(ArgumentException), @"Cannot export null type provided via 'types' parameter." }; + yield return new object[] { false, "ct4-", (XsdDataContractExporter exp) => exp.CanExport(new Type[] { typeof(Types.Point), typeof(Types.NonSerializableSquare) }) }; + } + + [Theory] + [MemberData(nameof(Export_MemberData))] + public void Export(string testname, Action export, Action schemaCheck = null) + { + _output.WriteLine($"=============== {testname} ==============="); + XsdDataContractExporter exporter = new XsdDataContractExporter(); + export(exporter); + + string schemas = SchemaUtils.DumpSchema(exporter.Schemas); + _output.WriteLine("Count = " + exporter.Schemas.Count); + _output.WriteLine(schemas); + + // When checking schema count, be sure to include the "Serialization" schema - which is omitted from 'DumpSchema' - as + // well as the XmlSchema, both of which are the base from which all further schemas build. + if (schemaCheck != null) + schemaCheck(schemas, exporter.Schemas); + + Assert.True(schemas.Length > 0); + } + public static IEnumerable Export_MemberData() + { + // Export(Type) + yield return new object[] { "Exp1", (XsdDataContractExporter exp) => exp.Export(typeof(Types.Point)), (string s, XmlSchemaSet ss) => { + Assert.Equal(3, ss.Count); + // *basic* + // Point + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + } }; + + // Export(ICollection) + yield return new object[] { "Exp2", (XsdDataContractExporter exp) => exp.Export(new Assembly[] { typeof(DataContractTypes).Assembly }), (string s, XmlSchemaSet ss) => { + Assert.Equal(21, ss.Count); + } }; + + // Export(ICollection) + yield return new object[] { "Exp3", (XsdDataContractExporter exp) => exp.Export(new Type[] { typeof(Types.Point), typeof(Types.Circle) }), (string s, XmlSchemaSet ss) => { + Assert.Equal(4, ss.Count); + // *basic* + // Point + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + // *shapes* + // Circle + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + } }; + yield return new object[] { "Exp4", (XsdDataContractExporter exp) => exp.Export(new Type[] { typeof(Types.NonAttributedPersonStruct), typeof(Types.NonAttributedPersonClass), typeof(Types.ExtendedSquare) }), (string s, XmlSchemaSet ss) => { + Assert.Equal(5, ss.Count); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + // *Types* + // NonAttributedPersonStruct + SchemaUtils.OrderedContains(@"", ref s); + Assert.Matches(@"\s*true", s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + // NonAttributedPersonClass + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + // ExtendedSquare + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + // *shapes* + // Square + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + // *basic* + // Point + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + } }; + + // EnumsTest - from Enums.cs + yield return new object[] { "ExpEnum", (XsdDataContractExporter exp) => exp.Export(new Type[] { typeof(System.Reflection.TypeAttributes) }), (string s, XmlSchemaSet ss) => { + Assert.Equal(3, ss.Count); + //Assert.Equal(3, ss.GlobalAttributes.Count); + Assert.Equal(5, ss.GlobalTypes.Count); + Assert.Equal(23, ss.GlobalElements.Count); + } }; + } + + [Theory] + [MemberData(nameof(Export_NegativeCases_MemberData))] + public void Export_NegativeCases(string testname, Action export, Type expectedExceptionType, string exMsg = null) + { + _output.WriteLine($"=============== {testname} ==============="); + XsdDataContractExporter exporter = new XsdDataContractExporter(); + var ex = Assert.Throws(expectedExceptionType, () => export(exporter)); + _output.WriteLine(ex.Message); + + if (exMsg != null) + Assert.Equal(exMsg, ex.Message); + } + public static IEnumerable Export_NegativeCases_MemberData() + { + // Export(Type) + yield return new object[] { "tn", (XsdDataContractExporter exp) => exp.Export((Type)null), typeof(ArgumentNullException), @"Value cannot be null. (Parameter 'type')" }; + yield return new object[] { "tinv", (XsdDataContractExporter exp) => exp.Export(typeof(Types.NonSerializableSquare)), typeof(InvalidDataContractException), @"Type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.Types.NonSerializableSquare' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. Alternatively, you can ensure that the type is public and has a parameterless constructor - all public members of the type will then be serialized, and no attributes will be required." }; + + // Export(ICollection) + yield return new object[] { "can", (XsdDataContractExporter exp) => exp.Export((ICollection)null), typeof(ArgumentNullException), @"Value cannot be null. (Parameter 'assemblies')" }; + yield return new object[] { "canv", (XsdDataContractExporter exp) => exp.Export(new Assembly[] { null }), typeof(ArgumentException), @"Cannot export null assembly provided via 'assemblies' parameter." }; + // This exception message might change with updates to this test assembly. Right now, 'NonSerializablePerson' is the non-serializable type that gets found first. If this becomes an issue, consider not verifying the exception message. + yield return new object[] { "cainv", (XsdDataContractExporter exp) => exp.Export(new Assembly[] { typeof(ExporterApiTests).Assembly }), typeof(InvalidDataContractException), @"Type 'NonSerializablePerson' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. Alternatively, you can ensure that the type is public and has a parameterless constructor - all public members of the type will then be serialized, and no attributes will be required." }; + + // Export(ICollection) + yield return new object[] { "ctn", (XsdDataContractExporter exp) => exp.Export((ICollection)null), typeof(ArgumentNullException), @"Value cannot be null. (Parameter 'types')" }; + yield return new object[] { "ctnv", (XsdDataContractExporter exp) => exp.Export(new Type[] { null }), typeof(ArgumentException), @"Cannot export null type provided via 'types' parameter." }; + yield return new object[] { "ctinv", (XsdDataContractExporter exp) => exp.Export(new Type[] { typeof(Types.Point), typeof(Types.NonSerializableSquare) }), typeof(InvalidDataContractException), @"Type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.Types.NonSerializableSquare' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. Alternatively, you can ensure that the type is public and has a parameterless constructor - all public members of the type will then be serialized, and no attributes will be required." }; + } + + [Theory] + [MemberData(nameof(GetSchemaTypeName_MemberData))] + public void GetSchemaTypeName(string testname, Type t, XmlQualifiedName qname, Type expectedExceptionType = null, string msg = null) + { + _output.WriteLine($"=============== {testname} ==============="); + XsdDataContractExporter exporter = new XsdDataContractExporter(); + + if (expectedExceptionType == null) + { + XmlQualifiedName schemaTypeName = exporter.GetSchemaTypeName(t); + Assert.Equal(qname, schemaTypeName); + } + else + { + var ex = Assert.Throws(expectedExceptionType, () => exporter.GetSchemaTypeName(t)); + if (!string.IsNullOrEmpty(msg)) + Assert.Equal(msg, ex.Message); + } + } + public static IEnumerable GetSchemaTypeName_MemberData() + { + // GetSchemaTypeName(Type) + yield return new object[] { "GSTN_Point", typeof(Types.Point), new XmlQualifiedName("Point", "http://basic") }; + yield return new object[] { "GSTN_null", null, null, typeof(ArgumentNullException), @"Value cannot be null. (Parameter 'type')" }; + yield return new object[] { "GSTN_invalid", typeof(Types.NonSerializableSquare), null, typeof(InvalidDataContractException), @"Type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.Types.NonSerializableSquare' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. Alternatively, you can ensure that the type is public and has a parameterless constructor - all public members of the type will then be serialized, and no attributes will be required." }; + yield return new object[] { "GSTN_Square", typeof(Types.Square), new XmlQualifiedName("Square", "http://shapes") }; + yield return new object[] { "GSTN_ExtSq", typeof(Types.ExtendedSquare), new XmlQualifiedName("ExtendedSquare", "http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Xml.XsdDataContractExporterTests.Types") }; + + // From DataContractTypesTest.cs + yield return new object[] { "DCTT_Addr2", typeof(DataContractTypes.Address2), new XmlQualifiedName("Address", "http://schemas.datacontract.org/2004/07/schemaexport.suites") }; + } + + [Theory] + [MemberData(nameof(GetSchemaType_MemberData))] + public void GetSchemaType(string testname, Type t, XmlSchemaType stName, Type expectedExceptionType = null, string msg = null) + { + _output.WriteLine($"=============== {testname} ==============="); + XsdDataContractExporter exporter = new XsdDataContractExporter(); + + if (expectedExceptionType == null) + { + XmlSchemaType schemaType = exporter.GetSchemaType(t); + Assert.Equal(stName, schemaType); + } + else + { + var ex = Assert.Throws(expectedExceptionType, () => exporter.GetSchemaType(t)); + if (!string.IsNullOrEmpty(msg)) + Assert.Equal(msg, ex.Message); + } + } + public static IEnumerable GetSchemaType_MemberData() + { + // GetSchemaTypeName(Type) + yield return new object[] { "GST_Point", typeof(Types.Point), null }; // Per the docs - "types for which the GetSchemaTypeName method returns a valid name, this method returns null." + yield return new object[] { "GST_null", null, null, typeof(ArgumentNullException), @"Value cannot be null. (Parameter 'type')" }; + yield return new object[] { "GST_invalid", typeof(Types.NonSerializableSquare), null, typeof(InvalidDataContractException), @"Type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.Types.NonSerializableSquare' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. Alternatively, you can ensure that the type is public and has a parameterless constructor - all public members of the type will then be serialized, and no attributes will be required." }; + } + + [Theory] + [MemberData(nameof(GetRootElementName_MemberData))] + public void GetRootElementName(string testname, Type t, XmlQualifiedName rName, Type expectedExceptionType = null, string msg = null) + { + _output.WriteLine($"=============== {testname} ==============="); + XsdDataContractExporter exporter = new XsdDataContractExporter(); + + if (expectedExceptionType == null) + { + XmlQualifiedName rootTypeName = exporter.GetRootElementName(t); + Assert.Equal(rName, rootTypeName); + } + else + { + var ex = Assert.Throws(expectedExceptionType, () => exporter.GetSchemaTypeName(t)); + if (!string.IsNullOrEmpty(msg)) + Assert.Equal(msg, ex.Message); + } + } + public static IEnumerable GetRootElementName_MemberData() + { + // GetSchemaTypeName(Type) + yield return new object[] { "GREN_Point", typeof(Types.Point), new XmlQualifiedName("Point", "http://basic") }; + yield return new object[] { "GREN_null", null, null, typeof(ArgumentNullException), @"Value cannot be null. (Parameter 'type')" }; + yield return new object[] { "GREN_invalid", typeof(Types.NonSerializableSquare), null, typeof(InvalidDataContractException), @"Type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.Types.NonSerializableSquare' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. Alternatively, you can ensure that the type is public and has a parameterless constructor - all public members of the type will then be serialized, and no attributes will be required." }; + yield return new object[] { "GREN_Square", typeof(Types.Square), new XmlQualifiedName("Square", "http://shapes") }; + yield return new object[] { "GREN_ExtSq", typeof(Types.ExtendedSquare), new XmlQualifiedName("ExtendedSquare", "http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Xml.XsdDataContractExporterTests.Types") }; + } + + [Fact] + public void get_Schemas_Bug() + { + // Bug 23200 from who knows which ancient bug database + // I believe the gist of this is that modifying the XmlSchemaSet provided by XsdDataContractExporter.get_Schemas + // can result in that same property throwing an exception? I'm not really sure what this bug is, or if this really + // is a bug. Neither the code in NetFx nor here actually throws an exception without the newly added lines. + XsdDataContractExporter exporter = new XsdDataContractExporter(); + exporter.Export(typeof(Types.Circle)); + XmlSchemaSet schemaSet = exporter.Schemas; // added - exception + foreach (XmlSchema schema in exporter.Schemas.Schemas("http://basic")) // original - Still no exception + exporter.Schemas.Remove(schema); + var ex = Assert.Throws(() => exporter.Schemas); // added + Assert.Equal(@"Type 'http://basic:Point' is not declared.", ex.Message); // added + exporter.Export(typeof(Types.Square)); + ex = Assert.Throws(() => exporter.Schemas); // added + Assert.Equal(@"Type 'http://basic:Point' is not declared.", ex.Message); // added + } + } +} diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExporterTypesTests.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExporterTypesTests.cs new file mode 100644 index 0000000000000..c79813748c4d5 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExporterTypesTests.cs @@ -0,0 +1,842 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections; +using System.Collections.Generic; +using System.Xml.Serialization; +using Xunit; +using Xunit.Abstractions; + +using SerializableTypes.XsdDataContractExporterTests; + +namespace System.Runtime.Serialization.Xml.XsdDataContractExporterTests +{ + public class ExporterTypesTests + { + private readonly ITestOutputHelper _output; + public ExporterTypesTests(ITestOutputHelper output) + { + _output = output; + } + + [Fact] + public void TypesTest() + { + var types = new List() + { + typeof(DataContractTypes.Person1), + typeof(DataContractTypes.Person2), + typeof(ExporterTypesTests.Group), + typeof(ExporterTypesTests.NoDataContract), + typeof(ExporterTypesTests.DataContractWithValidMember), + typeof(ExporterTypesTests.DataContractWithValidMember), + typeof(ExporterTypesTests.PersonInfo), + }; + + XsdDataContractExporter exporter = new XsdDataContractExporter(); + ExportOptions options = new ExportOptions(); + options.KnownTypes.Add(typeof(ArrayList)); + options.KnownTypes.Add(typeof(Guid)); + exporter.Options = options; + + exporter.Export(types); + exporter.Export(types); // Run twice, to ensure that types are not re-exported + + string schemas = SchemaUtils.DumpSchema(exporter.Schemas); + _output.WriteLine(schemas); + _output.WriteLine($"----------------- {exporter.Schemas.Count}, {exporter.Schemas.GlobalElements.Count}, {exporter.Schemas.GlobalTypes.Count}"); + + Assert.Equal(5, exporter.Schemas.Count); + Assert.Equal(36, exporter.Schemas.GlobalElements.Count); + Assert.Equal(18, exporter.Schemas.GlobalTypes.Count); + + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + } + + [Theory] + [InlineData(typeof(NoDataContractWithoutParameterlessConstructor), typeof(InvalidDataContractException), @"Type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+NoDataContractWithoutParameterlessConstructor' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. Alternatively, you can ensure that the type is public and has a parameterless constructor - all public members of the type will then be serialized, and no attributes will be required.")] + [InlineData(typeof(DataContractWithInvalidMember), typeof(InvalidDataContractException), @"Type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+NoDataContractWithoutParameterlessConstructor' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. Alternatively, you can ensure that the type is public and has a parameterless constructor - all public members of the type will then be serialized, and no attributes will be required.")] + [InlineData(typeof(SerializableWithInvalidMember), typeof(InvalidDataContractException), @"Type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+NoDataContractWithoutParameterlessConstructor' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. Alternatively, you can ensure that the type is public and has a parameterless constructor - all public members of the type will then be serialized, and no attributes will be required.")] + [InlineData(typeof(TypeWithReadWriteCollectionAndNoCtorOnCollection), typeof(InvalidDataContractException), @"System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+CollectionWithoutParameterlessCtor`1[[System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+Person, System.Runtime.Serialization.Xml.Tests, Version=7.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51]] does not have a default constructor.")] + // Yes, the exception type for this next one is different. It was different in NetFx as well. + [InlineData(typeof(ArrayContainer), typeof(InvalidOperationException), @"DataContract for type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+ArrayB' cannot be added to DataContractSet since type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+ArrayA' with the same data contract name 'Array' in namespace 'http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Xml.XsdDataContractExporterTests' is already present and the contracts are not equivalent.")] + [InlineData(typeof(KeyValueNameSame), typeof(InvalidDataContractException), @"The collection data contract type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+KeyValueNameSame' specifies the same value 'MyName' for both the KeyName and the ValueName properties. This is not allowed. Consider changing either the KeyName or the ValueName property.")] + [InlineData(typeof(AnyWithRoot), typeof(InvalidDataContractException), @"Type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+AnyWithRoot' cannot specify an XmlRootAttribute attribute because its IsAny setting is 'true'. This type must write all its contents including the root element. Verify that the IXmlSerializable implementation is correct.")] + public void TypesTest_Negative(Type badType, Type exType, string exMsg = null) + { + XsdDataContractExporter exporter = new XsdDataContractExporter(); + var ex = Assert.Throws(exType, () => exporter.Export(badType)); + if (exMsg != null) + Assert.Equal(exMsg, ex.Message); + } + + [Theory] + [InlineData(new Type[] { typeof(AddressA), typeof(AddressB) }, typeof(InvalidOperationException), @"DataContract for type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+AddressB' cannot be added to DataContractSet since type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+AddressA' with the same data contract name 'Address' in namespace 'http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Xml.XsdDataContractExporterTests' is already present and the contracts are not equivalent.")] + [InlineData(new Type[] { typeof(AddressA), typeof(AddressC) }, typeof(InvalidOperationException), @"DataContract for type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+AddressC' cannot be added to DataContractSet since type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+AddressA' with the same data contract name 'Address' in namespace 'http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Xml.XsdDataContractExporterTests' is already present and the contracts are not equivalent.")] + [InlineData(new Type[] { typeof(OrderA), typeof(OrderB) }, typeof(InvalidOperationException), @"DataContract for type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+OrderB' cannot be added to DataContractSet since type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+OrderA' with the same data contract name 'Order' in namespace 'http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Xml.XsdDataContractExporterTests' is already present and the contracts are not equivalent.")] + [InlineData(new Type[] { typeof(ArrayA), typeof(ArrayB) }, typeof(InvalidOperationException), @"DataContract for type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+ArrayB' cannot be added to DataContractSet since type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+ArrayA' with the same data contract name 'Array' in namespace 'http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Xml.XsdDataContractExporterTests' is already present and the contracts are not equivalent.")] + [InlineData(new Type[] { typeof(EnumA), typeof(EnumB) }, typeof(InvalidOperationException), @"DataContract for type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+EnumB' cannot be added to DataContractSet since type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+EnumA' with the same data contract name 'Enum' in namespace 'http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Xml.XsdDataContractExporterTests' is already present and the contracts are not equivalent.")] + [InlineData(new Type[] { typeof(EnumB), typeof(EnumC) }, typeof(InvalidOperationException), @"DataContract for type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+EnumC' cannot be added to DataContractSet since type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+EnumB' with the same data contract name 'Enum' in namespace 'http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Xml.XsdDataContractExporterTests' is already present and the contracts are not equivalent.")] + [InlineData(new Type[] { typeof(EnumContainerA), typeof(EnumContainerB) }, typeof(InvalidOperationException), @"DataContract for type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+EnumContainerB' cannot be added to DataContractSet since type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+EnumContainerA' with the same data contract name 'EnumContainer' in namespace 'http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Xml.XsdDataContractExporterTests' is already present and the contracts are not equivalent.")] + [InlineData(new Type[] { typeof(CollectionA), typeof(CollectionB) }, typeof(InvalidOperationException), @"DataContract for type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+CollectionB' cannot be added to DataContractSet since type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+CollectionA' with the same data contract name 'MyCollection' in namespace 'http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Xml.XsdDataContractExporterTests' is already present and the contracts are not equivalent.")] + [InlineData(new Type[] { typeof(DictionaryA), typeof(DictionaryB) }, typeof(InvalidOperationException), @"DataContract for type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+DictionaryB' cannot be added to DataContractSet since type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+DictionaryA' with the same data contract name 'MyDictionary' in namespace 'http://schemas.datacontract.org/2004/07/System.Runtime.Serialization.Xml.XsdDataContractExporterTests' is already present and the contracts are not equivalent.")] + public void TypeArrayTest_Negative(Type[] badTypes, Type exType, string exMsg = null) + { + XsdDataContractExporter exporter = new XsdDataContractExporter(); + var ex = Assert.Throws(exType, () => exporter.Export(badTypes)); + if (exMsg != null) + Assert.Equal(exMsg, ex.Message); + } + + [Fact] + public void ReferenceTypes() // From IsReferenceTypes.cs + { + List types = new List() + { + typeof(ExporterTypesTests.Order_ContainsRef), + typeof(ExporterTypesTests.Customers_ContainsDuplicateRefs), + typeof(ExporterTypesTests.Student_ContainsDuplicateCollectionRefs), + typeof(ExporterTypesTests.CircularLinkedList_ContainsBackpointingRef), + typeof(ExporterTypesTests.RefCircularLinks_ContainsBackpointer), + typeof(ExporterTypesTests.RefCircularNodeA_ContainsRefWithBackpointer), + typeof(ExporterTypesTests.RefNestedNode_ContainsBackpointer), + typeof(ExporterTypesTests.RefSimpleDataContractCycle_ContainsRefWithBackpointer), + typeof(ExporterTypesTests.Fruit), + typeof(ExporterTypesTests.RefApple), + typeof(ExporterTypesTests.EdibleContainer_ContainsPolymorphicRefs), + }; + + XsdDataContractExporter exporter = new XsdDataContractExporter(); + ExportOptions options = new ExportOptions(); + options.KnownTypes.Add(typeof(ArrayList)); + options.KnownTypes.Add(typeof(Guid)); + + exporter.Export(types); + exporter.Export(types); // Run twice, to ensure that types are not re-exported + + string schemas = SchemaUtils.DumpSchema(exporter.Schemas); + _output.WriteLine(schemas); + _output.WriteLine($"----------------- {exporter.Schemas.Count}, {exporter.Schemas.GlobalElements.Count}, {exporter.Schemas.GlobalTypes.Count}"); + + Assert.Equal(3, exporter.Schemas.Count); + Assert.Equal(39, exporter.Schemas.GlobalElements.Count); + Assert.Equal(21, exporter.Schemas.GlobalTypes.Count); + + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + SchemaUtils.OrderedContains(@"", ref schemas); + } + + [Theory] + [InlineData(typeof(ExporterTypesTests.Fruit2), typeof(InvalidDataContractException), @"The IsReference setting for type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+Fruit2' is 'False', but the same setting for its parent class 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+RefEdibleItem' is 'True'. Derived types must have the same value for IsReference as the base type. Change the setting on type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+Fruit2' to 'True', or on type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+RefEdibleItem' to 'False', or do not set IsReference explicitly.")] + [InlineData(typeof(ExporterTypesTests.Orange), typeof(InvalidDataContractException), @"The IsReference setting for type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+Orange' is 'False', but the same setting for its parent class 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+Fruit' is 'True'. Derived types must have the same value for IsReference as the base type. Change the setting on type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+Orange' to 'True', or on type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+Fruit' to 'False', or do not set IsReference explicitly.")] + [InlineData(typeof(ExporterTypesTests.RefEnum), typeof(InvalidDataContractException), @"Enum type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+RefEnum' cannot have the IsReference setting of 'True'. Either change the setting to 'False', or remove it completely.")] + public void ReferenceTypes_Negative(Type badRefType, Type exType, string exMsg = null) + { + XsdDataContractExporter exporter = new XsdDataContractExporter(); + var ex = Assert.Throws(exType, () => exporter.Export(badRefType)); + if (exMsg != null) + Assert.Equal(exMsg, ex.Message); + } + +#pragma warning disable CS0169, CS0414 + public class NoDataContract + { + } + + [DataContract] + public class DataContractWithValidMember + { + [DataMember] + NoDataContract member; + } + + [Serializable] + public class SerializableWithValidMember + { + NoDataContract member; + } + + public class NoDataContractWithoutParameterlessConstructor + { + public NoDataContractWithoutParameterlessConstructor(string init) + { + } + } + + [DataContract] + public class DataContractWithInvalidMember + { + [DataMember] + NoDataContractWithoutParameterlessConstructor member; + } + + [Serializable] + public class SerializableWithInvalidMember + { + NoDataContractWithoutParameterlessConstructor member; + } + + [DataContract(Name = "Order")] + public class OrderA + { + [DataMember] + public AddressA address; + } + + [DataContract(Name = "Order")] + public class OrderB + { + [DataMember] + public AddressB address; + } + + [DataContract(Name = "BaseOrder")] + public class BaseOrder + { + } + + [DataContract(Name = "Order")] + public class OrderD : BaseOrder + { + [DataMember] + public AddressA address; + } + + [DataContract(Name = "Address")] + public class AddressA + { + [DataMember] + public string zip; + } + + [DataContract(Name = "Address")] + public class AddressB + { + [DataMember] + public int zip; + } + + [DataContract(Name = "Address")] + public class AddressC + { + [DataMember] + public string street; + [DataMember(IsRequired = true)] + public string zip; + } + + [DataContract] + public class ArrayContainer + { + [DataMember] + public ArrayA a1; + [DataMember] + public ArrayB a2; + } + + [DataContract(Name = "Array")] + public class ArrayA + { + [DataMember] + public ArrayA[] items; + } + + [DataContract(Name = "Array")] + public class ArrayB + { + [DataMember] + public ArrayC[] items; + } + + [DataContract(Name = "Array")] + public class ArrayC + { + [DataMember] + public int items; + } + + [DataContract(Name = "EnumContainer")] + public class EnumContainerA + { + [DataMember] + public EnumA member; + } + + [DataContract(Name = "EnumContainer")] + public class EnumContainerB + { + [DataMember] + public EnumB member; + } + + [DataContract(Name = "Enum")] + public enum EnumA : long + { + } + + [DataContract(Name = "Enum")] + public enum EnumB : long + { + [EnumMember] Min, + [EnumMember] Zero, + [EnumMember] Max, + } + + [DataContract(Name = "Enum")] + public enum EnumC : long + { + [EnumMember] Min, + [EnumMember] Max, + } + + [Serializable] + public class Group + { + public IList People; + } + + [KnownType(typeof(Employee))] + [Serializable] + public class Person + { + string name = "John Smith"; + } + + + [KnownType(typeof(Admin))] + [KnownType(typeof(Architect))] + [KnownType(typeof(Engineer))] + [Serializable] + public class Employee : Person + { + int empId = 42; + } + + [Serializable] + public class Engineer : Employee + { + } + + [Serializable] + [KnownType(typeof(Admin))] + public class Admin : Employee + { + } + + [Serializable] + [KnownType(typeof(Person))] + public class Architect : Employee + { + } + + [CollectionDataContract(Name = "MyCollection", ItemName = "MyItemA")] + public class CollectionA : List + { + } + + [CollectionDataContract(Name = "MyCollection", ItemName = "MyItemB")] + public class CollectionB : List + { + } + + [CollectionDataContract(Name = "MyDictionary", KeyName = "MyKeyA")] + public class DictionaryA : Dictionary + { + } + + [CollectionDataContract(Name = "MyDictionary", KeyName = "MyKeyB")] + public class DictionaryB : Dictionary + { + } + + [CollectionDataContract(KeyName = "MyName", ValueName = "MyName")] + public class KeyValueNameSame : Dictionary + { + } + + [XmlSchemaProvider(null, IsAny = true)] + [XmlRoot(ElementName = "AnyRootElement", IsNullable = false)] + public class AnyWithRoot : XmlSerializableBase + { + } + + public class PersonInfo + { + CollectionWithoutParameterlessCtor localPersons; + ArrayList localPersonArrayList; + public InnerPersonCollection innerPersonInfo = new InnerPersonCollection(); + + public CollectionWithoutParameterlessCtor Persons + { + get + { + localPersons = localPersons ?? new CollectionWithoutParameterlessCtor(5); + return localPersons; + } + } + + public ArrayList PersonArrayList + { + get + { + localPersonArrayList = localPersonArrayList ?? new ArrayList(); + return localPersonArrayList; + } + } + + public PersonInfo() + { + Person p1 = new Person(); + + Person p2 = new Person(); + + Person p3 = new Person(); + + this.Persons.Add(p1); + this.Persons.Add(p2); + + this.PersonArrayList.Add(new Guid()); + this.PersonArrayList.Add("teststring"); + + this.innerPersonInfo.Friends.Add(p3); + + this.innerPersonInfo.PotentialSalaries[0] = 90.0; + this.innerPersonInfo.PotentialSalaries[1] = 100.0; + this.innerPersonInfo.PotentialSalaries[2] = 106.0; + + this.innerPersonInfo.PotentialExpenditures = new double[] { 50.0, 55.0, 69.0 }; + + } + } + + public class InnerPersonCollection + { + private double[] potentialSalaries; + private double[] potentialExpenditures; + CollectionWithoutParameterlessCtor friends; + + public double[] PotentialSalaries + { + get + { + potentialSalaries = potentialSalaries ?? new double[3]; + return potentialSalaries; + } + } + + public double[] PotentialExpenditures + { + get + { + return potentialExpenditures; + } + set + { + potentialExpenditures = value; + } + } + + + public CollectionWithoutParameterlessCtor Friends + { + get + { + friends = friends ?? new CollectionWithoutParameterlessCtor(2); + return friends; + } + } + } + + public class TypeWithReadWriteCollectionAndNoCtorOnCollection + { + private double[] potentialSalaries; + private double[] potentialExpenditures; + CollectionWithoutParameterlessCtor friends; + + public double[] PotentialSalaries + { + get + { + potentialSalaries = potentialSalaries ?? new double[3]; + return potentialSalaries; + } + } + + public double[] PotentialExpenditures + { + get + { + return potentialExpenditures; + } + set + { + potentialExpenditures = value; + } + } + + + public CollectionWithoutParameterlessCtor Friends + { + get + { + friends = friends ?? new CollectionWithoutParameterlessCtor(2); + return friends; + } + set + { + friends = value; + } + } + } + + public class CollectionWithoutParameterlessCtor : ICollection + { + ArrayList list; + + public CollectionWithoutParameterlessCtor(int size) + { + list = new ArrayList(size); + } + + #region ICollection Members + + public void Add(T item) + { + list.Add(item); + } + + public void Clear() + { + list.Clear(); + } + + public bool Contains(T item) + { + return list.Contains(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + list.CopyTo(array, arrayIndex); + } + + public int Count + { + get { return list.Count; } + } + + public bool IsReadOnly + { + get { return list.IsReadOnly; } + } + + public bool Remove(T item) + { + list.Remove(item); + return true; + } + + #endregion + + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + for (int i = 0; i < list.Count; i++) + { + yield return (T)list[i]; + } + } + + #endregion + + #region IEnumerable Members + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return list.GetEnumerator(); + } + + #endregion + } + + #region IsReferenceTypes + [DataContract] + class Order_ContainsRef + { + [DataMember] + public string Id = "29817691"; + [DataMember] + public string Url = "http://www.contoso.com/store/exec/OrderManagement?id=x9876270adh8q"; + [DataMember] + public RefCustomer RefCustomer = RefCustomer.CreateInstance(); + } + + [DataContract(IsReference = true)] + class RefEdibleItem + { + } + + [DataContract(IsReference = false)] + class Fruit2 : RefEdibleItem + { + } + + [DataContract] + class Fruit : RefEdibleItem + { + } + + [DataContract(IsReference = true)] + class RefApple : Fruit + { + } + + [DataContract(IsReference = false)] + class Orange : Fruit + { + } + + [DataContract] + [KnownType(typeof(Fruit))] + [KnownType(typeof(RefApple))] + class EdibleContainer_ContainsPolymorphicRefs + { + [DataMember] + RefEdibleItem w = new Fruit(); + [DataMember] + RefEdibleItem x = new RefApple(); + [DataMember] + Fruit z = new RefApple(); + } + + [DataContract] + class Customers_ContainsDuplicateRefs + { + static RefCustomer customer = RefCustomer.CreateInstance(); + [DataMember] + public RefCustomer RefCustomer1 = customer; + [DataMember] + public RefCustomer RefCustomer2 = customer; + } + + [DataContract] + public class Student_ContainsDuplicateCollectionRefs + { + static RefGrades grades; + + static Student_ContainsDuplicateCollectionRefs() + { + grades = new RefGrades(); + grades.Add("A"); + } + + [DataMember] + RefGrades grades1 = grades; + [DataMember] + RefGrades grades2 = grades; + } + + [CollectionDataContract(IsReference = true)] + public class RefGrades : List + { + } + + [DataContract(IsReference = true)] + class RefCustomer + { + [DataMember] + string Name; + [DataMember] + int ZipCode; + + internal static RefCustomer CreateInstance() + { + RefCustomer x = new RefCustomer(); + x.Name = "Bill Gates"; + x.ZipCode = 98052; + return x; + } + } + + + [DataContract] + public class CircularLinkedList_ContainsBackpointingRef + { + [DataMember] + RefNode start; + + [DataMember] + int numberOfNodes; + + public CircularLinkedList_ContainsBackpointingRef() + { + numberOfNodes = 4; + RefNode currentNode = null, prevNode = null; + start = null; + for (int i = 0; i < numberOfNodes; i++) + { + currentNode = new RefNode(i, "Hello World"); + if (i == 0) + start = currentNode; + if (prevNode != null) + prevNode.Next = currentNode; + prevNode = currentNode; + } + currentNode.Next = start; + } + } + + [DataContract(IsReference = true)] + public class RefNode + { + [DataMember] + public RefNode Next; + + [DataMember] + int id; + + [DataMember] + string name; + + public RefNode(int id, string name) + { + this.id = id; + this.name = name; + } + } + + + [DataContract(IsReference = true)] + public class RefCircularLinks_ContainsBackpointer + { + [DataMember] + RefCircularLinks_ContainsBackpointer link; + + public RefCircularLinks_ContainsBackpointer() + { + link = this; + } + } + + + [DataContract(IsReference = true)] + public class RefCircularNodeA_ContainsRefWithBackpointer + { + [DataMember] + RefCircularNodeB_ContainsRefWithBackpointer linkToB; + + public RefCircularNodeA_ContainsRefWithBackpointer() + { + linkToB = new RefCircularNodeB_ContainsRefWithBackpointer(this); + } + } + + [DataContract(IsReference = true)] + public class RefCircularNodeB_ContainsRefWithBackpointer + { + [DataMember] + RefCircularNodeA_ContainsRefWithBackpointer linkToA; + + public RefCircularNodeB_ContainsRefWithBackpointer(RefCircularNodeA_ContainsRefWithBackpointer nodeA) + { + linkToA = nodeA; + } + } + + + [DataContract(IsReference = true)] + public class RefNestedNode_ContainsBackpointer + { + [DataMember] + RefNestedNode_ContainsBackpointer node; + + [DataMember] + int level; + + public RefNestedNode_ContainsBackpointer(int level) + : this(level, null) + { + } + + public RefNestedNode_ContainsBackpointer(int level, RefNestedNode_ContainsBackpointer rootNode) + { + if (level > 0) + this.node = new RefNestedNode_ContainsBackpointer(level - 1, (rootNode == null ? this : rootNode)); + else + this.node = rootNode; + this.level = level; + } + } + + + [DataContract(IsReference = true)] + public class RefSimpleDataContractCycle_ContainsRefWithBackpointer + { + [DataMember] + object emptyFirstMember = new object(); + [DataMember] + public RefSimpleDataContractCycleNextLink next; + + public static RefSimpleDataContractCycle_ContainsRefWithBackpointer CreateInstance() + { + RefSimpleDataContractCycle_ContainsRefWithBackpointer simpleCycle = new RefSimpleDataContractCycle_ContainsRefWithBackpointer(); + RefSimpleDataContractCycleNextLink childLink = new RefSimpleDataContractCycleNextLink(); + simpleCycle.next = childLink; + childLink.backLink = simpleCycle; + return simpleCycle; + } + } + + + [DataContract] + public class RefSimpleDataContractCycleNextLink + { + [DataMember] + public RefSimpleDataContractCycle_ContainsRefWithBackpointer backLink; + } + + [DataContract(IsReference = true)] + enum RefEnum + { + + } + #endregion + +#pragma warning restore CS0169, CS0414 + } +} diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SchemaUtils.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SchemaUtils.cs new file mode 100644 index 0000000000000..9379df362e593 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SchemaUtils.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.IO; +using System.Text; +using System.Xml; +using System.Xml.Schema; +using Xunit; + +namespace System.Runtime.Serialization.Xml.XsdDataContractExporterTests +{ + internal class SchemaUtils + { + internal static string SerializationNamespace = "http://schemas.microsoft.com/2003/10/Serialization/"; + static XmlWriterSettings writerSettings = new XmlWriterSettings() { Indent = true }; + + public static string OrderedContains(string expected, ref string actual) + { + Assert.Contains(expected, actual); + actual = actual.Substring(actual.IndexOf(expected)); + return actual; + } + + public static string DumpSchema(XmlSchemaSet schemas) + { + StringBuilder sb = new StringBuilder(); + StringWriter sw = new StringWriter(sb); + foreach (XmlSchema schema in schemas.Schemas()) + { + if (schema.TargetNamespace != SerializationNamespace) + { + schema.Write(sw); + } + sw.WriteLine(); + } + sw.Flush(); + return sb.ToString(); + } + + internal static XmlSchema GetSchema(XmlSchemaSet schemaSet, string targetNs) + { + XmlSchema schema = null; + foreach (XmlSchema ctSchema in schemaSet.Schemas()) + { + if (ctSchema.TargetNamespace == targetNs) + { + schema = ctSchema; + break; + } + } + return schema; + } + } +} diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/ArrayTypes.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/ArrayTypes.cs new file mode 100644 index 0000000000000..3ae741883b396 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/ArrayTypes.cs @@ -0,0 +1,102 @@ +using System; +using System.Runtime.Serialization; +using System.Collections.Generic; + +#if UseSeparateAssemblyNamespace +using Address = SerializableTypes.XsdDataContractExporterTests.Address; +using Employee = SerializableTypes.XsdDataContractExporterTests.Employee; + +namespace SerializableTypes.XsdDataContractExporterTests.ArrayTypes +#else +using Address = System.Runtime.Serialization.Xml.XsdDataContractExporterTests.Address; +using Employee = System.Runtime.Serialization.Xml.XsdDataContractExporterTests.Employee; + +namespace System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ArrayTypes +#endif +{ + [Serializable] + public class Company + { + string name; + string[] products; + Address address; + [OptionalField] + Employee[] employees; + } + + // IsRequired default different for [Serializable] and [DataContract] + [DataContract(Name="Company")] + public class Company2 + { + [DataMember(IsRequired=true)] + public string name; + + [DataMember(Name="products", IsRequired=true)] + public string[] Products; + + [DataMember(IsRequired = true)] + Address address; + + [DataMember] + Employee[] employees; + + public Company2() + { + } + } + + [DataContract(Namespace="http://schemas.datacontract.org/2004/07/SerializableTypes.XsdDataContractExporterTests")] + public class Employee + { + [DataMember(IsRequired=true)] + Company company; + } + + [DataContract] + public class JaggedArrays + { + [DataMember] + Company[] companyArray_1rank; + + [DataMember] + Company[][] companyArray_2rank; + + [DataMember] + Company[][][] companyArray_3rank; + + [DataMember] + object[] objectArray_1rank; + + [DataMember] + object[][] objectArray_2rank; + + [DataMember] + ManagerEmployeeList peerList; + + [DataMember] + DateTimeOffset[] dateTimeOffsetArray_1rank; + + [DataMember] + DateTimeOffset[][] dateTimeOffsetArray_2rank; + } + + [DataContract] + public class SystemArray + { + + [DataMember] + public Array[] arrayArray; + + [DataMember] + public Array array; + + } + + [CollectionDataContract] + public class ManagerEmployeeList : List> + { + } +} + + + diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/ConfigTypes.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/ConfigTypes.cs new file mode 100644 index 0000000000000..93f3e69494afc --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/ConfigTypes.cs @@ -0,0 +1,52 @@ +#if UseSeparateAssemblyNamespace +namespace SerializableTypes.XsdDataContractExporterTests +#else +namespace System.Runtime.Serialization.Xml.XsdDataContractExporterTests +#endif +{ + using System; + + [Serializable] + public class ConfigBase1 + { + string foo = "bar"; + } + + [Serializable] + public class ConfigDerived1 : ConfigBase1 + { + } + + [Serializable] + public class ConfigBase2 + { + string foo = "bar"; + } + + [Serializable] + public class ConfigDerived2 : ConfigBase2 + { + } + + [Serializable] + public class ConfigBase3 + { + string foo = "bar"; + } + + [Serializable] + public class ConfigDerived3 : ConfigBase3 + { + } + + [Serializable] + public class ConfigBase4 + { + string foo = "bar"; + } + + [Serializable] + public class ConfigDerived4 : ConfigBase4 + { + } +} diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/ConflictingNameTypes.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/ConflictingNameTypes.cs new file mode 100644 index 0000000000000..b44de0e7f640e --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/ConflictingNameTypes.cs @@ -0,0 +1,72 @@ +using System; +using System.Runtime.Serialization; + +#if UseSeparateAssemblyNamespace +namespace SerializableTypes.XsdDataContractExporterTests +#else +namespace System.Runtime.Serialization.Xml.XsdDataContractExporterTests +#endif +{ + public class ConflictingNameTypes + { + [DataContract] + public class ConflictBase + { + [DataMember(IsRequired=true)] + int a; + } + + [DataContract] + public class ConflictDerived1 : ConflictBase + { + [DataMember(IsRequired = true)] + int a; + } + + [DataContract] + public class ConflictDerived2 : ConflictBase + { + [DataMember(IsRequired = true)] + string[] a; + } + + [DataContract] + public class ConflictDerived11 : ConflictDerived1 + { + [DataMember(IsRequired = true)] + int a; + } + + [DataContract] + public class ConflictDerived12 : ConflictDerived1 + { + [DataMember(IsRequired = true)] + string a; + } + + [DataContract] + public class NoConflictBase + { + [DataMember(IsRequired = true)] + int a; + } + + [DataContract] + public class NoConflictDerived1 : NoConflictBase + { + [DataMember(IsRequired = true)] + int a; + } + + [DataContract(Namespace="http://www.tempuri.org/")] + public class NoConflictDerived2 : NoConflictBase + { + [DataMember(IsRequired = true)] + string a; + } + + } +} + + + diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/DataContractSurrogate.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/DataContractSurrogate.cs new file mode 100644 index 0000000000000..c7570de114bd6 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/DataContractSurrogate.cs @@ -0,0 +1,98 @@ +using System; +using System.Runtime.Serialization; +using System.Xml; +using System.Xml.Serialization; +using System.Xml.Schema; + +#if UseSeparateAssemblyNamespace +namespace SerializableTypes.XsdDataContractExporterTests +#else +namespace System.Runtime.Serialization.Xml.XsdDataContractExporterTests +#endif +{ + public class DataContractSurrogate + { + [DataContract] + public class CircleContainer + { + [DataMember] + Circle circle; + [DataMember] + public Circle[] Circles{ get { return null;} set {}} + } + + [Serializable] + public class Circle + { + public int Radius; + } + + [Serializable] + public class Square + { + public int Side; + } + + public class Node + { + Node next; + } + + [Serializable] + public class SerializableNode + { + SerializableNode next; + } + + + [XmlRoot("XmlSerializerPersonElement")] + public class XmlSerializerPerson + { + public XmlSerializerPerson(){} + [XmlAttribute] + public string Name; + [XmlAttribute] + public int Age; + } + + [XmlSchemaProvider("StaticGetSchema")] + public class XmlSerializerAdapter : IXmlSerializable + { + public XmlSchema GetSchema() + { + throw new NotImplementedException(); + } + + public void ReadXml(XmlReader reader) + { + throw new NotImplementedException(); + } + + public void WriteXml(XmlWriter writer) + { + throw new NotImplementedException(); + } + + static XmlQualifiedName StaticGetSchema(XmlSchemaSet schemaSet) + { + XmlReflectionImporter importer = new XmlReflectionImporter(); + XmlTypeMapping xmlTypeMapping = importer.ImportTypeMapping(typeof(T)); + XmlSchemas schemas = new XmlSchemas(); + XmlSchemaExporter exporter = new XmlSchemaExporter(schemas); + exporter.ExportTypeMapping(xmlTypeMapping); + schemas.Compile(new ValidationEventHandler (ValidationCallbackWithErrorCode), true); + for (int i = 0; i < schemas.Count; i++) + { + XmlSchema schema = schemas[i]; + schemaSet.Add(schema); + } + return new XmlQualifiedName(xmlTypeMapping.TypeName, xmlTypeMapping.Namespace); + } + + private static void ValidationCallbackWithErrorCode (object sender, ValidationEventArgs args) { + Console.WriteLine("Schema warning: " + args.Message); + } + } + } +} + diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/DataContractTypes.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/DataContractTypes.cs new file mode 100644 index 0000000000000..37c256f96a34d --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/DataContractTypes.cs @@ -0,0 +1,607 @@ +using System; +using System.Runtime.Serialization; +using System.Collections.Generic; + +[assembly:ContractNamespace("http://special1.tempuri.org", ClrNamespace= "SerializableTypes.XsdDataContractExporterTests.More")] + +#if UseSeparateAssemblyNamespace +namespace SerializableTypes.XsdDataContractExporterTests.More +#else +namespace System.Runtime.Serialization.Xml.XsdDataContractExporterTests.More +#endif +{ + [DataContract] + public class Foo + { + [DataMember] + int id; + } + + [KnownType(typeof(GenericBasePOCO>))] + [KnownType(typeof(GenericBasePOCO))] + [KnownType(typeof(SimpleBaseContainerPOCO))] + public class GenericContainerPOCO + { + public GenericBasePOCO2 GenericData; + public object TestGenericBasePOCO; + public GenericContainerPOCO() + { + } + } + + + public class GenericBasePOCO where T : new() + { + public object genericData = new T(); + } + + + public class GenericBasePOCO2 + where T : new() + where K : new() + { + public T genericData1 = new T(); + + public K genericData2 = new K(); + } + + [KnownType(typeof(SimpleBaseDerivedPOCO2))] + public class SimpleBaseContainerPOCO + { + public SimpleBasePOCO Base1; + + public List Base2; + + public SimpleBaseContainerPOCO() + { + } + } + + [KnownType(typeof(SimpleBaseDerivedPOCO))] + public class SimpleBasePOCO + { + public string BaseData = String.Empty; + } + + + public class SimpleBaseDerivedPOCO : SimpleBasePOCO + { + public string DerivedData = String.Empty; + } + + public class SimpleBaseDerivedPOCO2 : SimpleBasePOCO + { + public string DerivedData = String.Empty; + } + + [DataContract] + [KnownType(typeof(GenericBaseDC>))] + [KnownType(typeof(SimpleBaseContainerDC))] + public class GenericContainerDC + { + [DataMember] + public GenericBaseDC2 GenericData; + public GenericContainerDC() + { + } + } + + + [DataContract] + public class GenericBaseDC where T : new() + { + [DataMember] + public object genericData = new T(); + } + + + [DataContract] + public class GenericBaseDC2 + where T : new() + where K : new() + { + [DataMember] + public T genericData1 = new T(); + + [DataMember] + public K genericData2 = new K(); + } + + [DataContract] + [KnownType(typeof(SimpleBaseDerivedDC2))] + public class SimpleBaseContainerDC + { + [DataMember] + public SimpleBaseDC Base1; + + [DataMember] + public List Base2; + + public SimpleBaseContainerDC() + { } + } + + [DataContract] + [KnownType(typeof(SimpleBaseDerivedDC))] + public class SimpleBaseDC + { + [DataMember] + public string BaseData = String.Empty; + } + + + [DataContract] + public class SimpleBaseDerivedDC : SimpleBaseDC + { + [DataMember] + public string DerivedData = String.Empty; + } + + [DataContract] + public class SimpleBaseDerivedDC2 : SimpleBaseDC + { + [DataMember] + public string DerivedData = String.Empty; + } +} + +#if UseSeparateAssemblyNamespace +namespace SerializableTypes.XsdDataContractExporterTests +#else +namespace System.Runtime.Serialization.Xml.XsdDataContractExporterTests +#endif +{ + public class DataContractTypes + { + [DataContract] + public class Person1 + { + [DataMember] + public string name; + + [DataMember] + public int age; + + [DataMember] + float salary; + + Person1() + { + } + + public Person1(string init) + { + name = "John Anderson"; + age = 25; + salary = 100000; + } + } + + // Unknown data does not affect the data contract of the class + [DataContract(Name="DataContractTypes.Person1")] + public class Person2 : IExtensibleDataObject + { + public string firstName; + public string lastName; + + [DataMember(Name="name")] + internal string Name + { + get { return firstName + " " + lastName; } + private set + { + int splitIndex = value.IndexOf(' '); + firstName = value.Substring(0, splitIndex); + lastName = value.Substring(splitIndex+1); + } + } + + protected int personAge; + + [DataMember(Name="age")] + public virtual int Age + { + get { return personAge; } + set { personAge = value; } + } + + [DataMember] + internal float salary; + + protected Person2() + { + } + + public Person2(string init) + { + Name = "John Anderson"; + Age = 25; + salary = 100000; + } + + ExtensionDataObject extensionData; + public ExtensionDataObject ExtensionData + { + get { return extensionData; } + set { extensionData = value; } + } + } + + [DataContract(Name="PersonContract")] + internal class Person3 + { + [DataMember(Name="Name")] + public string name; + + [DataMember(Name="Nickname")] + public string name2; + + [DataMember(Name="Age")] + public int age; + + [DataMember(Name="Salary")] + float salary; + + [DataMember] + Address address; + + [DataMember] + public Address Address + { + get { return address; } + set { address = value; } + } + + public Person3() + { + name = "John Anderson"; + name2 = "Johny"; + age = 25; + salary = 100000; + Address = new Address(null); + } + } + + [DataContract(Name="Person")] + public struct Person4 + { + [DataMember] + public string name; + + [DataMember] + public int age; + + [DataMember] + float salary; + + [DataMember] + Address address; + + [DataMember] + DateTimeOffset hireDate; + + public Person4(StreamingContext context) + { + name = "John Anderson"; + age = 25; + salary = 100000; + address = new Address(null); + hireDate = new DateTimeOffset(new DateTime(1995, 01, 17, 5, 30, 0), new TimeSpan(1,15,120)); + } + } + + [DataContract(Name="Address")] + public class Address + { + [DataMember(IsRequired=true)] + public string street; + + string city; + + [DataMember(Name = "city", IsRequired = true)] + public string City + { + get { return city; } + set { city = value; } + } + + [DataMember(IsRequired=true)] + string state; + + int zip; + + [DataMember(Name = "zip", IsRequired = true)] + int Zip + { + get { return zip; } + set {zip = value; } + } + + public Address() + { + } + + public Address(string init) + { + street = "One FooBar Avenue"; + City = "BazTown"; + state = "WA"; + Zip = 66066; + } + } + + [DataContract(Name="Address", Namespace="http://schemas.datacontract.org/2004/07/schemaexport.suites")] + public struct Address2 + { + [DataMember] + public string street; + + [DataMember] + string city; + + string state; + + [DataMember(Name="state")] + public string State + { + get { return state; } + set { state = value; } + } + + [DataMember] + int zip; + + public Address2(string init) + { + street = "One FooBar Avenue"; + city = "BazTown"; + state = "WA"; + zip = 66066; + } + } + + [DataContract(Namespace="http://invalid.org?query")] + public class Child : Person2 + { + [DataMember(Name="age")] + public override int Age + { + get { return personAge; } + set + { + if (personAge > 18) + throw new Exception("Children must be aged 18 or younger"); + personAge = value; + } + } + + [DataMember] + Person2 mother; + [DataMember] + Person2 father; + + Child(StreamingContext context) + { + } + + public Child(string init) : base(init) + { + personAge = 13; + mother = new Person2(null); + father = null; + } + } + + [DataContract(Name="DerivedAddress")] + public class DerivedAddress : Address + { + [DataMember] + string email; + + [DataMember] + string phone; + + public DerivedAddress() : base(null) + { + email = "neo@zion.net"; + phone = "222-111-2222"; + } + } + + [DataContract(Name="Node")] + class Node + { + [DataMember] + Node nextNode; + + [DataMember] + Node previousNode; + + Node() + { + } + } + + [DataContract(Name="Node")] + class Node2 + { + [DataMember] + Node2 nextNode; + + [DataMember] + Node3 previousNode; + + Node2() + { + } + } + + [DataContract(Name="Node")] + class Node3 + { + [DataMember] + Node3 nextNode; + + [DataMember] + Node4 previousNode; + + Node3() + { + } + } + + [DataContract(Name="Node")] + class Node4 + { + [DataMember] + Node3 nextNode; + + [DataMember] + Node2 previousNode; + + Node4() + { + } + } + + [DataContract] + class A + { + [DataMember] + B member; + + A() + { + } + } + + [DataContract] + class B + { + [DataMember] + A member; + + B() + { + } + } + + [DataContract] + public class ClassWithInterfaceMember + { + [DataMember] + ISampleInterface interfaceMember; + } + + interface ISampleInterface + { + void InterfaceMethod(); + } + + [DataContract(Name="DerivedAddress2")] + public class DerivedAddress2 : DerivedAddress + { + [DataMember] + byte[] extraData; + + public DerivedAddress2() : base() + { + } + } + + [DataContract] + public class Foo + { + [DataMember(IsRequired=false)] + int i=1; + [DataMember(IsRequired=true)] + int j=3; + [DataMember(Order=3)] + string a = "a"; + [DataMember(Order=4, IsRequired=false)] + public int z = 32; + + } + + [DataContract] + public class Bar + { + [DataMember] + int i=1; + [DataMember(Order=4, IsRequired=true)] + int j=3; + [DataMember(Order=5)] + string a = "a"; + [DataMember(Order=8)] + public int z = 32; + + } + + [DataContract] + [Serializable] + public class MixedDCSerializable + { + int serializableInt = 0; + [DataMember] + int dataContractInt = 0; + } + + [Serializable] + public class SerializableOnly : MixedDCSerializable + { + string serializableString; + [NonSerialized] + int nonSerializedInt; + } + + [DataContract] + [Serializable] + public class DerivedMixedDCSerializable : SerializableOnly + { + public float serializableFloat = 0.0F; + [DataMember] + public float dataContractFloat = 0.0F; + } + + [Serializable] + public class AllPrimitives + { + public object objectMember; + public char charMember; + public bool boolMember; + public byte unsignedByteMember; + //[CLSCompliant(false)] + public sbyte byteMember; + public short shortMember; + //[CLSCompliant(false)] + public ushort unsignedShortMember; + public int intMember; + //[CLSCompliant(false)] + public uint unsignedIntMember; + public long longMember; + //[CLSCompliant(false)] + public ulong unsignedLongMember; + public float floatMember; + public double doubleMember; + public decimal decimalMember; + public DateTime dateTimeMember; + public string stringMember; + byte[] byteArrayMember; + public Guid guidMember; + public TimeSpan timeSpanMember; + public Uri uri; + } + + [DataContract] + public class AllSpecialTypes + { + [DataMember] System.Enum enumMember; + [DataMember] System.ValueType valueTypeMember; + [DataMember] System.Array arrayMember; + } + + } +} + + + diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/Enums.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/Enums.cs new file mode 100644 index 0000000000000..4d22f65ba8325 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/Enums.cs @@ -0,0 +1,138 @@ +using System; +using System.Runtime.Serialization; + +#if UseSeparateAssemblyNamespace +namespace SerializableTypes.XsdDataContractExporterTests +#else +namespace System.Runtime.Serialization.Xml.XsdDataContractExporterTests +#endif +{ + public class Enums + { + public enum Mode + { + NotSpecified, + Single, + Multiple, + } + + [DataContract(Name="DifferentMode")] + public enum Mode2 + { + [EnumMember(Value="None")] + NotSpecified = -1, + Single, + [EnumMember] + Multiple, + } + + public enum Color : byte + { + Red, + Green, + Blue, + Reserved, + } + + //[CLSCompliant(false)] + public enum ULongRange : ulong + { + Min = UInt64.MinValue, + Small = 1, + Medium = 10, + Large = 100, + Max = UInt64.MaxValue, + } + + [Flags] + public enum FlagsEnum + { + Foo = 1, + Bar = 2, + Baz = 4, + Bazooka = 8 + } + + [Flags] + [DataContract(Namespace="http://special2.tempuri.org")] + public enum LongRange : long + { + [EnumMember] + Min = Int64.MinValue, + [EnumMember(Value="Small")] + Value1 = 1L, + Value10 = 10L, + [EnumMember(Value="Medium")] + Value100 = 100L, + [EnumMember(Value="Large")] + Value1000 = 1000L, + [EnumMember] + Max = Int64.MaxValue, + } + + [DataContract] + public class EnumContainer + { + [DataMember] + Mode mode; + + [DataMember] + Mode2 mode2; + + [DataMember] + Color color; + + [DataMember] + ULongRange enumValue; + + [DataMember] + FlagsEnum flagsEnum; + + [DataMember] + LongRange longFlagsEnum; + + public EnumContainer() + { + } + + [DataContract] + public class NestedEnumContainer + { + [DataMember] + Mode mode; + + NestedEnumContainer() + { + } + } + + internal enum NestedSimpleEnum + { + Negative = -1, + NoComment = 0, + Affirmative = 1, + } + } + } + + public enum Mode + { + NotSpecified, + Single, + Multiple, + } + + [DataContract(Name="Mode")] + public enum DifferentMode + { + [EnumMember(Value="NotSpecified")] + Member1, + [EnumMember] + Single=1, + [EnumMember(Value="Multiple")] + Mult, + } + +} + + diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/GenericTypes.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/GenericTypes.cs new file mode 100644 index 0000000000000..01b0e7f76394d --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/GenericTypes.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; +using System.Security; + +#if UseSeparateAssemblyNamespace +namespace SerializableTypes.XsdDataContractExporterTests +#else +namespace System.Runtime.Serialization.Xml.XsdDataContractExporterTests +#endif +{ + [Serializable] + internal class DateTimeOffsetGeneric + { + T single; + T[] array; + List list; + Dictionary dictionary; + } + + [Serializable] + internal class Foo where Q : new() + { + Q single; + Q[] array; + List list; + Dictionary dictionary; + } + + [DataContract(Name = "PairOf{0}and{1}")] + internal struct Pair + { + [DataMember] + T1 t1; + [DataMember] + T2 t2; + } + + [KnownType(typeof(Pair>, Foo>))] + [Serializable] + public class Bar + { + Foo fooBar; + XsdType xsdFloat; + XsdType xsdDecimal; + WrapperISerializable wrappedInt; + WrapperISerializable wrappedIntArray; + DateTimeOffsetGeneric genericDateTimeOffset; + DateTimeOffsetGeneric genericDateTimeOffsetArray; + } + + [Serializable] + internal class WrapperISerializable : ISerializable + { + [SecurityCritical] + public void GetObjectData(SerializationInfo info, StreamingContext context) { } + } + + [XmlSchemaProvider("StaticGetSchema")] + public class XsdType : IXmlSerializable + { + static XmlSchemaType StaticGetSchema(XmlSchemaSet schemas) + { + const string ns = "http://GenericXmlSerializableNs"; + XmlSchema schema = new XmlSchema(); + schema.TargetNamespace = ns; + schema.Namespaces.Add("tns", ns); + schemas.Add(schema); + + XmlSchemaComplexType schemaType = new XmlSchemaComplexType(); + schemaType.Name = typeof(T).Name + "Wrapper"; + XmlSchemaSequence sequence = new XmlSchemaSequence(); + schemaType.Particle = sequence; + XmlSchemaElement element = new XmlSchemaElement(); + element.Name = "MyElement"; + if (typeof(T) == typeof(decimal)) + element.SchemaTypeName = new XmlQualifiedName("decimal", XmlSchema.Namespace); + else if (typeof(T) == typeof(float)) + element.SchemaTypeName = new XmlQualifiedName("float", XmlSchema.Namespace); + else + element.SchemaTypeName = new XmlQualifiedName("anyType", XmlSchema.Namespace); + sequence.Items.Add(element); + schema.Items.Add(schemaType); + schemas.Add(schema); + return schemaType; + } + + public XmlSchema GetSchema() { throw new NotImplementedException(); } + public void ReadXml(XmlReader reader) { throw new NotImplementedException(); } + public void WriteXml(XmlWriter writer) { throw new NotImplementedException(); } + } + +} + diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/ISerializableTypes.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/ISerializableTypes.cs new file mode 100644 index 0000000000000..e4e667cfb1954 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/ISerializableTypes.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections; +using System.Runtime.Serialization; +using System.Security; + +#if UseSeparateAssemblyNamespace +namespace SerializableTypes.XsdDataContractExporterTests +#else +namespace System.Runtime.Serialization.Xml.XsdDataContractExporterTests +#endif +{ + [Serializable] + public class BaseISerializable : ISerializable + { + protected BaseISerializable() + { + } + + protected BaseISerializable(SerializationInfo info, StreamingContext context) + { + } + + public string street; + int zip; + [NonSerialized] + float privateData; + + [SecurityCritical] + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + } + } + + [Serializable] + public class DerivedISerializable : BaseISerializable + { + DerivedISerializable(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + } + + [Serializable] + public class MyUri : Uri + { + protected MyUri(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } + + [Serializable] + public class MyDerivedUri : MyUri + { + protected MyDerivedUri(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } + + [Serializable] + public struct StructISerializable : ISerializable + { + public StructISerializable(SerializationInfo serInfo, StreamingContext context) + { + } + + [SecurityCritical] + public void GetObjectData(SerializationInfo serInfo, StreamingContext context) + { + } + + } + + [DataContract] + public class UseISerializable + { + [DataMember] + Hashtable hashtable; + + [DataMember] + InvalidOperationException exception; + +#if !HideTypesWithoutSerializableAttribute + [DataMember] + System.Reflection.Assembly assembly; + + [DataMember] + System.IO.DirectoryInfo directoryInfo; +#endif + [DataMember] + StructISerializable structISerMember; + + [DataMember] + BaseISerializable classISerMember; + } + + [Serializable] + public class ISerializableDerivingDC : DataContractTypes.Address, ISerializable + { + public ISerializableDerivingDC(SerializationInfo serInfo, StreamingContext context) + { + } + + [SecurityCritical] + void ISerializable.GetObjectData(SerializationInfo serInfo, StreamingContext context) + { + } + } + +} + diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/IXmlSerializableTypes.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/IXmlSerializableTypes.cs new file mode 100644 index 0000000000000..e42d9fb96407f --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/IXmlSerializableTypes.cs @@ -0,0 +1,399 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using System.Data.SqlTypes; +using System.Runtime.Serialization; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; + +#if UseSeparateAssemblyNamespace +namespace SerializableTypes.XsdDataContractExporterTests +#else +namespace System.Runtime.Serialization.Xml.XsdDataContractExporterTests +#endif +{ + public class XmlSerializableBase : IXmlSerializable + { + public XmlSchema GetSchema() + { + return null; + } + + public void ReadXml(XmlReader reader) + { + throw new NotImplementedException(); + } + + public void WriteXml(XmlWriter writer) + { + throw new NotImplementedException(); + } + + public static XmlSchema GetSchema(string ns, XmlSchemaSet schemas) + { + if (ns == null) + { + ns = String.Empty; + } + + ICollection currentSchemas = schemas.Schemas(); + foreach (XmlSchema schema in currentSchemas) + { + if ((schema.TargetNamespace == null && ns.Length == 0) || ns.Equals(schema.TargetNamespace)) + return schema; + } + if (ns.Length > 0) + { + XmlSchema newSchema = new XmlSchema(); + newSchema.TargetNamespace = ns; + newSchema.Namespaces.Add("tns", ns); + schemas.Add(newSchema); + return newSchema; + } + return null; + } + } + + [XmlSchemaProvider("StaticGetSchema")] + [XmlRoot(ElementName ="ComplexTypeElement", Namespace ="http://ElementNs/", IsNullable = false)] + public class ComplexType : XmlSerializableBase + { + static XmlSchemaType StaticGetSchema(XmlSchemaSet schemas) + { + XmlSchema schema = GetSchema("http://TypeNs/", schemas); + XmlSchemaComplexType schemaType = new XmlSchemaComplexType(); + schemaType.Name = "MyComplexType"; + XmlSchemaSequence sequence = new XmlSchemaSequence(); + schemaType.Particle = sequence; + XmlSchemaElement element = new XmlSchemaElement(); + element.Name = "MyElement"; + element.SchemaTypeName = new XmlQualifiedName("int", XmlSchema.Namespace); + sequence.Items.Add(element); + schema.Items.Add(schemaType); + schemas.Add(schema); + return schemaType; + } + } + + [XmlSchemaProvider("StaticGetSchema")] + public class SimpleType : XmlSerializableBase + { + static XmlQualifiedName StaticGetSchema(XmlSchemaSet schemas) + { + XmlSchema schema = GetSchema("http://TypeNs/", schemas); + XmlSchemaSimpleType schemaType = new XmlSchemaSimpleType(); + schemaType.Name = "MySimpleType"; + XmlSchemaSimpleTypeRestriction content = new XmlSchemaSimpleTypeRestriction(); + schemaType.Content = content; + content.BaseType = XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.Boolean); + schema.Items.Add(schemaType); + schemas.Add(schema); + return new XmlQualifiedName(schemaType.Name, schema.TargetNamespace); + } + } + + [XmlSchemaProvider("StaticGetSchema")] + [XmlRoot(ElementName ="IntElement", Namespace ="http://ElementNs/", IsNullable = false)] + public struct XsdInt : IXmlSerializable + { + static XmlQualifiedName StaticGetSchema(XmlSchemaSet schemas) + { + XmlSchemaType schemaType = XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.Int); + return schemaType.QualifiedName; + } + + public XmlSchema GetSchema() + { + throw new NotImplementedException(); + } + + public void ReadXml(XmlReader reader) + { + throw new NotImplementedException(); + } + + public void WriteXml(XmlWriter writer) + { + throw new NotImplementedException(); + } + } + + [XmlSchemaProvider("StaticGetSchema")] + [XmlRoot(ElementName ="StringElement", Namespace ="http://ElementNs/", IsNullable = true)] + public class XsdString : IXmlSerializable + { + static XmlQualifiedName StaticGetSchema(XmlSchemaSet schemas) + { + XmlSchemaType schemaType = XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.String); + return schemaType.QualifiedName; + } + + public XmlSchema GetSchema() + { + throw new NotImplementedException(); + } + + public void ReadXml(XmlReader reader) + { + throw new NotImplementedException(); + } + + public void WriteXml(XmlWriter writer) + { + throw new NotImplementedException(); + } + } + + [XmlSchemaProvider("StaticGetSchema")] + [XmlRoot(ElementName="ComplexStructElement", Namespace="http://ElementNs/", IsNullable = false)] + public struct ComplexStruct : IXmlSerializable + { + static XmlSchemaType StaticGetSchema(XmlSchemaSet schemas) + { + XmlSchema schema = XmlSerializableBase.GetSchema("http://TypeNs/", schemas); + XmlSchemaComplexType schemaType = new XmlSchemaComplexType(); + schemaType.Name = "MyComplexStruct"; + XmlSchemaSequence sequence = new XmlSchemaSequence(); + schemaType.Particle = sequence; + XmlSchemaElement element = new XmlSchemaElement(); + element.Name = "MyElement"; + element.SchemaTypeName = new XmlQualifiedName("int", XmlSchema.Namespace); + sequence.Items.Add(element); + schema.Items.Add(schemaType); + schemas.Add(schema); + return schemaType; + } + + public XmlSchema GetSchema() + { + throw new NotImplementedException(); + } + + public void ReadXml(XmlReader reader) + { + throw new NotImplementedException(); + } + + public void WriteXml(XmlWriter writer) + { + throw new NotImplementedException(); + } + } + + [XmlSchemaProvider("StaticGetSchema")] + [XmlRoot(ElementName ="AnonElement", Namespace ="http://ElementNs/", IsNullable = true)] + public class AnonymousType : XmlSerializableBase + { + static XmlSchemaType StaticGetSchema(XmlSchemaSet schemas) + { + XmlSchemaComplexType schemaType = new XmlSchemaComplexType(); + XmlSchemaSequence sequence = new XmlSchemaSequence(); + schemaType.Particle = sequence; + XmlSchemaElement element = new XmlSchemaElement(); + element.Name = "MyElement"; + element.SchemaTypeName = new XmlQualifiedName("int", XmlSchema.Namespace); + sequence.Items.Add(element); + return schemaType; + } + } + + public class NoSchema : XmlSerializableBase + { + } + + [XmlRoot] + public class EmptyXmlRoot : XmlSerializableBase + { + } + + [XmlRoot(IsNullable=true)] + public class NullableOnlyXmlRoot : XmlSerializableBase + { + } + + [XmlRoot(ElementName=null)] + public class NullElementXmlRoot : XmlSerializableBase + { + } + + [XmlRoot(ElementName="")] + public class EmptyElementXmlRoot : XmlSerializableBase + { + } + + [XmlSchemaProvider(null, IsAny=true)] + public class AnyBasic : XmlSerializableBase + { + } + + [XmlSchemaProvider("StaticGetSchema", IsAny = true)] + public class AnyWithSchemaTypeMethod : XmlSerializableBase + { + static XmlSchemaType StaticGetSchema(XmlSchemaSet schemas) + { + return null; + } + } + + [XmlSchemaProvider("StaticGetSchema", IsAny = true)] + public class AnyWithQnameMethod : XmlSerializableBase + { + static XmlQualifiedName StaticGetSchema(XmlSchemaSet schemas) + { + return null; + } + } + + [XmlSchemaProvider("StaticGetSchema")] + public class AnyImplicitWithSchemaTypeMethod : XmlSerializableBase + { + static XmlSchemaType StaticGetSchema(XmlSchemaSet schemas) + { + return null; + } + } + + [XmlSchemaProvider("StaticGetSchema")] + public class AnyImplicitWithQnameMethod : XmlSerializableBase + { + static XmlQualifiedName StaticGetSchema(XmlSchemaSet schemas) + { + return null; + } + } + + public class NoSchemaProviderWithSchema : IXmlSerializable + { + public XmlSchema GetSchema() + { + XmlSchema schema = new XmlSchema(); + schema.Id = this.GetType().Name; + XmlSchemaElement element = new XmlSchemaElement(); + element.Name = "userElement"; + element.SchemaTypeName = new XmlQualifiedName("int", XmlSchema.Namespace); + schema.Items.Add(element); + return schema; + } + + public void ReadXml(XmlReader reader) + { + throw new NotImplementedException(); + } + + public void WriteXml(XmlWriter writer) + { + throw new NotImplementedException(); + } + } + + [XmlSchemaProvider("GetTypedDataSetSchema")] + [XmlRoot("TypedDataSet", Namespace = "http://datasetns/")] + public class TypedDataSet : DataSet + { + public static System.Xml.Schema.XmlSchemaComplexType GetTypedDataSetSchema(System.Xml.Schema.XmlSchemaSet xs) + { + TypedDataSet ds = new TypedDataSet(); + System.Xml.Schema.XmlSchemaComplexType type = new System.Xml.Schema.XmlSchemaComplexType(); + System.Xml.Schema.XmlSchemaSequence sequence = new System.Xml.Schema.XmlSchemaSequence(); + xs.Add(ds.GetSchemaSerializable()); + if (PublishLegacyWSDL()) + { + System.Xml.Schema.XmlSchemaAny any = new System.Xml.Schema.XmlSchemaAny(); + any.Namespace = ds.Namespace; + sequence.Items.Add(any); + } + else + { + System.Xml.Schema.XmlSchemaAny any1 = new System.Xml.Schema.XmlSchemaAny(); + any1.Namespace = "http://www.w3.org/2001/XMLSchema"; + any1.MinOccurs = new System.Decimal(0); + any1.ProcessContents = System.Xml.Schema.XmlSchemaContentProcessing.Lax; + sequence.Items.Add(any1); + System.Xml.Schema.XmlSchemaAny any2 = new System.Xml.Schema.XmlSchemaAny(); + any2.Namespace = "urn:schemas-microsoft-com:xml-diffgram-v1"; + any2.MinOccurs = new System.Decimal(0); + any2.ProcessContents = System.Xml.Schema.XmlSchemaContentProcessing.Lax; + sequence.Items.Add(any2); + sequence.MaxOccurs = System.Decimal.MaxValue; + System.Xml.Schema.XmlSchemaAttribute attribute = new System.Xml.Schema.XmlSchemaAttribute(); + attribute.Name = "namespace"; + attribute.FixedValue = ds.Namespace; + type.Attributes.Add(attribute); + } + type.Particle = sequence; + return type; + } + protected override System.Xml.Schema.XmlSchema GetSchemaSerializable() + { + System.IO.MemoryStream stream = new System.IO.MemoryStream(); + this.WriteXmlSchema(new System.Xml.XmlTextWriter(stream, null)); + stream.Position = 0; + return System.Xml.Schema.XmlSchema.Read(new System.Xml.XmlTextReader(stream), null); + } + protected static bool PublishLegacyWSDL() + { + //System.Collections.Specialized.NameValueCollection settings = ((System.Collections.Specialized.NameValueCollection)(System.Configuration.ConfigurationManager.GetSection("system.data.dataset"))); + //if ((settings != null)) + //{ + // string[] values = settings.GetValues("WSDL_VERSION"); + // if ((values != null)) + // { + // System.Single version = System.Single.Parse(((string)(values[0])), ((System.IFormatProvider)(null))); + // return(version < 2); + // } + //} + return true; + } + } + + [Serializable] + public class IXmlSerializablesContainer + { + ComplexType complexType; + ComplexStruct complexStruct; + SimpleType simpleType; + AnonymousType anonymousType; + NoSchema noSchema; + XsdInt xsdInt; + XsdString xsdString; + DataSet dataSet; + TypedDataSet typedDataSet; + AnyBasic anyBasic; + AnyBasic[] anyArray; + AnyWithSchemaTypeMethod anyWithSchemaType; + AnyWithQnameMethod anyWithQname; + AnyImplicitWithSchemaTypeMethod anyImplicitWithSchemaType; + AnyImplicitWithQnameMethod anyImplicitWithQname; + NoSchemaProviderWithSchema noSchemaProviderWithSchema; + XmlElement xmlElement; + XmlElement[] xmlElementArray; + XmlNode[] xmlNodes; + XmlNode[][] xmlNodesArray; + Dictionary xmlElementDictionary; + } + + [Serializable] + public class SqlTypeContainer + { + // The following were disabled in NetFx test... but should work now. + // SqlBinary, SqlChars, SqlInt32, SqlString, SqlDateTime, SqlGuid + + public SqlBinary sqlBinary = new SqlBinary(new byte[]{4,2}); + public SqlByte sqlByte = new SqlByte(4); + public SqlBytes sqlBytes = new SqlBytes(new byte[]{4,2}); + public SqlChars sqlChars = new SqlChars(new char[]{'4', '2'}); + public SqlDecimal sqlDecimal = new SqlDecimal(4.2); + public SqlDouble sqlDouble = new SqlDouble(4.2); + public SqlInt16 sqlInt16 = new SqlInt16(42); + public SqlInt32 sqlInt32 = new SqlInt32(42); + public SqlInt64 sqlInt64 = new SqlInt64(42L); + public SqlMoney sqlMoney = new SqlMoney(42); + public SqlSingle sqlSingle = new SqlSingle(4.2); + public SqlString sqlString = new SqlString("MySqlString"); + public SqlDateTime sqlDateTime = new SqlDateTime(); + public SqlGuid sqlGuid = new SqlGuid(); + } +} + diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/LegacyTypes.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/LegacyTypes.cs new file mode 100644 index 0000000000000..332cb876f6639 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/LegacyTypes.cs @@ -0,0 +1,42 @@ +using System; +using System.Xml; +using System.Collections; +using System.Collections.Generic; +using System.Security; +using System.Runtime.Serialization; + +#if UseSeparateAssemblyNamespace +namespace SerializableTypes.XsdDataContractExporterTests +#else +namespace System.Runtime.Serialization.Xml.XsdDataContractExporterTests +#endif +{ + [Serializable] + [SecuritySafeCritical] +#if UseSeparateAssemblyNamespace + public unsafe class LegacyTypes +#else + public class LegacyTypes +#endif + { + Hashtable h; + List lInt; + public IList list; + public IList stringList; + public ICollection collection; + public ICollection stringCollection; + public IEnumerable enumerable; + public IEnumerable stringEnumerable; + public IDictionary dictionary; + public IDictionary dictionaryOfStringToInt; + Dictionary dExVer; +#if !HideTypesWithoutSerializableAttribute + float* f; +#endif + IntPtr iPtr; + DBNull dbNull; + } + +} + + diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/NullableTypes.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/NullableTypes.cs new file mode 100644 index 0000000000000..109ab772167b2 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/NullableTypes.cs @@ -0,0 +1,66 @@ +using System; +using System.Runtime.Serialization; +using System.Security; + +#if UseSeparateAssemblyNamespace +namespace SerializableTypes.XsdDataContractExporterTests +#else +namespace System.Runtime.Serialization.Xml.XsdDataContractExporterTests +#endif +{ + [DataContract] + public struct Point + { + + Nullable x; + Nullable y; + + [DataMember] + public Nullable X { get { return x; } set { x = value; } } + [DataMember] + public Nullable Y { get { return y; } set { y = value; } } + + } + + [DataContract] + public struct Rectangle + { + [DataMember] + public Nullable TopLeft; + [DataMember] + public Point? BottomRight; + } + + [Serializable] + [KnownType(typeof(Point))] + public struct Polygon : ISerializable + { + Nullable[] points; + + [SecurityCritical] + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + } + } + + [Serializable] + [KnownType(typeof(Polygon))] + [KnownType(typeof(Nullable))] + [KnownType(typeof(Container))] + public class Container + { + Polygon polygon; + Rectangle? excessivelyNullableRectangle; //not excessively anymore + Nullable[] nullableInts; + Nullable[][] nullableLongss; + } + + [DataContract] + public struct NullableDateTimeOffset + { + Nullable nullableDTO; + + [DataMember] + public Nullable NullableDTO { get { return nullableDTO; } set { nullableDTO = value; } } + } +} diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/PartialTrust.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/PartialTrust.cs new file mode 100644 index 0000000000000..596176da62008 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/PartialTrust.cs @@ -0,0 +1,110 @@ +using System; +using System.Runtime.Serialization; +using System.Security; +using System.Security.Permissions; +using System.Xml; +using System.Xml.Serialization; +using System.Xml.Schema; + +[assembly:AllowPartiallyTrustedCallers] +#if UseSeparateAssemblyNamespace +namespace SerializableTypes.XsdDataContractExporterTests +#else +namespace System.Runtime.Serialization.Xml.XsdDataContractExporterTests +#endif +{ + public class PartialTrust + { + [Serializable] + //[SerializationPermissionNotRequired] + public class SafePoint + { + int x = 42, y = 43; + } + + [Serializable] + //[SerializationPermissionNotRequired] + public class SafePoint3D : SafePoint + { + int z = 44; + DateTimeOffset dateCreated = new DateTimeOffset(new DateTime(1997, 03, 11, 07, 15, 30), new TimeSpan(1,2,60)); + } + + [Serializable] + //[SerializationPermissionNotRequired] + public class SafeCube + { + SafePoint3D topLeftBehind = new SafePoint3D(); + SafePoint3D bottomRightFront = new SafePoint3D(); + } + + [Serializable] + public class UnsafePoint + { + int x = 42, y = 43; + } + + [Serializable] + //[SerializationPermissionNotRequired] + public class UnsafePoint3D : UnsafePoint + { + int z = 44; + } + + [Serializable] + //[SerializationPermissionNotRequired] + public class UnsafeCube + { + UnsafePoint3D topLeftBehind = new UnsafePoint3D(); + UnsafePoint3D bottomRightFront = new UnsafePoint3D(); + } + + //[SerializationPermissionNotRequired] + public class AttributeOnlyIXmlSerializable : IXmlSerializable + { + public AttributeOnlyIXmlSerializable() + { + // This was not commented in NetFx. It clutters output though and seems unneccesary for our needs. + //Console.WriteLine("Default Ctor"); + } + + public AttributeOnlyIXmlSerializable(string init) + { + + } + + public XmlSchema GetSchema() + { + return null; + } + + public void ReadXml(XmlReader reader) + { + Console.WriteLine(reader.NodeType + " " + reader.Name); + Console.WriteLine("Value1 = " + reader.GetAttribute("myAttribute1")); + Console.WriteLine("Value2 = " + reader.GetAttribute("myAttribute2")); + } + + public void WriteXml(XmlWriter writer) + { + writer.WriteAttributeString("myAttribute1", "", "myAttribute1Value"); + writer.WriteAttributeString("myAttribute2", "", "myAttribute2Value"); + } + } + + public class UnsafeAttributeOnlyIXmlSerializable : AttributeOnlyIXmlSerializable + { + public UnsafeAttributeOnlyIXmlSerializable() + { + //may be called to invoke GetSchema() method + } + + public UnsafeAttributeOnlyIXmlSerializable(string init) + { + + } + + } + } +} + diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/SerializableTypes.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/SerializableTypes.cs new file mode 100644 index 0000000000000..87fc463c59c8c --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/SerializableTypes.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections; +using System.Runtime.Serialization; + +#if UseSeparateAssemblyNamespace +namespace SerializableTypes.XsdDataContractExporterTests +#else +namespace System.Runtime.Serialization.Xml.XsdDataContractExporterTests +#endif +{ + [Serializable] + public class Address + { + public string street; + string city; + string state; + int zip; + + [NonSerialized] + float privateData; + + public string Apartment + { + get { return null; } + set { } + } + + public Address() + { + } + } + + [Serializable] + public struct Address2 + { + public string street; + string city; + string state; + int zip; + + [NonSerialized] + float privateData; + + } + + [Serializable] + public class Employee //: DataContractTypes.Person2 + { + ArrayTypes.Company company; + + Employee(StreamingContext context) + { + } + } + + [Serializable] + [KnownType(typeof(ArrayList))] + [KnownType(typeof(int))] + [KnownType(typeof(DateTime))] + [KnownType(typeof(Employee))] + [KnownType(typeof(ObjectContainer))] + public class ObjectContainer + { + object obj; + } + +} diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/SerializationTypes.csproj b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/SerializationTypes.csproj new file mode 100644 index 0000000000000..440b641b2ac93 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SerializationTypes/SerializationTypes.csproj @@ -0,0 +1,21 @@ + + + + netstandard2.1 + true + UseSeparateAssemblyNamespace;HideTypesWithoutSerializableAttribute + $(NoWarn);169;414 + + + + + all + + + + + + + + diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SurrogateTests.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SurrogateTests.cs new file mode 100644 index 0000000000000..7a2c32aa527d9 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/SurrogateTests.cs @@ -0,0 +1,525 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Reflection; +using System.Runtime.Serialization; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Serialization; +using Xunit; +using Xunit.Abstractions; + + +namespace System.Runtime.Serialization.Xml.XsdDataContractExporterTests +{ + public class SurrogateTests + { + private readonly ITestOutputHelper _output; + public SurrogateTests(ITestOutputHelper output) + { + _output = output; + } + + [Theory] + [MemberData(nameof(SurrogateProvider_MemberData))] + public void SurrogateProvider(Type type, ISerializationSurrogateProvider surrogate, Action schemaCheck = null) + { + ExportOptions options = new ExportOptions() { DataContractSurrogate = surrogate }; + XsdDataContractExporter exporter = new XsdDataContractExporter() { Options = options }; + + exporter.Export(type); + string schema = SchemaUtils.DumpSchema(exporter.Schemas); + _output.WriteLine(schema); + + if (schemaCheck != null) + schemaCheck(schema, exporter.Schemas); + } + public static IEnumerable SurrogateProvider_MemberData() + { + yield return new object[] { typeof(SurrogateTests.CircleContainer), new NodeToSerializableNode(new CircleToSquare(new XmlSerializerToXmlFormatter(null))), (string s, XmlSchemaSet ss) => { + SchemaUtils.OrderedContains(@"", ref s); + + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"Property", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"Field", ref s); + SchemaUtils.OrderedContains(@"", ref s); + + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"0", ref s); + SchemaUtils.OrderedContains(@"7", ref s); + SchemaUtils.OrderedContains(@"0", ref s); + SchemaUtils.OrderedContains(@"0", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"Field", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + } }; + yield return new object[] { typeof(SurrogateTests.Node), new NodeToSerializableNode(new CircleToSquare(new XmlSerializerToXmlFormatter(null))), (string s, XmlSchemaSet ss) => { + SchemaUtils.OrderedContains(@"", ref s); + + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"0", ref s); + SchemaUtils.OrderedContains(@"7", ref s); + SchemaUtils.OrderedContains(@"0", ref s); + SchemaUtils.OrderedContains(@"0", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"Field", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + } }; + yield return new object[] { typeof(SurrogateTests.XmlSerializerPerson), new NodeToSerializableNode(new CircleToSquare(new XmlSerializerToXmlFormatter(null))), (string s, XmlSchemaSet ss) => { + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"XmlSerializable", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + } }; + yield return new object[] { typeof(SurrogateTests.ValidSurrogateTest), new PersonSurrogate(), (string s, XmlSchemaSet ss) => { + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + } }; + yield return new object[] { typeof(SurrogateTests.ValidSurrogateTestDC), new PersonSurrogate(), (string s, XmlSchemaSet ss) => { + SchemaUtils.OrderedContains(@"", ref s); + + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + SchemaUtils.OrderedContains(@"", ref s); + } }; + } + + [Theory] + [MemberData(nameof(SurrogateProvider_Negative_MemberData))] + public void SurrogateProvider_Negative(Type badType, ISerializationSurrogateProvider surrogate, Type exceptionType, string exMsg = null) + { + XsdDataContractExporter exporter = new XsdDataContractExporter(); + exporter.Options = new ExportOptions(); + exporter.Options.DataContractSurrogate = surrogate; + + var ex = Assert.Throws(exceptionType, () => exporter.Export(badType)); + if (exMsg != null) + Assert.Equal(exMsg, ex.Message); + } + public static IEnumerable SurrogateProvider_Negative_MemberData() + { + yield return new object[] { typeof(SurrogateTests.InvalidSurrogateTest), new CollectionASurrogate(), typeof(InvalidDataContractException) }; + yield return new object[] { typeof(SurrogateTests.InvalidSurrogateTestDC), new CollectionASurrogate(), typeof(InvalidDataContractException) }; + } + + #region SurrogateProviders + public class CircleToSquare : ISerializationSurrogateProvider2 + { + ISerializationSurrogateProvider2? _nextSurrogate; + public CircleToSquare(ISerializationSurrogateProvider2? nextSurrogate) + { + this._nextSurrogate = nextSurrogate; + } + + public Type GetSurrogateType(Type type) + { + if (type == typeof(SurrogateTests.Circle)) + return typeof(SurrogateTests.Square); + return (_nextSurrogate != null) ? _nextSurrogate.GetSurrogateType(type) : type; + } + + public object GetCustomDataToExport(Type clrType, Type dcType) + { + if (clrType == typeof(SurrogateTests.Circle) && dcType == typeof(SurrogateTests.Square)) + return clrType.Assembly.GetName().Version; + return (_nextSurrogate != null) ? _nextSurrogate.GetCustomDataToExport(clrType, dcType) : null; + } + + public object GetCustomDataToExport(MemberInfo memberInfo, Type dcType) => memberInfo.MemberType.ToString(); + public void GetKnownCustomDataTypes(Collection knownTypes) { } + public object GetObjectToSerialize(object obj, Type memberType) => throw new NotImplementedException(); + public object GetDeserializedObject(object obj, Type memberType) => throw new NotImplementedException(); + public Type GetReferencedTypeOnImport(string name, string ns, object customData) => null; + } + + public class NodeToSerializableNode : ISerializationSurrogateProvider2 + { + ISerializationSurrogateProvider2? _nextSurrogate; + public NodeToSerializableNode(ISerializationSurrogateProvider2? nextSurrogate) + { + this._nextSurrogate = nextSurrogate; + } + + public Type GetSurrogateType(Type type) + { + if (type == typeof(SurrogateTests.Node)) + return typeof(SurrogateTests.SerializableNode); + return (_nextSurrogate != null) ? _nextSurrogate.GetSurrogateType(type) : type; + } + + public object GetCustomDataToExport(Type clrType, Type dcType) + { + if (clrType == typeof(SurrogateTests.Node) && dcType == typeof(SurrogateTests.SerializableNode)) + return clrType.Assembly.GetName().Version; + return (_nextSurrogate != null) ? _nextSurrogate.GetCustomDataToExport(clrType, dcType) : null; + } + + public object GetCustomDataToExport(MemberInfo memberInfo, Type dcType) => memberInfo.MemberType.ToString(); + public void GetKnownCustomDataTypes(Collection knownTypes) => knownTypes.Add(typeof(Version)); + public object GetObjectToSerialize(object obj, Type memberType) => throw new NotImplementedException(); + public object GetDeserializedObject(object obj, Type memberType) => throw new NotImplementedException(); + public Type GetReferencedTypeOnImport(string name, string ns, object customData) => null; + } + + + public class XmlSerializerToXmlFormatter : ISerializationSurrogateProvider2 + { + ISerializationSurrogateProvider2? _nextSurrogate; + public XmlSerializerToXmlFormatter(ISerializationSurrogateProvider2? nextSurrogate) + { + this._nextSurrogate = nextSurrogate; + } + + public Type GetSurrogateType(Type type) + { + if (type == typeof(SurrogateTests.XmlSerializerPerson)) + return typeof(SurrogateTests.XmlSerializerAdapter); + return (_nextSurrogate != null) ? _nextSurrogate.GetSurrogateType(type) : type; + } + + public object GetCustomDataToExport(Type clrType, Type dcType) + { + if (clrType == typeof(SurrogateTests.XmlSerializerPerson) && dcType == typeof(SurrogateTests.XmlSerializerAdapter)) + return "XmlSerializable"; + return (_nextSurrogate != null) ? _nextSurrogate.GetCustomDataToExport(clrType, dcType) : null; + } + + public object GetCustomDataToExport(MemberInfo memberInfo, Type dcType) => memberInfo.MemberType.ToString(); + public void GetKnownCustomDataTypes(Collection knownTypes) { } + public Type GetReferencedTypeOnImport(string name, string ns, object customData) => null; + public object GetObjectToSerialize(object obj, Type memberType) => throw new NotImplementedException(); + public object GetDeserializedObject(object obj, Type memberType) => throw new NotImplementedException(); + } + + class PersonSurrogate : ISerializationSurrogateProvider2 + { + public Type GetSurrogateType(Type type) + { + if (typeof(SurrogateTests.NonSerializablePerson).IsAssignableFrom(type)) + { + return typeof(SurrogateTests.Person); + } + + if (typeof(SurrogateTests.NonSerializablePersonDC).IsAssignableFrom(type)) + { + return typeof(SurrogateTests.PersonDC); + } + return type; + } + + public object GetObjectToSerialize(object obj, Type targetType) + { + SurrogateTests.NonSerializablePerson nonSerializablePerson = obj as SurrogateTests.NonSerializablePerson; + if (nonSerializablePerson != null) + { + return new Person(); + } + SurrogateTests.NonSerializablePersonDC nonSerializablePersonDC = obj as SurrogateTests.NonSerializablePersonDC; + if (nonSerializablePersonDC != null) + { + return new SurrogateTests.PersonDC(); + } + return obj; + } + + public object GetDeserializedObject(object obj, Type targetType) + { + SurrogateTests.Person ps = obj as SurrogateTests.Person; + if (ps != null) + { + return new SurrogateTests.NonSerializablePerson("John Smith"); + } + SurrogateTests.PersonDC psDC = obj as SurrogateTests.PersonDC; + if (psDC != null) + { + return new SurrogateTests.NonSerializablePersonDC("John Smith"); + } + return obj; + } + + public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData) + { + if (typeNamespace.Equals("http://schemas.datacontract.org/2004/07/Suites.SchemaExport")) + { + if (typeName.Equals("DataContractSurrogateTest.Person")) + { + return typeof(SurrogateTests.NonSerializablePerson); + } + if (typeName.Equals("DataContractSurrogateTest.PersonDC")) + { + return typeof(SurrogateTests.NonSerializablePersonDC); + } + } + return null; + } + + public object GetCustomDataToExport(Type clrType, Type dataContractType) => null; + public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType) => null; + public void GetKnownCustomDataTypes(Collection customDataTypes) { } + } + + //This is the surrogate that substitutes CollectionWithoutParameterlessCtor for CollectionA. + class CollectionASurrogate : ISerializationSurrogateProvider2 + { + public Type GetSurrogateType(Type type) + { + if (typeof(ExporterTypesTests.CollectionA).IsAssignableFrom(type)) + { + return typeof(ExporterTypesTests.CollectionWithoutParameterlessCtor); + } + return type; + } + + public object GetObjectToSerialize(object obj, Type targetType) + { + ExporterTypesTests.CollectionA collectionA = obj as ExporterTypesTests.CollectionA; + if (collectionA != null) + { + ExporterTypesTests.CollectionWithoutParameterlessCtor validCollection = new ExporterTypesTests.CollectionWithoutParameterlessCtor(1); + validCollection.Add(1); + return validCollection; + } + return obj; + } + + public object GetDeserializedObject(object obj, Type targetType) + { + ExporterTypesTests.CollectionWithoutParameterlessCtor validCollection = obj as ExporterTypesTests.CollectionWithoutParameterlessCtor; + if (validCollection != null) + { + return new ExporterTypesTests.CollectionA(); + } + return obj; + } + + public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData) + { + if (typeNamespace.Equals("http://schemas.datacontract.org/2004/07/Suites.SchemaExport")) + { + if (typeName.Equals("ExporterTypesTests.CollectionWithoutParameterlessCtor`1")) + { + return typeof(ExporterTypesTests.CollectionA); + } + } + return null; + } + + public object GetCustomDataToExport(Type clrType, Type dataContractType) => null; + public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType) => null; + public void GetKnownCustomDataTypes(Collection customDataTypes) { } + } + #endregion + + #region Surrogate Test Types +#pragma warning disable CS0169, CS0414 + public class ValidSurrogateTest + { + ExporterTypesTests.CollectionWithoutParameterlessCtor friends; + + public ExporterTypesTests.CollectionWithoutParameterlessCtor Friends + { + get + { + friends = friends ?? new ExporterTypesTests.CollectionWithoutParameterlessCtor(2); + return friends; + } + } + } + + public class InvalidSurrogateTest + { + ExporterTypesTests.CollectionA localList = new ExporterTypesTests.CollectionA(); + + public ExporterTypesTests.CollectionA Surrogated + { + get + { + return localList; + } + } + } + + [DataContract] + public class ValidSurrogateTestDC + { + ExporterTypesTests.CollectionWithoutParameterlessCtor friends; + + [DataMember] + public ExporterTypesTests.CollectionWithoutParameterlessCtor Friends + { + get + { + friends = friends ?? new ExporterTypesTests.CollectionWithoutParameterlessCtor(2); + return friends; + } + } + } + + [DataContract] + public class InvalidSurrogateTestDC + { + ExporterTypesTests.CollectionA localList = new ExporterTypesTests.CollectionA(); + + [DataMember] + public ExporterTypesTests.CollectionA Surrogated + { + get + { + return localList; + } + } + } + + [DataContract] + public class CircleContainer + { + [DataMember] + Circle circle; + [DataMember] + public Circle[] Circles { get { return null; } set { } } + } + + [Serializable] + public class Circle + { + public int Radius; + } + + [Serializable] + public class Square + { + public int Side; + } + + public class Node + { + Node next; + } + + [Serializable] + public class SerializableNode + { + SerializableNode next; + } + + [XmlRoot("XmlSerializerPersonElement")] + public class XmlSerializerPerson + { + public XmlSerializerPerson() { } + [XmlAttribute] + public string Name; + [XmlAttribute] + public int Age; + } + + [XmlSchemaProvider("StaticGetSchema")] + public class XmlSerializerAdapter : IXmlSerializable + { + public XmlSchema GetSchema() + { + throw new NotImplementedException(); + } + + public void ReadXml(XmlReader reader) + { + throw new NotImplementedException(); + } + + public void WriteXml(XmlWriter writer) + { + throw new NotImplementedException(); + } + + static XmlQualifiedName StaticGetSchema(XmlSchemaSet schemaSet) + { + XmlReflectionImporter importer = new XmlReflectionImporter(); + XmlTypeMapping xmlTypeMapping = importer.ImportTypeMapping(typeof(T)); + XmlSchemas schemas = new XmlSchemas(); + XmlSchemaExporter exporter = new XmlSchemaExporter(schemas); + exporter.ExportTypeMapping(xmlTypeMapping); + schemas.Compile(new ValidationEventHandler(ValidationCallbackWithErrorCode), true); + for (int i = 0; i < schemas.Count; i++) + { + XmlSchema schema = schemas[i]; + schemaSet.Add(schema); + } + return new XmlQualifiedName(xmlTypeMapping.TypeName, xmlTypeMapping.Namespace); + } + + private static void ValidationCallbackWithErrorCode(object sender, ValidationEventArgs args) + { + Console.WriteLine("Schema warning: " + args.Message); + } + } + + public class Person + { + public string name = "John Smith"; + } + + public class NonSerializablePerson + { + public string name; + + public NonSerializablePerson(string name) + { + this.name = name; + } + } + + [DataContract] + public class PersonDC + { + [DataMember] + public string name = "John Smith"; + } + + public class NonSerializablePersonDC + { + public string name; + + public NonSerializablePersonDC(string name) + { + this.name = name; + } + } +#pragma warning restore CS0169, CS0414 + #endregion + } +} diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/Types.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/Types.cs new file mode 100644 index 0000000000000..f50cdb081d524 --- /dev/null +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/Types.cs @@ -0,0 +1,138 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections; +using System.Collections.Generic; + +namespace System.Runtime.Serialization.Xml.XsdDataContractExporterTests.Types +{ + [DataContract(Namespace = "http://basic")] + public class Point + { + [DataMember] + public int X = 42; + [DataMember] + public int Y = 43; + } + + [DataContract(Namespace = "http://shapes")] + public class Circle + { + [DataMember] + public Point Center = new Point(); + [DataMember] + public int Radius = 5; + } + + [DataContract(Namespace = "http://shapes")] + public class Square + { + [DataMember] + public Point BottomLeft = new Point(); + [DataMember] + public int Side = 5; + } + + public class NonSerializableSquare + { + public int Length = 5; + + public NonSerializableSquare(int length) + { + Length = length; + } + } + + public struct NonAttributedPersonStruct + { + public string firstName; + public string lastName; + } + + public class NonAttributedPersonClass + { + public string firstName = "John"; + public string lastName = "Smith"; + + internal NonAttributedPersonClass() + { + } + } + + public class ExtendedSquare : Square + { + public string lineColor = "black"; + } + + public class RecursiveCollection1 : IEnumerable + { + public void Add(RecursiveCollection1 item) + { + } + + public IEnumerator GetEnumerator() + { + throw new NotImplementedException(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + throw new NotImplementedException(); + } + } + + public class RecursiveCollection2 : IEnumerable> + { + public void Add(RecursiveCollection1 item) + { + } + + public IEnumerator> GetEnumerator() + { + throw new NotImplementedException(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + throw new NotImplementedException(); + } + } + + public class Box + { + } + + public class RecursiveCollection3 : IEnumerable>> + { + public void Add(RecursiveCollection1 item) + { + } + + public IEnumerator>> GetEnumerator() + { + throw new NotImplementedException(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + throw new NotImplementedException(); + } + } + + public class RecursiveCollection4 : IEnumerable> + { + public void Add(RecursiveCollection1 item) + { + } + + public IEnumerator> GetEnumerator() + { + throw new NotImplementedException(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + throw new NotImplementedException(); + } + } +} From 24ca75cd9658378b2358a560b059d3e7304d82be Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Tue, 2 Aug 2022 16:40:29 -0700 Subject: [PATCH 23/33] Fix bugs found by newly ported tests. --- .../src/Resources/Strings.resx | 2 +- .../Serialization/ClassDataContract.cs | 2 +- .../Serialization/CollectionDataContract.cs | 2 +- .../Runtime/Serialization/DataContract.cs | 15 +++++--- .../Runtime/Serialization/DataContractSet.cs | 24 ++++++------ .../Runtime/Serialization/DataMember.cs | 2 +- .../Runtime/Serialization/EnumDataContract.cs | 37 +++++++++++++++++++ .../System/Runtime/Serialization/Globals.cs | 6 +++ .../Serialization/PrimitiveDataContract.cs | 2 +- .../Runtime/Serialization/SchemaHelper.cs | 2 + .../Runtime/Serialization/SchemaImporter.cs | 7 ++-- .../Runtime/Serialization/XmlDataContract.cs | 2 +- 12 files changed, 76 insertions(+), 27 deletions(-) diff --git a/src/libraries/System.Private.DataContractSerialization/src/Resources/Strings.resx b/src/libraries/System.Private.DataContractSerialization/src/Resources/Strings.resx index e0ee506de2bfb..4cee84fe5e639 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/Resources/Strings.resx +++ b/src/libraries/System.Private.DataContractSerialization/src/Resources/Strings.resx @@ -1381,7 +1381,7 @@ Simple type restriction must specify a base type. - =Simple types with <union> content are not supported. + Simple types with <union> content are not supported. Invalid type specified. Type with name '{0}' not found in schema with namespace '{1}'. diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs index f158fa3ba3afc..cd7bb6a2700dd 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs @@ -1361,7 +1361,7 @@ internal override DataContract BindGenericParameters(DataContract[] paramContrac } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal override bool Equals(object? other, HashSet checkedContracts) + internal override bool Equals(object? other, HashSet? checkedContracts) { if (IsEqualOrChecked(other, checkedContracts)) return true; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs index 60c6f7e33af75..fd265d5834443 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs @@ -1491,7 +1491,7 @@ internal bool RequiresMemberAccessForWrite(SecurityException? securityException) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal override bool Equals(object? other, HashSet checkedContracts) + internal override bool Equals(object? other, HashSet? checkedContracts) { if (IsEqualOrChecked(other, checkedContracts)) return true; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs index 31134fbd87357..b0cbbceda3ffe 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs @@ -2057,7 +2057,7 @@ public sealed override bool Equals(object? obj) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal virtual bool Equals(object? other, HashSet checkedContracts) + internal virtual bool Equals(object? other, HashSet? checkedContracts) { if (other is DataContract dataContract) { @@ -2066,7 +2066,7 @@ internal virtual bool Equals(object? other, HashSet checked return false; } - internal bool IsEqualOrChecked(object? other, HashSet checkedContracts) + internal bool IsEqualOrChecked(object? other, HashSet? checkedContracts) { if (other == null) return false; @@ -2074,10 +2074,13 @@ internal bool IsEqualOrChecked(object? other, HashSet check if ((object)this == other) return true; - DataContractPairKey contractPairKey = new DataContractPairKey(this, other); - if (checkedContracts.Contains(contractPairKey)) - return true; - checkedContracts.Add(contractPairKey); + if (checkedContracts != null) + { + DataContractPairKey contractPairKey = new DataContractPairKey(this, other); + if (checkedContracts.Contains(contractPairKey)) + return true; + checkedContracts.Add(contractPairKey); + } return false; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs index 02ea2cb54821f..b08415157c270 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs @@ -92,8 +92,7 @@ internal void Add(XmlQualifiedName name, DataContract dataContract) { if (dataContract.IsBuiltInDataContract) return; - if (dataContract is DataContract dataContractInternal) - InternalAdd(name, dataContractInternal); + InternalAdd(name, dataContract); } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -167,16 +166,19 @@ private void AddClassDataContract(ClassDataContract classDataContract) [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private void AddCollectionDataContract(CollectionDataContract collectionDataContract) { - if (collectionDataContract.IsDictionary) + if (collectionDataContract.UnderlyingType != Globals.TypeOfSchemaDefinedType) { - ClassDataContract keyValueContract = (collectionDataContract.ItemContract as ClassDataContract)!; - AddClassDataContract(keyValueContract); - } - else - { - DataContract itemContract = GetItemTypeDataContract(collectionDataContract); - if (itemContract != null) - Add(itemContract.XmlName, itemContract); + if (collectionDataContract.IsDictionary) + { + ClassDataContract keyValueContract = (collectionDataContract.ItemContract as ClassDataContract)!; + AddClassDataContract(keyValueContract); + } + else + { + DataContract itemContract = GetItemTypeDataContract(collectionDataContract); + if (itemContract != null) + Add(itemContract.XmlName, itemContract); + } } AddKnownDataContracts(collectionDataContract.KnownDataContracts); } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs index 816b9aca0cdbf..2f1ed959e98dc 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataMember.cs @@ -298,7 +298,7 @@ internal DataMember BindGenericParameters(DataContract[] paramContracts, Diction } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal bool Equals(object? other, HashSet checkedContracts) + internal bool Equals(object? other, HashSet? checkedContracts) { if (this == other) return true; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs index 7ae2bd9b8738b..a964149ce9538 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs @@ -401,6 +401,43 @@ internal long GetEnumValueFromString(string value) } } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + internal override bool Equals(object? other, HashSet? checkedContracts) + { + if (IsEqualOrChecked(other, checkedContracts)) + return true; + + if (base.Equals(other, null)) + { + if (other is EnumDataContract enumContract) + { + if (Members.Count != enumContract.Members.Count || Values?.Count != enumContract.Values?.Count) + return false; + string[] memberNames1 = new string[Members.Count], memberNames2 = new string[Members.Count]; + for (int i = 0; i < Members.Count; i++) + { + memberNames1[i] = Members[i].Name; + memberNames2[i] = enumContract.Members[i].Name; + } + Array.Sort(memberNames1); + Array.Sort(memberNames2); + for (int i = 0; i < Members.Count; i++) + { + if (memberNames1[i] != memberNames2[i]) + return false; + } + + return (IsFlags == enumContract.IsFlags); + } + } + return false; + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext? context) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs index 16fc2561b92a5..fc0e5999c81be 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs @@ -320,6 +320,12 @@ internal static Type TypeOfHashtable internal static Type TypeOfSchemaDefinedType => s_typeOfSchemaDefinedType ??= typeof(SchemaDefinedType); + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicFields)] + private static Type? s_typeOfSchemaDefinedEnum; + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.NonPublicFields)] + internal static Type TypeOfSchemaDefinedEnum => + s_typeOfSchemaDefinedEnum ??= typeof(SchemaDefinedEnum); + private static MemberInfo? s_schemaMemberInfoPlaceholder; internal static MemberInfo SchemaMemberInfoPlaceholder => s_schemaMemberInfoPlaceholder ??= TypeOfSchemaDefinedType.GetField("_xmlName", BindingFlags.NonPublic | BindingFlags.Instance)!; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs index d861fcbdbdcf5..218b5ddd5433b 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs @@ -119,7 +119,7 @@ protected static bool TryReadNullAtTopLevel(XmlReaderDelegator reader) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal override bool Equals(object? other, HashSet checkedContracts) + internal override bool Equals(object? other, HashSet? checkedContracts) { if (other is PrimitiveDataContract) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs index 59639ac8bc6cc..e91e7e2d684ed 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs @@ -37,6 +37,8 @@ public SchemaDefinedType(XmlQualifiedName xmlName) } } + internal enum SchemaDefinedEnum { SchemaDefinedEnumValue }; + internal static class SchemaHelper { internal static bool NamespacesEqual(string? ns1, string? ns2) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs index 07afed9f5d03f..191261a6a423c 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs @@ -935,15 +935,13 @@ private void ImportClassMember(XmlSchemaElement element, ClassDataContract dataC { XmlQualifiedName typeName = dataContract.XmlName; - Debug.Assert(element.Name != null); - if (element.MinOccurs > 1) ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ElementMinOccursMustBe, element.Name)); if (element.MaxOccurs != 1) ThrowTypeCannotBeImportedException(typeName.Name, typeName.Namespace, SR.Format(SR.ElementMaxOccursMustBe, element.Name)); DataContract? memberTypeContract = null; - string memberName = element.Name; + string? memberName = element.Name; bool memberIsRequired = (element.MinOccurs > 0); bool memberIsNullable = element.IsNillable; bool memberEmitDefaultValue; @@ -987,6 +985,7 @@ private void ImportClassMember(XmlSchemaElement element, ClassDataContract dataC memberEmitDefaultValue = emitDefaultValueFromAnnotation != null ? emitDefaultValueFromAnnotation.Value : Globals.DefaultEmitDefaultValue; Debug.Assert(dataContract.Members != null); // This method is only called from ImportClass() after that method has initialized the Members collection. + Debug.Assert(memberName != null); // At this point, elements without a name should have been handled. int prevMemberIndex = dataContract.Members.Count - 1; if (prevMemberIndex >= 0) @@ -1179,7 +1178,7 @@ private static bool IsDictionary(XmlQualifiedName typeName, XmlSchemaAnnotation? [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] private EnumDataContract ImportEnum(XmlQualifiedName typeName, XmlSchemaSimpleTypeRestriction restriction, bool isFlags, XmlSchemaAnnotation? annotation) { - EnumDataContract dataContract = new EnumDataContract(Globals.TypeOfSchemaDefinedType); + EnumDataContract dataContract = new EnumDataContract(Globals.TypeOfSchemaDefinedEnum); dataContract.XmlName = typeName; dataContract.BaseContractName = ImportActualType(annotation, SchemaExporter.DefaultEnumBaseTypeName, typeName); dataContract.IsFlags = isFlags; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs index c0066d6d42850..597b6306d2580 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs @@ -379,7 +379,7 @@ internal IXmlSerializable ReflectionCreateXmlSerializable(Type type) } [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] - internal override bool Equals(object? other, HashSet checkedContracts) + internal override bool Equals(object? other, HashSet? checkedContracts) { if (IsEqualOrChecked(other, checkedContracts)) return true; From ded55f64e8dab87d9a9c92d69b1b7e6df4c261e8 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Tue, 2 Aug 2022 18:23:55 -0700 Subject: [PATCH 24/33] Account for different newline sizes on different platforms. --- .../Runtime/Serialization/Schema/Import/ImporterTests.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import/ImporterTests.cs b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import/ImporterTests.cs index cb951fd10dc29..79d9c1f65078e 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import/ImporterTests.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/Import/ImporterTests.cs @@ -109,14 +109,16 @@ public void Import(Action import, int codeLength = -1) } public static IEnumerable Import_MemberData() { + int newlineSize = Environment.NewLine.Length; + // Import(XmlSchemaSet) - yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.PositiveSchemas), 5396 }; + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.PositiveSchemas), 5060 + (168 * newlineSize) }; // 168 lines // Import(XmlSchemaSet, ICollection) - yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.PositiveSchemas, new XmlQualifiedName[] { SchemaUtils.ValidTypeNames[0] }), 1615 }; + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.PositiveSchemas, new XmlQualifiedName[] { SchemaUtils.ValidTypeNames[0] }), 1515 + (50 * newlineSize) }; // 50 lines // Import(XmlSchemaSet, XmlQualifiedName) - yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.PositiveSchemas, SchemaUtils.ValidTypeNames[0]), 1615 }; + yield return new object[] { (XsdDataContractImporter imp) => imp.Import(SchemaUtils.PositiveSchemas, SchemaUtils.ValidTypeNames[0]), 1515 + (50 * newlineSize) }; // 50 lines // Import(XmlSchemaSet, XmlSchemaElement) // TODO From 7462bea6f2e00ccb9405f02fccbe2ae7fe5ef8ef Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Tue, 2 Aug 2022 21:25:45 -0700 Subject: [PATCH 25/33] Skip flaky test on wasm for now. --- .../tests/XsdDataContractExporterTests/ExporterTypesTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExporterTypesTests.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExporterTypesTests.cs index c79813748c4d5..211d201329659 100644 --- a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExporterTypesTests.cs +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExporterTypesTests.cs @@ -70,6 +70,7 @@ public void TypesTest() } [Theory] + [SkipOnPlatform(TestPlatforms.Browser, "Inconsistent and unpredictable results.")] // TODO - Why does 'TypeWithReadWriteCollectionAndNoCtorOnCollection' only cause an exception sometimes, but not all the time? What's special about wasm here? [InlineData(typeof(NoDataContractWithoutParameterlessConstructor), typeof(InvalidDataContractException), @"Type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+NoDataContractWithoutParameterlessConstructor' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. Alternatively, you can ensure that the type is public and has a parameterless constructor - all public members of the type will then be serialized, and no attributes will be required.")] [InlineData(typeof(DataContractWithInvalidMember), typeof(InvalidDataContractException), @"Type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+NoDataContractWithoutParameterlessConstructor' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. Alternatively, you can ensure that the type is public and has a parameterless constructor - all public members of the type will then be serialized, and no attributes will be required.")] [InlineData(typeof(SerializableWithInvalidMember), typeof(InvalidDataContractException), @"Type 'System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterTypesTests+NoDataContractWithoutParameterlessConstructor' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. Alternatively, you can ensure that the type is public and has a parameterless constructor - all public members of the type will then be serialized, and no attributes will be required.")] From 7bbdbeef20a627b2f3c6cef2982f09c45f1f2ea2 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Wed, 10 Aug 2022 23:30:31 -0700 Subject: [PATCH 26/33] Non-draft PR feedback. --- ...m.Private.DataContractSerialization.csproj | 1 + .../Serialization/ClassDataContract.cs | 28 ++++------- .../Serialization/CollectionDataContract.cs | 30 ++++-------- .../Runtime/Serialization/DataContract.cs | 22 +++++---- .../Runtime/Serialization/DataContractSet.cs | 5 +- .../Serialization/DiagnosticUtility.cs | 46 +++++++++++++++++ .../Runtime/Serialization/EnumDataContract.cs | 10 +--- .../Serialization/ExtensionDataReader.cs | 1 + .../System/Runtime/Serialization/Globals.cs | 2 +- .../Serialization/Json/JsonDataContract.cs | 3 ++ .../Serialization/PrimitiveDataContract.cs | 1 - .../Runtime/Serialization/SchemaHelper.cs | 2 +- .../Runtime/Serialization/SchemaImporter.cs | 2 + .../Runtime/Serialization/XmlDataContract.cs | 1 - .../Serialization/XsdDataContractExporter.cs | 30 +++++++++--- ...System.Runtime.Serialization.Primitives.cs | 6 +-- .../ISerializationSurrogateProvider.cs | 29 +++++++++++ .../ISerializationSurrogateProvider2.cs | 32 ++++++++++++ .../Serialization/Schema/DiagnosticUtility.cs | 49 +++++++++++++++++++ .../ISerializationCodeDomSurrogateProvider.cs | 5 +- .../Schema/XsdDataContractImporter.cs | 10 +++- .../tests/DataContractSerializer.cs | 12 +++++ 22 files changed, 253 insertions(+), 74 deletions(-) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj b/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj index 63f4b4b250c61..f81bacc216dca 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj +++ b/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj @@ -165,6 +165,7 @@ + diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs index cd7bb6a2700dd..932e8745fa0e6 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs @@ -217,7 +217,7 @@ internal XmlFormatClassReaderDelegate XmlFormatReaderDelegate { if (IsReadOnlyContract) { - ThrowInvalidDataContractException(DeserializationExceptionMessage, null /*type*/); + ThrowInvalidDataContractException(DeserializationExceptionMessage, type: null); } XmlFormatClassReaderDelegate tempDelegate = CreateXmlFormatReaderDelegate(); Interlocked.MemoryBarrier(); @@ -302,8 +302,7 @@ internal static bool IsNonAttributedTypeValidForSerialization( if (!IsArraySegment(type)) { - Type[] interfaceTypes = type.GetInterfaces(); - foreach (Type interfaceType in interfaceTypes) + foreach (Type interfaceType in type.GetInterfaces()) { if (CollectionDataContract.IsCollectionInterface(interfaceType)) return false; @@ -584,7 +583,6 @@ private sealed class ClassDataContractCriticalHelper : DataContract.DataContract private MethodInfo? _extensionDataSetMethod; private DataContractDictionary? _knownDataContracts; private string? _serializationExceptionMessage; - private bool _isISerializable; private bool _isKnownTypeAttributeChecked; private bool _isMethodChecked; @@ -620,9 +618,9 @@ internal ClassDataContractCriticalHelper([DynamicallyAccessedMembers(DataContrac return; } Type? baseType = type.BaseType; - _isISerializable = (Globals.TypeOfISerializable.IsAssignableFrom(type)); + IsISerializable = (Globals.TypeOfISerializable.IsAssignableFrom(type)); SetIsNonAttributedType(type); - if (_isISerializable) + if (IsISerializable) { if (HasDataContract) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.ISerializableCannotHaveDataContract, DataContract.GetClrTypeFullName(type)))); @@ -660,7 +658,7 @@ internal ClassDataContractCriticalHelper([DynamicallyAccessedMembers(DataContrac throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.OnlyDataContractTypesCanHaveExtensionData, DataContract.GetClrTypeFullName(type)))); } - if (_isISerializable) + if (IsISerializable) { SetDataContractName(xmlName); } @@ -1211,11 +1209,7 @@ internal override DataContractDictionary? KnownDataContracts internal string? DeserializationExceptionMessage => (_serializationExceptionMessage == null) ? null : SR.Format(SR.ReadOnlyClassDeserialization, _serializationExceptionMessage); - internal override bool IsISerializable - { - get => _isISerializable; - set => _isISerializable = value; - } + internal override bool IsISerializable { get; set; } internal bool HasDataContract => _hasDataContract; @@ -1360,7 +1354,8 @@ internal override DataContract BindGenericParameters(DataContract[] paramContrac } } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", + Justification = "All ctor's required to create an instance of this type are marked with RequiresUnreferencedCode.")] internal override bool Equals(object? other, HashSet? checkedContracts) { if (IsEqualOrChecked(other, checkedContracts)) @@ -1446,12 +1441,7 @@ internal override bool Equals(object? other, HashSet? check private static bool IsEveryDataMemberOptional(IEnumerable dataMembers) { - foreach (DataMember dataMember in dataMembers) - { - if (dataMember.IsRequired) - return false; - } - return true; + return !dataMembers.Any(dm => dm.IsRequired); } public override int GetHashCode() diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs index fd265d5834443..ed283a39aef22 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs @@ -25,39 +25,28 @@ internal interface IKeyValue [DataContract(Namespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays")] internal struct KeyValue : IKeyValue { - private K _key; - private V _value; - internal KeyValue(K key, V value) { - _key = key; - _value = value; + Key = key; + Value = value; } [DataMember(IsRequired = true)] - public K Key - { - get => _key; - set => _key = value; - } + public K Key { get; set; } [DataMember(IsRequired = true)] - public V Value - { - get => _value; - set => _value = value; - } + public V Value { get; set; } object? IKeyValue.Key { - get => _key; - set => _key = (K)value!; + get => this.Key; + set => this.Key = (K)value!; } object? IKeyValue.Value { - get => _value; - set => _value = (V)value!; + get => this.Value; + set => this.Value = (V)value!; } } @@ -1490,7 +1479,8 @@ internal bool RequiresMemberAccessForWrite(SecurityException? securityException) return false; } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", + Justification = "All ctor's required to create an instance of this type are marked with RequiresUnreferencedCode.")] internal override bool Equals(object? other, HashSet? checkedContracts) { if (IsEqualOrChecked(other, checkedContracts)) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs index 51bc90635040e..3df8ebd13f7ae 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs @@ -415,6 +415,9 @@ internal static int GetId(RuntimeTypeHandle typeHandle) } catch (Exception ex) { + if (Fx.IsFatal(ex)) + throw; + throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(ex.Message, ex); } } @@ -905,6 +908,9 @@ internal static string GetNamespace(string key) } catch (Exception ex) { + if (Fx.IsFatal(ex)) + throw; + throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(ex.Message, ex); } } @@ -923,6 +929,9 @@ internal static XmlDictionaryString GetClrTypeString(string key) } catch (Exception ex) { + if (Fx.IsFatal(ex)) + throw; + throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(ex.Message, ex); } } @@ -935,6 +944,9 @@ internal static XmlDictionaryString GetClrTypeString(string key) } catch (Exception ex) { + if (Fx.IsFatal(ex)) + throw; + throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(ex.Message, ex); } return value; @@ -2000,7 +2012,6 @@ private static void ImportKnownTypeAttributes(Type? type, Dictionary } } - // NOTE TODO smolloy - This entire try/catch block is new in CoreFx from the beginning. I wonder why it wasn't there in NetFx. Is it needed there? Or not-needed here? //For Json we need to add KeyValuePair to KnownTypes if the UnderLyingType is a Dictionary try { @@ -2036,7 +2047,7 @@ internal static void CheckAndAdd(Type type, Dictionary typesChecked, } else if (nameToDataContractTable.TryGetValue(dataContract.XmlName, out DataContract? alreadyExistingContract)) { - // NOTE TODO smolloy - The existing contract type was used as-is in NetFx. The call to get the appropriate adapter type was added in CoreFx with https://github.com/dotnet/runtime/commit/50c0a70c52fa66fafa1227be552ccdab5e4cf8e4 + // The alreadyExistingContract type was used as-is in NetFx. The call to get the appropriate adapter type was added in CoreFx with https://github.com/dotnet/runtime/commit/50c0a70c52fa66fafa1227be552ccdab5e4cf8e4 // Don't throw duplicate if its a KeyValuePair as it could have been added by Dictionary if (DataContractCriticalHelper.GetDataContractAdapterType(alreadyExistingContract.UnderlyingType) != DataContractCriticalHelper.GetDataContractAdapterType(type)) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.DupContractInKnownTypes, type, alreadyExistingContract.UnderlyingType, dataContract.XmlName.Namespace, dataContract.XmlName.Name))); @@ -2046,9 +2057,6 @@ internal static void CheckAndAdd(Type type, Dictionary typesChecked, ImportKnownTypeAttributes(type, typesChecked, ref nameToDataContractTable); } - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", - Justification = "DataContract is an internal type, but the override here is the very public Object.Equals(). Being an internal type" + - "though, we control when this is called, and all callers are annotated with [RequiresUnreferencedCode].")] public sealed override bool Equals(object? obj) { if ((object)this == obj) @@ -2056,7 +2064,6 @@ public sealed override bool Equals(object? obj) return Equals(obj, new HashSet()); } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal virtual bool Equals(object? other, HashSet? checkedContracts) { if (other is DataContract dataContract) @@ -2232,10 +2239,7 @@ internal static string SanitizeTypeName(string typeName) return typeName.Replace('.', '_'); } } -} -namespace System.Runtime.Serialization -{ internal interface IGenericNameProvider { int GetParameterCount(); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs index b08415157c270..129540177a69d 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSet.cs @@ -67,6 +67,7 @@ public DataContractDictionary? KnownTypesForObject get => _knownTypesForObject; internal set => _knownTypesForObject = value; } + internal static void EnsureTypeNotGeneric(Type type) { if (type.ContainsGenericParameters) @@ -395,12 +396,14 @@ private static bool IsTypeReferenceable(Type type) CollectionDataContract.IsCollection(type, out _) || ClassDataContract.IsNonAttributedTypeValidForSerialization(type)); } - catch (Exception) + catch (Exception ex) { // An exception can be thrown in the designer when a project has a runtime binding redirection for a referenced assembly or a reference dependent assembly. // Type.IsDefined is known to throw System.IO.FileLoadException. // ClassDataContract.IsNonAttributedTypeValidForSerialization is known to throw System.IO.FileNotFoundException. // We guard against all non-critical exceptions. + if (Fx.IsFatal(ex)) + throw; } return false; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DiagnosticUtility.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DiagnosticUtility.cs index 012b8ec54929b..a6217253340dc 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DiagnosticUtility.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DiagnosticUtility.cs @@ -3,6 +3,8 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Threading; namespace System.Runtime.Serialization { @@ -20,6 +22,50 @@ public static void Assert(string message) { Assert(false, message); } + + public static bool IsFatal(Exception exception) + { + while (exception != null) + { + // NetFx checked for FatalException and FatalInternalException as well, which were ServiceModel constructs. + if ((exception is OutOfMemoryException && !(exception is InsufficientMemoryException)) || + exception is ThreadAbortException) + { + return true; + } + + // These exceptions aren't themselves fatal, but since the CLR uses them to wrap other exceptions, + // we want to check to see whether they've been used to wrap a fatal exception. If so, then they + // count as fatal. + if (exception is TypeInitializationException || + exception is TargetInvocationException) + { + exception = exception.InnerException!; + } + else if (exception is AggregateException) + { + // AggregateExceptions have a collection of inner exceptions, which may themselves be other + // wrapping exceptions (including nested AggregateExceptions). Recursively walk this + // hierarchy. The (singular) InnerException is included in the collection. + var innerExceptions = ((AggregateException)exception).InnerExceptions; + foreach (Exception innerException in innerExceptions) + { + if (IsFatal(innerException)) + { + return true; + } + } + + break; + } + else + { + break; + } + } + + return false; + } } internal static class DiagnosticUtility diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs index a964149ce9538..e7e19232c474b 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs @@ -123,7 +123,7 @@ internal EnumDataContractCriticalHelper( Type baseType = Enum.GetUnderlyingType(type); XmlQualifiedName baseTypeName = GetBaseContractName(baseType); _baseContract = DataContract.GetBuiltInDataContract(baseTypeName.Name, baseTypeName.Namespace)!; - // NOTE TODO smolloy - Setting XmlName might be redundant. But I don't want to miss an edge case. + // Setting XmlName might be redundant. But I don't want to miss an edge case. _baseContract.XmlName = baseTypeName; ImportBaseType(baseType); IsFlags = type.IsDefined(Globals.TypeOfFlagsAttribute, false); @@ -164,7 +164,7 @@ internal XmlQualifiedName BaseContractName SR.Format(SR.InvalidEnumBaseType, value.Name, value.Namespace, XmlName.Name, XmlName.Namespace)); ImportBaseType(baseType); _baseContract = DataContract.GetBuiltInDataContract(value.Name, value.Namespace)!; - // NOTE TODO smolloy - Setting XmlName might be redundant. But I don't want to miss an edge case. + // Setting XmlName might be redundant. But I don't want to miss an edge case. _baseContract.XmlName = value; } } @@ -401,7 +401,6 @@ internal long GetEnumValueFromString(string value) } } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal override bool Equals(object? other, HashSet? checkedContracts) { if (IsEqualOrChecked(other, checkedContracts)) @@ -433,11 +432,6 @@ internal override bool Equals(object? other, HashSet? check return false; } - public override int GetHashCode() - { - return base.GetHashCode(); - } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal override void WriteXmlValue(XmlWriterDelegator xmlWriter, object obj, XmlObjectSerializerWriteContext? context) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExtensionDataReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExtensionDataReader.cs index ee25766466b35..d4309b86b3d4c 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExtensionDataReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ExtensionDataReader.cs @@ -737,6 +737,7 @@ private bool MoveToText(Type type, IDataNode dataNode, bool isTypedNode) _internalNodeType = ExtensionDataNodeType.Text; return handled; } + private void PushElement() { GrowElementsIfNeeded(); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs index 95e6176016c73..3fa9493884c75 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Globals.cs @@ -328,7 +328,7 @@ internal static Type TypeOfHashtable private static MemberInfo? s_schemaMemberInfoPlaceholder; internal static MemberInfo SchemaMemberInfoPlaceholder => - s_schemaMemberInfoPlaceholder ??= TypeOfSchemaDefinedType.GetField("_xmlName", BindingFlags.NonPublic | BindingFlags.Instance)!; + s_schemaMemberInfoPlaceholder ??= TypeOfSchemaDefinedType.GetField(nameof(SchemaDefinedType._xmlName), BindingFlags.NonPublic | BindingFlags.Instance)!; private static Uri? s_dataContractXsdBaseNamespaceUri; internal static Uri DataContractXsdBaseNamespaceUri => diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonDataContract.cs index 589e69485f54f..88258b3b397cd 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonDataContract.cs @@ -204,6 +204,9 @@ internal static int GetId(RuntimeTypeHandle typeHandle) } catch (Exception ex) { + if (Fx.IsFatal(ex)) + throw; + throw DiagnosticUtility.ExceptionUtility.ThrowHelperFatal(ex.Message, ex); } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs index 218b5ddd5433b..638ba22d8842f 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/PrimitiveDataContract.cs @@ -118,7 +118,6 @@ protected static bool TryReadNullAtTopLevel(XmlReaderDelegator reader) return false; } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal override bool Equals(object? other, HashSet? checkedContracts) { if (other is PrimitiveDataContract) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs index e91e7e2d684ed..2a632482b459e 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaHelper.cs @@ -29,7 +29,7 @@ internal SchemaObjectInfo(XmlSchemaType? type, XmlSchemaElement? element, XmlSch internal sealed class SchemaDefinedType { - private XmlQualifiedName _xmlName; + internal XmlQualifiedName _xmlName; public SchemaDefinedType(XmlQualifiedName xmlName) { diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs index 191261a6a423c..2590d866c26f8 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/SchemaImporter.cs @@ -62,6 +62,8 @@ internal void Import([NotNullIfNotNull("_elements")] out List? #pragma warning suppress 56500 // covered by FxCOP catch (Exception ex) { + if (Fx.IsFatal(ex)) + throw; throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.Format(SR.CannotImportInvalidSchemas), ex)); } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs index 597b6306d2580..af769058a1f9a 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs @@ -378,7 +378,6 @@ internal IXmlSerializable ReflectionCreateXmlSerializable(Type type) } } - [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] internal override bool Equals(object? other, HashSet? checkedContracts) { if (IsEqualOrChecked(other, checkedContracts)) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs index 8cc82bbb2ed98..3a59e19a55867 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XsdDataContractExporter.cs @@ -123,8 +123,11 @@ public void Export(ICollection assemblies) Export(); } - catch + catch (Exception ex) { + if (Fx.IsFatal(ex)) + throw; + _dataContractSet = oldValue; throw; } @@ -151,8 +154,11 @@ public void Export(ICollection types) Export(); } - catch + catch (Exception ex) { + if (Fx.IsFatal(ex)) + throw; + _dataContractSet = oldValue; throw; } @@ -173,8 +179,11 @@ public void Export(Type type) AddType(type); Export(); } - catch + catch (Exception ex) { + if (Fx.IsFatal(ex)) + throw; + _dataContractSet = oldValue; throw; } @@ -320,8 +329,11 @@ public bool CanExport(ICollection assemblies) _dataContractSet = oldValue; return false; } - catch + catch (Exception ex) { + if (Fx.IsFatal(ex)) + throw; + _dataContractSet = oldValue; throw; } @@ -354,8 +366,11 @@ public bool CanExport(ICollection types) _dataContractSet = oldValue; return false; } - catch + catch (Exception ex) { + if (Fx.IsFatal(ex)) + throw; + _dataContractSet = oldValue; throw; } @@ -383,8 +398,11 @@ public bool CanExport(Type type) _dataContractSet = oldValue; return false; } - catch + catch (Exception ex) { + if (Fx.IsFatal(ex)) + throw; + _dataContractSet = oldValue; throw; } diff --git a/src/libraries/System.Runtime.Serialization.Primitives/ref/System.Runtime.Serialization.Primitives.cs b/src/libraries/System.Runtime.Serialization.Primitives/ref/System.Runtime.Serialization.Primitives.cs index e57d5032e1c72..63f1abbba95ae 100644 --- a/src/libraries/System.Runtime.Serialization.Primitives/ref/System.Runtime.Serialization.Primitives.cs +++ b/src/libraries/System.Runtime.Serialization.Primitives/ref/System.Runtime.Serialization.Primitives.cs @@ -3,8 +3,6 @@ // ------------------------------------------------------------------------------ // Changes to this file must follow the https://aka.ms/api-review process. // ------------------------------------------------------------------------------ -using System.Collections.ObjectModel; -using System.Reflection; namespace System.Runtime.Serialization { @@ -80,9 +78,9 @@ public partial interface ISerializationSurrogateProvider } public interface ISerializationSurrogateProvider2 : ISerializationSurrogateProvider { - object? GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType); + object? GetCustomDataToExport(Reflection.MemberInfo memberInfo, Type dataContractType); object? GetCustomDataToExport(Type runtimeType, Type dataContractType); - void GetKnownCustomDataTypes(Collection customDataTypes); + void GetKnownCustomDataTypes(Collections.ObjectModel.Collection customDataTypes); Type? GetReferencedTypeOnImport(string typeName, string typeNamespace, object? customData); } [System.AttributeUsageAttribute(System.AttributeTargets.Class | System.AttributeTargets.Struct, Inherited=true, AllowMultiple=true)] diff --git a/src/libraries/System.Runtime.Serialization.Primitives/src/System/Runtime/Serialization/ISerializationSurrogateProvider.cs b/src/libraries/System.Runtime.Serialization.Primitives/src/System/Runtime/Serialization/ISerializationSurrogateProvider.cs index 6ff2e2c899451..571fc45de92d1 100644 --- a/src/libraries/System.Runtime.Serialization.Primitives/src/System/Runtime/Serialization/ISerializationSurrogateProvider.cs +++ b/src/libraries/System.Runtime.Serialization.Primitives/src/System/Runtime/Serialization/ISerializationSurrogateProvider.cs @@ -3,10 +3,39 @@ namespace System.Runtime.Serialization { + /// + /// Provides the methods needed to substitute one type for another by DataContractSerializer during serialization + /// and deserialization. This interface together with (and + /// `System.Runtime.Serialization.Schema.ISerializationCodeDomSurrogateProvider`) replace + /// the `IDataContractSurrogate` from .Net 4.8. + /// public interface ISerializationSurrogateProvider { + /// + /// During serialization, deserialization, and schema import and export, returns a data contract type that substitutes the specified type. + /// (Formerly known as `GetDataContractType` on the .Net 4.8 `IDataContractSurrogate` interface.) + /// + /// The runtime type to substitute. + /// The to substitute for the type value. This type must be serializable by the DataContractSerializer. For example, + /// it must be marked with the DataContractAttribute attribute or other mechanisms that the serializer recognizes. Type GetSurrogateType(Type type); + + /// + /// During serialization, returns an object that substitutes the specified object. + /// + /// The object to substitute. + /// The that the substituted object should be assigned to. + /// The substituted object that will be serialized. The object must be serializable by the DataContractSerializer. For example, + /// it must be marked with the attribute or other mechanisms that the serializer recognizes. object GetObjectToSerialize(object obj, Type targetType); + + /// + /// During deserialization, returns an object that is a substitute for the specified object. + /// + /// The deserialized object to be substituted. + /// The that the substituted object should be assigned to. + /// The substituted deserialized object. This object must be of a type that is serializable by the DataContractSerializer. For example, + /// it must be marked with the attribute or other mechanisms that the serializer recognizes. object GetDeserializedObject(object obj, Type targetType); } } diff --git a/src/libraries/System.Runtime.Serialization.Primitives/src/System/Runtime/Serialization/ISerializationSurrogateProvider2.cs b/src/libraries/System.Runtime.Serialization.Primitives/src/System/Runtime/Serialization/ISerializationSurrogateProvider2.cs index 0d53dff2f33f0..0194c0f111a6a 100644 --- a/src/libraries/System.Runtime.Serialization.Primitives/src/System/Runtime/Serialization/ISerializationSurrogateProvider2.cs +++ b/src/libraries/System.Runtime.Serialization.Primitives/src/System/Runtime/Serialization/ISerializationSurrogateProvider2.cs @@ -6,11 +6,43 @@ namespace System.Runtime.Serialization { + /// + /// Provides the methods needed to substitute one type for another by DataContractSerializer during export + /// and import of XML schema documents (XSD). This interface builds upon . + /// Together (along with `System.Runtime.Serialization.Schema.ISerializationCodeDomSurrogateProvider`), these + /// interfaces replace the `IDataContractSurrogate` from .Net 4.8. + /// public interface ISerializationSurrogateProvider2 : ISerializationSurrogateProvider { + /// + /// During schema export operations, inserts annotations into the schema for non-null return values. + /// + /// A that describes the member. + /// The data contract type to be annotated. + /// An object that represents the annotation to be inserted into the XML schema definition. object? GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType); + + /// + /// During schema export operations, inserts annotations into the schema for non-null return values. + /// + /// The runtime type to be replaced. + /// The data contract type to be annotated. + /// An object that represents the annotation to be inserted into the XML schema definition. object? GetCustomDataToExport(Type runtimeType, Type dataContractType); + + /// + /// Sets the collection of known types to use for serialization and deserialization of the custom data objects. + /// + /// A of to add known types to. void GetKnownCustomDataTypes(Collection customDataTypes); + + /// + /// During schema import, returns the type referenced by the schema. + /// + /// The name of the type in schema. + /// The namespace of the type in schema. + /// The object that represents the annotation inserted into the XML schema definition, which is data that can be used for finding the referenced type. + /// The to use for the referenced type. Type? GetReferencedTypeOnImport(string typeName, string typeNamespace, object? customData); } } diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/DiagnosticUtility.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/DiagnosticUtility.cs index 6064c043bfceb..46b0dde85c686 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/DiagnosticUtility.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/DiagnosticUtility.cs @@ -3,9 +3,58 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Threading; namespace System.Runtime.Serialization { + internal static class Fx + { + public static bool IsFatal(Exception exception) + { + while (exception != null) + { + // NetFx checked for FatalException and FatalInternalException as well, which were ServiceModel constructs. + if ((exception is OutOfMemoryException && !(exception is InsufficientMemoryException)) || + exception is ThreadAbortException) + { + return true; + } + + // These exceptions aren't themselves fatal, but since the CLR uses them to wrap other exceptions, + // we want to check to see whether they've been used to wrap a fatal exception. If so, then they + // count as fatal. + if (exception is TypeInitializationException || + exception is TargetInvocationException) + { + exception = exception.InnerException!; + } + else if (exception is AggregateException) + { + // AggregateExceptions have a collection of inner exceptions, which may themselves be other + // wrapping exceptions (including nested AggregateExceptions). Recursively walk this + // hierarchy. The (singular) InnerException is included in the collection. + var innerExceptions = ((AggregateException)exception).InnerExceptions; + foreach (Exception innerException in innerExceptions) + { + if (IsFatal(innerException)) + { + return true; + } + } + + break; + } + else + { + break; + } + } + + return false; + } + } + internal static class DiagnosticUtility { [Conditional("DEBUG")] diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ISerializationCodeDomSurrogateProvider.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ISerializationCodeDomSurrogateProvider.cs index 2fcf279dc6f1a..a69a18711d0b4 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ISerializationCodeDomSurrogateProvider.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ISerializationCodeDomSurrogateProvider.cs @@ -14,8 +14,11 @@ namespace System.Runtime.Serialization public interface ISerializationCodeDomSurrogateProvider { /// - /// A method to processes the type that has been generated from imported schema. + /// Processes the type that has been generated from the imported schema. /// + /// A to process that represents the type declaration generated during schema import. + /// The that contains the other code generated during schema import. + /// A that contains the processed type. CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit); } } diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs index 24b3db31024fa..00f54a684a059 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/XsdDataContractImporter.cs @@ -321,8 +321,11 @@ private XmlSchemaElement[] SingleElementArray return elementTypeNames; } - catch + catch (Exception ex) { + if (Fx.IsFatal(ex)) + throw; + _dataContractSet = oldValue; throw; } @@ -353,8 +356,11 @@ private bool InternalCanImport(XmlSchemaSet schemas, ICollection(DateTime.SpecifyKind(DateTime.MaxValue, DateTimeKind.Utc), @"9999-12-31T23:59:59.9999999Z"), DateTime.SpecifyKind(DateTime.MaxValue, DateTimeKind.Utc)); } + [Fact] + public static void DCS_BinarySerializationOfDateTime() + { + DateTime dateTime = DateTime.Parse("2021-01-01"); + MemoryStream ms = new(); + DataContractSerializer dcs = new(dateTime.GetType()); + using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(ms, null, null, ownsStream: true)) + dcs.WriteObject(writer, dateTime); + var serializedBytes = ms.ToArray(); + Assert.Equal(72, serializedBytes.Length); + } + [Fact] public static void DCS_DecimalAsRoot() { From be324a7db4f8f0656e20a36e818211bbee7bd8d4 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Thu, 11 Aug 2022 00:36:51 -0700 Subject: [PATCH 27/33] Gentle nudge for Azure pipeline, which seems to have gotten stuck. --- .../src/System/Runtime/Serialization/ClassDataContract.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs index 932e8745fa0e6..abeeabc0743f2 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs @@ -1306,7 +1306,7 @@ internal override DataContract BindGenericParameters(DataContract[] paramContrac xmlName = XmlName; genericParams = paramContracts; - // NOTE TODO smolloy - this type-binding ('boundType') stuff is new. We did not do this in NetFx. We used to use default constructors and let the + // NOTE TODO smolloy - this type-binding ('boundType') stuff is new here. We did not do this in NetFx. We used to use default constructors and let the // underlying type get filled in later. But default constructors for DataContracts runs afoul of requiring an underlying type. Our web of nullable // notations make it hard to get around. But it also allows us to feel good about using .UnderlyingType from matching parameter contracts. Type[] underlyingParamTypes = new Type[paramContracts.Length]; From 08d419cde90cc3ec97ca8518e145cb1773368a98 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Fri, 12 Aug 2022 03:29:02 -0700 Subject: [PATCH 28/33] Change DC.Members API. Drop KVP shennanigans. --- .../Serialization/ClassDataContract.cs | 9 +- .../Runtime/Serialization/DataContract.cs | 58 ++++--- .../Runtime/Serialization/EnumDataContract.cs | 8 +- .../Serialization/Schema/CodeExporter.cs | 145 ++++++++---------- .../Serialization/Schema/RoundTripTest.cs | 19 ++- .../ref/System.Runtime.Serialization.Xml.cs | 2 +- .../ExporterApiTests.cs | 5 +- 7 files changed, 141 insertions(+), 105 deletions(-) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs index abeeabc0743f2..31ac83ec899cd 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -63,12 +64,14 @@ internal ClassDataContract? BaseClassContract set => _helper.BaseClassContract = value; } - public override List? Members + internal List? Members { get => _helper.Members; - internal set => _helper.Members = value; + set => _helper.Members = value; } + public override ReadOnlyCollection DataMembers => (Members == null) ? DataContract.s_emptyDataMemberList : Members.AsReadOnly(); + internal XmlDictionaryString?[]? ChildElementNamespaces { [RequiresUnreferencedCode(DataContract.SerializerTrimmerWarning)] @@ -1306,7 +1309,7 @@ internal override DataContract BindGenericParameters(DataContract[] paramContrac xmlName = XmlName; genericParams = paramContracts; - // NOTE TODO smolloy - this type-binding ('boundType') stuff is new here. We did not do this in NetFx. We used to use default constructors and let the + // NOTE TODO smolloy - this type-binding ('boundType') stuff is new. We did not do this in NetFx. We used to use default constructors and let the // underlying type get filled in later. But default constructors for DataContracts runs afoul of requiring an underlying type. Our web of nullable // notations make it hard to get around. But it also allows us to feel good about using .UnderlyingType from matching parameter contracts. Type[] underlyingParamTypes = new Type[paramContracts.Length]; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs index 3df8ebd13f7ae..743d45d26f8b6 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs @@ -5,6 +5,7 @@ using System.Buffers.Binary; using System.Collections; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; @@ -32,6 +33,8 @@ public abstract class DataContract DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties; + internal static ReadOnlyCollection s_emptyDataMemberList = new List().AsReadOnly(); + private XmlDictionaryString _name; private XmlDictionaryString _ns; private readonly DataContractCriticalHelper _helper; @@ -251,11 +254,7 @@ public virtual bool IsDictionaryLike([NotNullWhen(true)] out string? keyName, [N return false; } - public virtual List? Members - { - get => null; - internal set { } - } + public virtual ReadOnlyCollection DataMembers => s_emptyDataMemberList; internal virtual void WriteRootElement(XmlWriterDelegator writer, XmlDictionaryString name, XmlDictionaryString? ns) { @@ -2012,24 +2011,45 @@ private static void ImportKnownTypeAttributes(Type? type, Dictionary } } - //For Json we need to add KeyValuePair to KnownTypes if the UnderLyingType is a Dictionary - try + AppContext.TryGetSwitch("Switch.System.Runtime.Serialization.DataContracts.Auto_Import_KVP", out bool autoImportKVP); + if (autoImportKVP) { - if (DataContract.GetDataContract(type) is CollectionDataContract collectionDataContract && collectionDataContract.IsDictionary && - collectionDataContract.ItemType.GetGenericTypeDefinition() == Globals.TypeOfKeyValue) + //For Json we need to add KeyValuePair to KnownTypes if the UnderLyingType is a Dictionary + // + // ^^^ Years later I think this is referring to how we treat dictionaries as collections of the + // 'KeyValue' struct we have internally. But Json for some reason needed contracts for KeyValuePair + // as well. Possibly related to 'UseSimpleDictionaryFormat'? So we would import both KeyValue and KVP + // contracts and be happy. + // Years later, we've had and gotten rid of a KeyValuePair adapter, and I'm not sure I see a case where + // DCJS is failing with either dictionary format without this code. This seems extraneous at this + // point. Perhaps its there to bridge a potential mis-match between producer and consumer? + // + // + // Or, if I put more faith in the 'catch' comment - this was a case where DCSJ might have used + // an internal KV struct because KVP was missing [Serializable], but regular DCS was using a + // KVPAdapter class? And now KVP does have [Serializable] so we don't need either of those workarounds + // anymore. We already dropped KVPAdapter in this PR. We can probably drop this workaround as well. + // This seems the more likely explaination for this block. + // + // TODO smolloy - discuss potential removal of this altogether. + try { - DataContract itemDataContract = DataContract.GetDataContract(Globals.TypeOfKeyValuePair.MakeGenericType(collectionDataContract.ItemType.GetGenericArguments())); - knownDataContracts ??= new DataContractDictionary(); + if (DataContract.GetDataContract(type) is CollectionDataContract collectionDataContract && collectionDataContract.IsDictionary && + collectionDataContract.ItemType.GetGenericTypeDefinition() == Globals.TypeOfKeyValue) + { + DataContract itemDataContract = DataContract.GetDataContract(Globals.TypeOfKeyValuePair.MakeGenericType(collectionDataContract.ItemType.GetGenericArguments())); + knownDataContracts ??= new DataContractDictionary(); - knownDataContracts.TryAdd(itemDataContract.XmlName, itemDataContract); + knownDataContracts.TryAdd(itemDataContract.XmlName, itemDataContract); + } + } + catch (InvalidDataContractException) + { + //Ignore any InvalidDataContractException as this phase is a workaround for lack of ISerializable. + //InvalidDataContractException may happen as we walk the type hierarchy back to Object and encounter + //types that may not be valid DC. This step is purely for KeyValuePair and shouldn't fail the (de)serialization. + //Any IDCE in this case fails the serialization/deserialization process which is not the optimal experience. } - } - catch (InvalidDataContractException) - { - //Ignore any InvalidDataContractException as this phase is a workaround for lack of ISerializable. - //InvalidDataContractException may happen as we walk the type hierarchy back to Object and encounter - //types that may not be valid DC. This step is purely for KeyValuePair and shouldn't fail the (de)serialization. - //Any IDCE in this case fails the serialization/deserialization process which is not the optimal experience. } type = type.BaseType; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs index e7e19232c474b..ac13799e9e78f 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/EnumDataContract.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -43,13 +44,14 @@ internal XmlQualifiedName BaseContractName set => _helper.BaseContractName = value; } - [NotNull] - public override List? Members + internal List Members { get => _helper.Members; - internal set => _helper.Members = value!; + set => _helper.Members = value; } + public override ReadOnlyCollection DataMembers => (Members == null) ? DataContract.s_emptyDataMemberList : Members.AsReadOnly(); + internal List? Values { get => _helper.Values; diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs index 7de43e0371495..6b84d07b7a630 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs @@ -660,10 +660,10 @@ private bool TryGetReferencedDictionaryType(DataContract collectionContract, [No // A dictionary should have a Key/Value item contract that has at least two members: key and value. Debug.Assert(itemContract != null); - Debug.Assert(itemContract.Members != null && itemContract.Members.Count > 1); + Debug.Assert(itemContract.DataMembers.Count > 1); - DataMember keyMember = itemContract.Members[0]; - DataMember valueMember = itemContract.Members[1]; + DataMember keyMember = itemContract.DataMembers[0]; + DataMember valueMember = itemContract.DataMembers[1]; CodeTypeReference? keyTypeReference = GetElementTypeReference(keyMember.MemberTypeContract, keyMember.IsNullable); CodeTypeReference? valueTypeReference = GetElementTypeReference(valueMember.MemberTypeContract, valueMember.IsNullable); if (keyTypeReference != null && valueTypeReference != null) @@ -838,49 +838,46 @@ private void ExportClassDataContract(DataContract classDataContract, ContractCod } } - if (classDataContract.Members != null) + for (int i = 0; i < classDataContract.DataMembers.Count; i++) { - for (int i = 0; i < classDataContract.Members.Count; i++) - { - DataMember dataMember = classDataContract.Members[i]; - - CodeTypeReference memberType = GetElementTypeReference(dataMember.MemberTypeContract, - (dataMember.IsNullable && dataMember.MemberTypeContract.IsValueType)); - - string dataMemberName = GetNameForAttribute(dataMember.Name); - string propertyName = GetMemberName(dataMemberName, contractCodeDomInfo); - string fieldName = GetMemberName(AppendToValidClrIdentifier(propertyName, ImportGlobals.DefaultFieldSuffix), contractCodeDomInfo); - - CodeMemberField field = new CodeMemberField(); - field.Type = memberType; - field.Name = fieldName; - field.Attributes = MemberAttributes.Private; - - CodeMemberProperty property = CreateProperty(memberType, propertyName, fieldName, dataMember.MemberTypeContract.IsValueType && SupportsDeclareValueTypes, raisePropertyChanged); - object? surrogateData = _dataContractSet.SurrogateData[dataMember]; - if (surrogateData != null) - property.UserData.Add(s_surrogateDataKey, surrogateData); - - CodeAttributeDeclaration dataMemberAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(DataMemberAttribute))); - if (dataMemberName != property.Name) - dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.NameProperty, new CodePrimitiveExpression(dataMemberName))); - if (dataMember.IsRequired != ImportGlobals.DefaultIsRequired) - dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.IsRequiredProperty, new CodePrimitiveExpression(dataMember.IsRequired))); - if (dataMember.EmitDefaultValue != ImportGlobals.DefaultEmitDefaultValue) - dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.EmitDefaultValueProperty, new CodePrimitiveExpression(dataMember.EmitDefaultValue))); - if (dataMember.Order != ImportGlobals.DefaultOrder) - dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.OrderProperty, new CodePrimitiveExpression(dataMember.Order))); - property.CustomAttributes.Add(dataMemberAttribute); - - if (GenerateSerializableTypes && !dataMember.IsRequired) - { - CodeAttributeDeclaration optionalFieldAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(OptionalFieldAttribute))); - field.CustomAttributes.Add(optionalFieldAttribute); - } + DataMember dataMember = classDataContract.DataMembers[i]; + + CodeTypeReference memberType = GetElementTypeReference(dataMember.MemberTypeContract, + (dataMember.IsNullable && dataMember.MemberTypeContract.IsValueType)); + + string dataMemberName = GetNameForAttribute(dataMember.Name); + string propertyName = GetMemberName(dataMemberName, contractCodeDomInfo); + string fieldName = GetMemberName(AppendToValidClrIdentifier(propertyName, ImportGlobals.DefaultFieldSuffix), contractCodeDomInfo); + + CodeMemberField field = new CodeMemberField(); + field.Type = memberType; + field.Name = fieldName; + field.Attributes = MemberAttributes.Private; - type.Members.Add(field); - type.Members.Add(property); + CodeMemberProperty property = CreateProperty(memberType, propertyName, fieldName, dataMember.MemberTypeContract.IsValueType && SupportsDeclareValueTypes, raisePropertyChanged); + object? surrogateData = _dataContractSet.SurrogateData[dataMember]; + if (surrogateData != null) + property.UserData.Add(s_surrogateDataKey, surrogateData); + + CodeAttributeDeclaration dataMemberAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(DataMemberAttribute))); + if (dataMemberName != property.Name) + dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.NameProperty, new CodePrimitiveExpression(dataMemberName))); + if (dataMember.IsRequired != ImportGlobals.DefaultIsRequired) + dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.IsRequiredProperty, new CodePrimitiveExpression(dataMember.IsRequired))); + if (dataMember.EmitDefaultValue != ImportGlobals.DefaultEmitDefaultValue) + dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.EmitDefaultValueProperty, new CodePrimitiveExpression(dataMember.EmitDefaultValue))); + if (dataMember.Order != ImportGlobals.DefaultOrder) + dataMemberAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.OrderProperty, new CodePrimitiveExpression(dataMember.Order))); + property.CustomAttributes.Add(dataMemberAttribute); + + if (GenerateSerializableTypes && !dataMember.IsRequired) + { + CodeAttributeDeclaration optionalFieldAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(OptionalFieldAttribute))); + field.CustomAttributes.Add(optionalFieldAttribute); } + + type.Members.Add(field); + type.Members.Add(property); } } @@ -940,26 +937,23 @@ private static bool NeedsExplicitNamespace(string dataContractNamespace, string return classDataContract.KnownDataContracts; handledContracts.Add(classDataContract, null); - if (classDataContract.Members != null) - { bool objectMemberHandled = false; - foreach (DataMember dataMember in classDataContract.Members) + foreach (DataMember dataMember in classDataContract.DataMembers) + { + DataContract memberContract = dataMember.MemberTypeContract; + if (!objectMemberHandled && _dataContractSet.KnownTypesForObject != null && IsObjectContract(memberContract)) + { + AddKnownTypeContracts(classDataContract, _dataContractSet.KnownTypesForObject); + objectMemberHandled = true; + } + else if (memberContract.Is(DataContractType.ClassDataContract)) { - DataContract memberContract = dataMember.MemberTypeContract; - if (!objectMemberHandled && _dataContractSet.KnownTypesForObject != null && IsObjectContract(memberContract)) + ContractCodeDomInfo memberCodeDomInfo = GetContractCodeDomInfo(memberContract); + if (!memberCodeDomInfo.IsProcessed) + GenerateType(memberContract, memberCodeDomInfo); + if (memberCodeDomInfo.ReferencedTypeExists) { - AddKnownTypeContracts(classDataContract, _dataContractSet.KnownTypesForObject); - objectMemberHandled = true; - } - else if (memberContract.Is(DataContractType.ClassDataContract)) - { - ContractCodeDomInfo memberCodeDomInfo = GetContractCodeDomInfo(memberContract); - if (!memberCodeDomInfo.IsProcessed) - GenerateType(memberContract, memberCodeDomInfo); - if (memberCodeDomInfo.ReferencedTypeExists) - { - AddKnownTypeContracts(classDataContract, GetKnownTypeContracts(memberContract, handledContracts)); - } + AddKnownTypeContracts(classDataContract, GetKnownTypeContracts(memberContract, handledContracts)); } } } @@ -1089,25 +1083,22 @@ private void ExportEnumDataContract(DataContract enumDataContract, ContractCodeD type.CustomAttributes.Add(dataContractAttribute); AddImportStatement(typeof(DataContractAttribute).Namespace, contractCodeDomInfo.CodeNamespace); - if (enumDataContract.Members != null) + for (int i = 0; i < enumDataContract.DataMembers.Count; i++) { - for (int i = 0; i < enumDataContract.Members.Count; i++) - { - string stringValue = enumDataContract.Members[i].Name; - long longValue = enumDataContract.Members[i].Order; // Members[] and Values[] go hand in hand. + string stringValue = enumDataContract.DataMembers[i].Name; + long longValue = enumDataContract.DataMembers[i].Order; // Members[] and Values[] go hand in hand. - CodeMemberField enumMember = new CodeMemberField(); - if (baseType == typeof(ulong)) - enumMember.InitExpression = new CodeSnippetExpression(XmlConvert.ToString((ulong)longValue)); - else - enumMember.InitExpression = new CodePrimitiveExpression(longValue); - enumMember.Name = GetMemberName(stringValue, contractCodeDomInfo); - CodeAttributeDeclaration enumMemberAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(EnumMemberAttribute))); - if (enumMember.Name != stringValue) - enumMemberAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.ValueProperty, new CodePrimitiveExpression(stringValue))); - enumMember.CustomAttributes.Add(enumMemberAttribute); - type.Members.Add(enumMember); - } + CodeMemberField enumMember = new CodeMemberField(); + if (baseType == typeof(ulong)) + enumMember.InitExpression = new CodeSnippetExpression(XmlConvert.ToString((ulong)longValue)); + else + enumMember.InitExpression = new CodePrimitiveExpression(longValue); + enumMember.Name = GetMemberName(stringValue, contractCodeDomInfo); + CodeAttributeDeclaration enumMemberAttribute = new CodeAttributeDeclaration(GetClrTypeFullName(typeof(EnumMemberAttribute))); + if (enumMember.Name != stringValue) + enumMemberAttribute.Arguments.Add(new CodeAttributeArgument(ImportGlobals.ValueProperty, new CodePrimitiveExpression(stringValue))); + enumMember.CustomAttributes.Add(enumMemberAttribute); + type.Members.Add(enumMember); } } diff --git a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/RoundTripTest.cs b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/RoundTripTest.cs index b39e1c79d8f5a..67c31622ace95 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/RoundTripTest.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/tests/System/Runtime/Serialization/Schema/RoundTripTest.cs @@ -22,6 +22,10 @@ public RoundTripTest(ITestOutputHelper output) [Fact] public void RountTripTest() { + // AppContext SetSwitch seems to be unreliable in the unit test case. So let's not rely on it + // for test coverage. But let's do look at the app switch to get our verification correct. + AppContext.TryGetSwitch("Switch.System.Runtime.Serialization.DataContracts.Auto_Import_KVP", out bool autoImportKVP); + XsdDataContractExporter exporter = new XsdDataContractExporter(); exporter.Export(typeof(RootClass)); XsdDataContractImporter importer = new XsdDataContractImporter(); @@ -30,6 +34,7 @@ public void RountTripTest() importer.Options.ReferencedTypes.Add(typeof(DBNull)); importer.Options.ReferencedTypes.Add(typeof(DateTimeOffset)); importer.Import(exporter.Schemas); + string code = SchemaUtils.DumpCode(importer.CodeCompileUnit); _output.WriteLine(code); @@ -56,7 +61,19 @@ public void RountTripTest() Assert.Contains(@"public partial class ArrayOfKeyValueOfintArrayOfstringty7Ep6D1 : object, System.Xml.Serialization.IXmlSerializable", code); Assert.Contains(@"private static System.Xml.XmlQualifiedName typeName = new System.Xml.XmlQualifiedName(""ArrayOfKeyValueOfintArrayOfstringty7Ep6D1"", ""http://schemas.microsoft.com/2003/10/Serialization/Arrays"");", code); Assert.Contains(@"public partial class ArrayOfKeyValueOfNullableOfunsignedByteNullableOfunsignedByte_ShTDFhl_P : object, System.Xml.Serialization.IXmlSerializable", code); - Assert.Contains(@"[System.Runtime.Serialization.DataContractAttribute(Name=""KeyValuePairOfstringNullableOfintU6ho3Bhd"", Namespace=""http://schemas.datacontract.org/2004/07/System.Collections.Generic"")]", code); + + if (autoImportKVP) + { + Assert.Contains(@"public partial struct KeyValuePairOfintArrayOfstringty7Ep6D1 : System.Runtime.Serialization.IExtensibleDataObject", code); + Assert.Contains(@"public partial struct KeyValuePairOfNullableOfunsignedByteNullableOfunsignedByte_ShTDFhl_P : System.Runtime.Serialization.IExtensibleDataObject", code); + Assert.Contains(@"[System.Runtime.Serialization.DataContractAttribute(Name=""KeyValuePairOfstringNullableOfintU6ho3Bhd"", Namespace=""http://schemas.datacontract.org/2004/07/System.Collections.Generic"")]", code); + } + else + { + Assert.DoesNotContain(@"public partial struct KeyValuePairOfintArrayOfstringty7Ep6D1 : System.Runtime.Serialization.IExtensibleDataObject", code); + Assert.DoesNotContain(@"public partial struct KeyValuePairOfNullableOfunsignedByteNullableOfunsignedByte_ShTDFhl_P : System.Runtime.Serialization.IExtensibleDataObject", code); + Assert.DoesNotContain(@"[System.Runtime.Serialization.DataContractAttribute(Name=""KeyValuePairOfstringNullableOfintU6ho3Bhd"", Namespace=""http://schemas.datacontract.org/2004/07/System.Collections.Generic"")]", code); + } } [Fact] diff --git a/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs b/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs index b42c43aa1f64a..e1f9618e94dc6 100644 --- a/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs +++ b/src/libraries/System.Runtime.Serialization.Xml/ref/System.Runtime.Serialization.Xml.cs @@ -492,7 +492,7 @@ internal DataContract(DataContractCriticalHelper helper) { } public virtual bool IsReference { get { throw null; } } public virtual bool IsValueType { get { throw null; } } public virtual System.Collections.Generic.Dictionary? KnownDataContracts { [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Data Contract Serialization and Deserialization might require types that cannot be statically analyzed. Make sure all of the required types are preserved.")] get { throw null; } } - public virtual System.Collections.Generic.List? Members { get { throw null; } } + public virtual System.Collections.ObjectModel.ReadOnlyCollection DataMembers { get { throw null; } } public virtual Type OriginalUnderlyingType { get { throw null; } } public virtual System.Xml.XmlQualifiedName XmlName { get { throw null; } } [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers(DataContract.DataContractPreserveMemberTypes)] diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExporterApiTests.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExporterApiTests.cs index 75d6950630c74..6c52be44e00b0 100644 --- a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExporterApiTests.cs +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExporterApiTests.cs @@ -120,8 +120,11 @@ public static IEnumerable Export_MemberData() } }; // Export(ICollection) + // AppContext SetSwitch seems to be unreliable in the unit test case. So let's not rely on it + // for test coverage. But let's do look at the app switch to get our verification correct. + AppContext.TryGetSwitch("Switch.System.Runtime.Serialization.DataContracts.Auto_Import_KVP", out bool autoImportKVP); yield return new object[] { "Exp2", (XsdDataContractExporter exp) => exp.Export(new Assembly[] { typeof(DataContractTypes).Assembly }), (string s, XmlSchemaSet ss) => { - Assert.Equal(21, ss.Count); + Assert.Equal(autoImportKVP ? 21 : 20, ss.Count); } }; // Export(ICollection) From 4f555bcc4a33d6d02e73fdef213700d88959a835 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Fri, 12 Aug 2022 15:02:03 -0700 Subject: [PATCH 29/33] More PR feedback. --- .../Serialization/ClassDataContract.cs | 2 +- .../Serialization/CollectionDataContract.cs | 2 +- .../Runtime/Serialization/DataContract.cs | 27 +++++-------- .../src/System/Xml/XmlBaseWriter.cs | 14 +++---- .../src/System/Xml/XmlConverter.cs | 26 +++--------- .../src/System/Xml/XmlStreamNodeWriter.cs | 40 +++++++------------ .../Directory.Build.props | 1 + ...System.Runtime.Serialization.Schema.csproj | 3 -- .../Serialization/Schema/CodeExporter.cs | 16 ++++---- .../Schema/ContractCodeDomInfo.cs | 10 +++++ .../Schema/SchemaImportHelper.cs | 2 + .../ExporterApiTests.cs | 2 + 12 files changed, 62 insertions(+), 83 deletions(-) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs index 31ac83ec899cd..a395b82d6f99f 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs @@ -1309,7 +1309,7 @@ internal override DataContract BindGenericParameters(DataContract[] paramContrac xmlName = XmlName; genericParams = paramContracts; - // NOTE TODO smolloy - this type-binding ('boundType') stuff is new. We did not do this in NetFx. We used to use default constructors and let the + // This type-binding ('boundType') stuff is new. We did not do this in NetFx. We used to use default contract constructors and let the // underlying type get filled in later. But default constructors for DataContracts runs afoul of requiring an underlying type. Our web of nullable // notations make it hard to get around. But it also allows us to feel good about using .UnderlyingType from matching parameter contracts. Type[] underlyingParamTypes = new Type[paramContracts.Length]; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs index ed283a39aef22..948817e1d31a2 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs @@ -1329,7 +1329,7 @@ internal override DataContract BindGenericParameters(DataContract[] paramContrac if (boundContracts != null && boundContracts.TryGetValue(this, out boundContract!)) return boundContract; - // NOTE TODO smolloy - this type-binding ('boundType') stuff is new. We did not do this in NetFx. We used to use default constructors and let the + // This type-binding ('boundType') stuff is new. We did not do this in NetFx. We used to use default contract constructors and let the // underlying type get filled in later. But default constructors for DataContracts runs afoul of requiring an underlying type. Our web of nullable // notations make it hard to get around. But it also allows us to feel good about using .UnderlyingType from matching parameter contracts. Type type = UnderlyingType; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs index 743d45d26f8b6..d61002c23a123 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs @@ -996,7 +996,7 @@ internal DataContractCriticalHelper( [MemberNotNull(nameof(_typeForInitialization))] private void SetTypeForInitialization(Type classType) { - // NOTE TODO smolloy - This 'if' was not commented out in 4.8. But 4.8 was not dealing with nullable notations, which we do have here in Core. + // TODO - This 'if' was not commented out in 4.8. But 4.8 was not dealing with nullable notations, which we do have here in Core. // With the absence of schema importing, it does not make sense to have a data contract without a valid serializable underlying type. (Even // with schema importing it doesn't make sense, but there is a building period while we're still figuring out all the data types and contracts // where the underlying type may be null.) Anyway... might it make sense to re-instate this if clause - but use it to throw an exception if @@ -2011,27 +2011,18 @@ private static void ImportKnownTypeAttributes(Type? type, Dictionary } } + // After careful consideration, I don't think this code is necessary anymore. After trying to + // decipher the intent of the comments here, my best guess is that this was DCJS's way of working + // around a non-[Serializable] KVP in Silverlight/early .Net Core. The regular DCS went with a + // KVPAdapter approach. Neither is needed now. + // + // But this code does produce additional artifacts in schema handling. To be cautious, just in case + // somebody needs a KVP contract in addition to the KV contract in their schema, I've kept this + // here behind this AppContext switch. AppContext.TryGetSwitch("Switch.System.Runtime.Serialization.DataContracts.Auto_Import_KVP", out bool autoImportKVP); if (autoImportKVP) { //For Json we need to add KeyValuePair to KnownTypes if the UnderLyingType is a Dictionary - // - // ^^^ Years later I think this is referring to how we treat dictionaries as collections of the - // 'KeyValue' struct we have internally. But Json for some reason needed contracts for KeyValuePair - // as well. Possibly related to 'UseSimpleDictionaryFormat'? So we would import both KeyValue and KVP - // contracts and be happy. - // Years later, we've had and gotten rid of a KeyValuePair adapter, and I'm not sure I see a case where - // DCJS is failing with either dictionary format without this code. This seems extraneous at this - // point. Perhaps its there to bridge a potential mis-match between producer and consumer? - // - // - // Or, if I put more faith in the 'catch' comment - this was a case where DCSJ might have used - // an internal KV struct because KVP was missing [Serializable], but regular DCS was using a - // KVPAdapter class? And now KVP does have [Serializable] so we don't need either of those workarounds - // anymore. We already dropped KVPAdapter in this PR. We can probably drop this workaround as well. - // This seems the more likely explaination for this block. - // - // TODO smolloy - discuss potential removal of this altogether. try { if (DataContract.GetDataContract(type) is CollectionDataContract collectionDataContract && collectionDataContract.IsDictionary && diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBaseWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBaseWriter.cs index 5854851d304cd..d197af209fd8e 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBaseWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBaseWriter.cs @@ -1674,8 +1674,8 @@ public void StartFragment(Stream stream, bool generateSelfContainedTextFragment) } else { - _oldStream = ((XmlStreamNodeWriter)_signingWriter!.NodeWriter).Stream; - ((XmlStreamNodeWriter)_signingWriter.NodeWriter).Stream = stream; + _oldStream = ((XmlStreamNodeWriter)_signingWriter!.NodeWriter).OutputStream; + ((XmlStreamNodeWriter)_signingWriter.NodeWriter).OutputStream = stream; } } else @@ -1687,8 +1687,8 @@ public void StartFragment(Stream stream, bool generateSelfContainedTextFragment) } else { - _oldStream = _nodeWriter.Stream; - _nodeWriter.Stream = stream; + _oldStream = _nodeWriter.OutputStream; + _nodeWriter.OutputStream = stream; } } } @@ -1711,14 +1711,14 @@ public void EndFragment() if (_oldWriter != null) _signingWriter!.NodeWriter = _oldWriter; else - ((XmlStreamNodeWriter)_signingWriter!.NodeWriter).Stream = _oldStream!; // Checked above. _oldStream can't be null if _oldWriter is. + ((XmlStreamNodeWriter)_signingWriter!.NodeWriter).OutputStream = _oldStream!; // Checked above. _oldStream can't be null if _oldWriter is. } else { if (_oldWriter != null) _writer = _oldWriter; else - _nodeWriter.Stream = _oldStream!; // Checked above. _oldStream can't be null if _oldWriter is. + _nodeWriter.OutputStream = _oldStream!; // Checked above. _oldStream can't be null if _oldWriter is. } NamespaceBoundary = _oldNamespaceBoundary; _oldWriter = null; @@ -1744,7 +1744,7 @@ public void WriteFragment(byte[] buffer, int offset, int count) FlushElement(); FlushBase64(); _nodeWriter.Flush(); - _nodeWriter.Stream.Write(buffer, offset, count); + _nodeWriter.OutputStream.Write(buffer, offset, count); } private void FlushBase64() diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlConverter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlConverter.cs index e47b44cf49e4e..0a856e04e7f1c 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlConverter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlConverter.cs @@ -247,7 +247,7 @@ public static UniqueId ToUniqueId(string value) { try { - return new UniqueId(Trim(value)); + return new UniqueId(value.Trim()); } catch (ArgumentException exception) { @@ -293,7 +293,7 @@ public static Guid ToGuid(string value) { try { - return new Guid(Trim(value)); + return new Guid(value.Trim()); } catch (FormatException exception) { @@ -458,14 +458,14 @@ public static void ToQualifiedName(string qname, out string prefix, out string l if (index < 0) { prefix = string.Empty; - localName = Trim(qname); + localName = qname.Trim(); } else { if (index == qname.Length - 1) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.Format(SR.XmlInvalidQualifiedName, qname))); - prefix = Trim(qname.Substring(0, index)); - localName = Trim(qname.Substring(index + 1)); + prefix = qname.Substring(0, index).Trim(); + localName = qname.Substring(index + 1).Trim(); } } @@ -1134,21 +1134,5 @@ public static string StripWhitespace(string s) } }); } - - private static string Trim(string s) - { - int i; - for (i = 0; i < s.Length && IsWhitespace(s[i]); i++); - - int j; - for (j = s.Length; j > 0 && IsWhitespace(s[j - 1]); j--); - - if (i == 0 && j == s.Length) - return s; - else if (j == 0) - return string.Empty; - else - return s.Substring(i, j - i); - } } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlStreamNodeWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlStreamNodeWriter.cs index a62023e03d397..f5c218aa755c8 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlStreamNodeWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlStreamNodeWriter.cs @@ -10,7 +10,6 @@ namespace System.Xml { internal abstract class XmlStreamNodeWriter : XmlNodeWriter { - private Stream _stream = null!; // initialized by SetOutput private readonly byte[] _buffer; private int _offset; private bool _ownsStream; @@ -22,11 +21,12 @@ internal abstract class XmlStreamNodeWriter : XmlNodeWriter protected XmlStreamNodeWriter() { _buffer = new byte[bufferLength]; + OutputStream = null!; // Always initialized by SetOutput() } protected void SetOutput(Stream stream, bool ownsStream, Encoding? encoding) { - _stream = stream; + OutputStream = stream; _ownsStream = ownsStream; _offset = 0; @@ -35,17 +35,7 @@ protected void SetOutput(Stream stream, bool ownsStream, Encoding? encoding) } // Getting/Setting the Stream exists for fragmenting - public Stream Stream - { - get - { - return _stream; - } - set - { - _stream = value; - } - } + public Stream OutputStream { get; set; } // StreamBuffer/BufferOffset exists only for the BinaryWriter to fix up nodes public byte[] StreamBuffer @@ -67,7 +57,7 @@ public int Position { get { - return (int)_stream.Position + _offset; + return (int)OutputStream.Position + _offset; } } @@ -228,7 +218,7 @@ public void WriteBytes(byte[] byteBuffer, int byteOffset, int byteCount) else { FlushBuffer(); - _stream.Write(byteBuffer, byteOffset, byteCount); + OutputStream.Write(byteBuffer, byteOffset, byteCount); } } @@ -240,14 +230,14 @@ protected unsafe void UnsafeWriteBytes(byte* bytes, int byteCount) { for (int i = 0; i < bufferLength; i++) buffer[i] = bytes[i]; - _stream.Write(buffer, 0, bufferLength); + OutputStream.Write(buffer, 0, bufferLength); bytes += bufferLength; byteCount -= bufferLength; } { for (int i = 0; i < byteCount; i++) buffer[i] = bytes[i]; - _stream.Write(buffer, 0, byteCount); + OutputStream.Write(buffer, 0, byteCount); } } @@ -285,7 +275,7 @@ protected void WriteUTF8Chars(byte[] chars, int charOffset, int charCount) else { FlushBuffer(); - _stream.Write(chars, charOffset, charCount); + OutputStream.Write(chars, charOffset, charCount); } } @@ -423,7 +413,7 @@ protected virtual void FlushBuffer() { if (_offset != 0) { - _stream.Write(_buffer, 0, _offset); + OutputStream.Write(_buffer, 0, _offset); _offset = 0; } } @@ -432,7 +422,7 @@ protected virtual Task FlushBufferAsync() { if (_offset != 0) { - var task = _stream.WriteAsync(_buffer, 0, _offset); + var task = OutputStream.WriteAsync(_buffer, 0, _offset); _offset = 0; return task; } @@ -443,24 +433,24 @@ protected virtual Task FlushBufferAsync() public override void Flush() { FlushBuffer(); - _stream.Flush(); + OutputStream.Flush(); } public override async Task FlushAsync() { await FlushBufferAsync().ConfigureAwait(false); - await _stream.FlushAsync().ConfigureAwait(false); + await OutputStream.FlushAsync().ConfigureAwait(false); } public override void Close() { - if (_stream != null) + if (OutputStream != null) { if (_ownsStream) { - _stream.Dispose(); + OutputStream.Dispose(); } - _stream = null!; + OutputStream = null!; } } } diff --git a/src/libraries/System.Runtime.Serialization.Schema/Directory.Build.props b/src/libraries/System.Runtime.Serialization.Schema/Directory.Build.props index 72712f3351c12..4a2bc78c16e30 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/Directory.Build.props +++ b/src/libraries/System.Runtime.Serialization.Schema/Directory.Build.props @@ -2,6 +2,7 @@ true + browser;ios;tvos;maccatalyst \ No newline at end of file diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj b/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj index 1629d7f071f76..d1d5600805109 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System.Runtime.Serialization.Schema.csproj @@ -1,10 +1,7 @@ $(NetCoreAppCurrent) - true Microsoft - false - true true Provides support for importing and exporting xsd schemas for DataContractSerializer. diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs index 6b84d07b7a630..45476be4423f1 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/CodeExporter.cs @@ -301,7 +301,7 @@ private void InvokeProcessImportedType(CollectionBase collection, ISerialization InvokeProcessImportedType(newCodeTypeDeclaration.Members, surrogateProvider); } } - } + } [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] internal CodeTypeReference GetCodeTypeReference(DataContract dataContract) @@ -323,6 +323,7 @@ private CodeTypeReference GetCodeTypeReference(Type type) return new CodeTypeReference(type); } + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private CodeTypeReference? GetCodeTypeReference(Type type, IList? parameters) { CodeTypeReference codeTypeReference = GetCodeTypeReference(type); @@ -660,7 +661,7 @@ private bool TryGetReferencedDictionaryType(DataContract collectionContract, [No // A dictionary should have a Key/Value item contract that has at least two members: key and value. Debug.Assert(itemContract != null); - Debug.Assert(itemContract.DataMembers.Count > 1); + Debug.Assert(itemContract.DataMembers.Count >= 2); DataMember keyMember = itemContract.DataMembers[0]; DataMember valueMember = itemContract.DataMembers[1]; @@ -708,6 +709,7 @@ private bool TryGetReferencedListType(DataContract itemContract, bool isItemType return null; } + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] private Type? GetReferencedTypeOnImport(DataContract dataContract) { Type? type = null; @@ -1023,10 +1025,10 @@ private void AddExtensionData(ContractCodeDomInfo contractCodeDomInfo) extensionDataObjectField.CustomAttributes.Add(nonSerializedAttribute); } type.Members.Add(extensionDataObjectField); - contractCodeDomInfo.GetMemberNames().Add(extensionDataObjectField.Name); + contractCodeDomInfo.AddMemberName(extensionDataObjectField.Name); CodeMemberProperty extensionDataObjectProperty = ExtensionDataObjectProperty; type.Members.Add(extensionDataObjectProperty); - contractCodeDomInfo.GetMemberNames().Add(extensionDataObjectProperty.Name); + contractCodeDomInfo.AddMemberName(extensionDataObjectProperty.Name); } } @@ -1042,8 +1044,8 @@ private void AddPropertyChangedNotifier(ContractCodeDomInfo contractCodeDomInfo, if (!isValueType) raisePropertyChangedEventMethod.Attributes |= MemberAttributes.Family; codeTypeDeclaration.Members.Add(raisePropertyChangedEventMethod); - contractCodeDomInfo.GetMemberNames().Add(memberEvent.Name); - contractCodeDomInfo.GetMemberNames().Add(raisePropertyChangedEventMethod.Name); + contractCodeDomInfo.AddMemberName(memberEvent.Name); + contractCodeDomInfo.AddMemberName(raisePropertyChangedEventMethod.Name); } } @@ -1389,7 +1391,7 @@ private static string GetMemberName(string memberName, ContractCodeDomInfo contr } } - contractCodeDomInfo.GetMemberNames().Add(memberName); + contractCodeDomInfo.AddMemberName(memberName); return memberName; } diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs index 36b4bee087693..809978d33b29b 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs @@ -4,6 +4,7 @@ using System; using System.CodeDom; using System.Collections.Generic; +using System.Diagnostics; using System.Xml; using System.Xml.Schema; @@ -50,5 +51,14 @@ internal HashSet GetMemberNames() else return _memberNames ??= new HashSet(StringComparer.OrdinalIgnoreCase); } + + internal bool AddMemberName(string memberName) + { + HashSet names = GetMemberNames(); + + // If the name already exists, 4.8 threw an exception because the backing collection type was Dictionary + Debug.Assert(!names.Contains(memberName)); + return names.Add(memberName); + } } } diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaImportHelper.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaImportHelper.cs index 5803fadc077ac..a268f8ef79266 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaImportHelper.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/SchemaImportHelper.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; using System.Runtime.Serialization.DataContracts; using System.Xml; @@ -40,6 +41,7 @@ internal static bool Is(this DataContract dataContract, DataContractType dcType) return null; } + [RequiresUnreferencedCode(ImportGlobals.SerializerTrimmerWarning)] internal static bool IsItemTypeNullable(this DataContract collectionDataContract) { if (collectionDataContract.GetContractType() == DataContractType.CollectionDataContract) diff --git a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExporterApiTests.cs b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExporterApiTests.cs index 6c52be44e00b0..03e2c5f5a918b 100644 --- a/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExporterApiTests.cs +++ b/src/libraries/System.Runtime.Serialization.Xml/tests/XsdDataContractExporterTests/ExporterApiTests.cs @@ -125,6 +125,8 @@ public static IEnumerable Export_MemberData() AppContext.TryGetSwitch("Switch.System.Runtime.Serialization.DataContracts.Auto_Import_KVP", out bool autoImportKVP); yield return new object[] { "Exp2", (XsdDataContractExporter exp) => exp.Export(new Assembly[] { typeof(DataContractTypes).Assembly }), (string s, XmlSchemaSet ss) => { Assert.Equal(autoImportKVP ? 21 : 20, ss.Count); + Assert.Equal(autoImportKVP ? 171 : 163, ss.GlobalTypes.Count); + Assert.Equal(autoImportKVP ? 204 : 196, ss.GlobalElements.Count); } }; // Export(ICollection) From 80fd11b46a2cf9ada434b8a1e6cf2b7ecc02afe2 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Fri, 12 Aug 2022 15:11:20 -0700 Subject: [PATCH 30/33] Nudge Azure pipelines again. :( --- .../System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs index 809978d33b29b..6603b3080be96 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs @@ -56,7 +56,7 @@ internal bool AddMemberName(string memberName) { HashSet names = GetMemberNames(); - // If the name already exists, 4.8 threw an exception because the backing collection type was Dictionary + // If the name already exists, 4.8 threw an exception because the backing collection type was Dictionary. Debug.Assert(!names.Contains(memberName)); return names.Add(memberName); } From f8ebd1a04f41c1f1cf9856307d4510902fb45f48 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Fri, 12 Aug 2022 16:38:08 -0700 Subject: [PATCH 31/33] nudge --- .../System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs index 6603b3080be96..809978d33b29b 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs +++ b/src/libraries/System.Runtime.Serialization.Schema/src/System/Runtime/Serialization/Schema/ContractCodeDomInfo.cs @@ -56,7 +56,7 @@ internal bool AddMemberName(string memberName) { HashSet names = GetMemberNames(); - // If the name already exists, 4.8 threw an exception because the backing collection type was Dictionary. + // If the name already exists, 4.8 threw an exception because the backing collection type was Dictionary Debug.Assert(!names.Contains(memberName)); return names.Add(memberName); } From 01517c7e04fcec8fe6f4f064bcdae26e2cfda774 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Fri, 12 Aug 2022 17:15:32 -0700 Subject: [PATCH 32/33] nudge again. --- .../System.Runtime.Serialization.Schema/Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.Serialization.Schema/Directory.Build.props b/src/libraries/System.Runtime.Serialization.Schema/Directory.Build.props index 4a2bc78c16e30..de1ad70191154 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/Directory.Build.props +++ b/src/libraries/System.Runtime.Serialization.Schema/Directory.Build.props @@ -5,4 +5,4 @@ browser;ios;tvos;maccatalyst - \ No newline at end of file + From b7100af18f5461993a45e4b85773bc55700571b9 Mon Sep 17 00:00:00 2001 From: Steve Molloy Date: Fri, 12 Aug 2022 20:02:55 -0700 Subject: [PATCH 33/33] One more nudge. --- .../System.Runtime.Serialization.Schema/Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.Serialization.Schema/Directory.Build.props b/src/libraries/System.Runtime.Serialization.Schema/Directory.Build.props index de1ad70191154..4a2bc78c16e30 100644 --- a/src/libraries/System.Runtime.Serialization.Schema/Directory.Build.props +++ b/src/libraries/System.Runtime.Serialization.Schema/Directory.Build.props @@ -5,4 +5,4 @@ browser;ios;tvos;maccatalyst - + \ No newline at end of file