Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit f86236c

Browse files
authored
Fix DCS_ResolveNameReturnsEmptyNamespace. (#19631)
* Fix DCS_ResolveNameReturnsEmptyNamespace. Fix #19629 * Updated comments. * Updated the comments. * Refactor the fix. * minor change
1 parent 1c9342b commit f86236c

File tree

2 files changed

+104
-46
lines changed

2 files changed

+104
-46
lines changed

src/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,23 @@ internal ClassDataContractCriticalHelper(Type type) : base(type)
776776
this.IsValueType = type.IsValueType;
777777
if (baseType != null && baseType != Globals.TypeOfObject && baseType != Globals.TypeOfValueType && baseType != Globals.TypeOfUri)
778778
{
779+
// dotnet/corefx#19629: a DataContract created at runtime does not work with the base DataContract
780+
// pre-generated by SG. It's because the runtime DataContract requires full information of a base DataContract
781+
// while a pre-generated DataContract is incomplete.
782+
//
783+
// At this point in code, we're in the midlle of creating a new DataContract at runtime, so we need to make
784+
// sure that we create our own base type DataContract when the base type could potentially have SG generated
785+
// DataContract.
786+
//
787+
// We wanted to enable the fix for the issue described above only when SG generated DataContracts are available.
788+
// Currently we don't have a good way of detecting usage of SG (either globally or per data contract).
789+
// But since SG is currently only used by .NET Native, so we used the "#if uapaot" to target the fix for .Net
790+
// Native only.
791+
#if uapaot
792+
DataContract baseContract = DataContract.GetDataContractCreatedAtRuntime(baseType);
793+
#else
779794
DataContract baseContract = DataContract.GetDataContract(baseType);
795+
#endif
780796
if (baseContract is CollectionDataContract)
781797
this.BaseContract = ((CollectionDataContract)baseContract).SharedTypeContract as ClassDataContract;
782798
else
@@ -1118,6 +1134,7 @@ private void SetIfMembersHaveConflict(List<DataMember> members)
11181134
while (currContract != null)
11191135
{
11201136
baseTypeIndex++;
1137+
11211138
foreach (DataMember member in currContract.Members)
11221139
{
11231140
membersInHierarchy.Add(new Member(member, currContract.StableName.Namespace, baseTypeIndex));

src/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs

Lines changed: 87 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ namespace System.Runtime.Serialization
1515
using System.Runtime.CompilerServices;
1616
using System.Linq;
1717
using Xml.Schema;
18+
using System.Collections.Concurrent;
1819

1920
#if USE_REFEMIT || uapaot
2021
public abstract class DataContract
@@ -64,6 +65,8 @@ internal static DataContract GetDataContractFromGeneratedAssembly(Type type)
6465
{
6566
return null;
6667
}
68+
69+
type = GetDataContractAdapterTypeForGeneratedAssembly(type);
6770
DataContract dataContract = GetGeneratedDataContract(type);
6871
if (dataContract == null)
6972
{
@@ -92,6 +95,20 @@ internal static DataContract GetDataContractFromGeneratedAssembly(Type type)
9295
#endif
9396
}
9497

98+
#if uapaot
99+
// This method returns adapter types used to get DataContract from
100+
// generated assembly.
101+
private static Type GetDataContractAdapterTypeForGeneratedAssembly(Type type)
102+
{
103+
if (type == Globals.TypeOfDateTimeOffset)
104+
{
105+
return Globals.TypeOfDateTimeOffsetAdapter;
106+
}
107+
108+
return type;
109+
}
110+
#endif
111+
95112
internal MethodInfo ParseMethod
96113
{
97114
get { return _helper.ParseMethod; }
@@ -124,6 +141,13 @@ internal static DataContract GetDataContractSkipValidation(int id, RuntimeTypeHa
124141
{
125142
return DataContractCriticalHelper.GetDataContractSkipValidation(id, typeHandle, type);
126143
}
144+
#if uapaot
145+
internal static DataContract GetDataContractCreatedAtRuntime(Type type, SerializationMode mode = SerializationMode.SharedContract)
146+
{
147+
DataContract dataContract = DataContractCriticalHelper.GetDataContractCreatedAtRuntime(type);
148+
return dataContract.GetValidContract(mode);
149+
}
150+
#endif
127151

128152
internal static DataContract GetGetOnlyCollectionDataContract(int id, RuntimeTypeHandle typeHandle, Type type, SerializationMode mode)
129153
{
@@ -380,6 +404,9 @@ internal class DataContractCriticalHelper
380404
{
381405
private static Dictionary<TypeHandleRef, IntRef> s_typeToIDCache = new Dictionary<TypeHandleRef, IntRef>(new TypeHandleRefEqualityComparer());
382406
private static DataContract[] s_dataContractCache = new DataContract[32];
407+
#if uapaot
408+
private static ConcurrentDictionary<Type, DataContract> s_dataContractCacheCreatedAtRuntime = new ConcurrentDictionary<Type, DataContract>();
409+
#endif
383410
private static int s_dataContractID;
384411
private static Dictionary<Type, DataContract> s_typeToBuiltInContract;
385412
private static Dictionary<XmlQualifiedName, DataContract> s_nameToBuiltInContract;
@@ -431,6 +458,23 @@ internal static DataContract GetDataContractSkipValidation(int id, RuntimeTypeHa
431458
return dataContract;
432459
}
433460

461+
#if uapaot
462+
internal static DataContract GetDataContractCreatedAtRuntime(Type type)
463+
{
464+
if (type == null)
465+
{
466+
throw new ArgumentNullException(nameof(type));
467+
}
468+
469+
DataContract dataContract = s_dataContractCacheCreatedAtRuntime.GetOrAdd(type, (t) =>
470+
{
471+
return CreateDataContract(t);
472+
});
473+
474+
return dataContract.GetValidContract();
475+
}
476+
#endif
477+
434478
internal static DataContract GetGetOnlyCollectionDataContractSkipValidation(int id, RuntimeTypeHandle typeHandle, Type type)
435479
{
436480
#if uapaot
@@ -534,55 +578,64 @@ private static DataContract CreateDataContract(int id, RuntimeTypeHandle typeHan
534578
type = Type.GetTypeFromHandle(typeHandle);
535579

536580
type = UnwrapNullableType(type);
537-
var originalType = type;
538581

539-
type = GetDataContractAdapterTypeForGeneratedAssembly(type);
540582
dataContract = DataContract.GetDataContractFromGeneratedAssembly(type);
541583
if (dataContract != null)
542584
{
543585
AssignDataContractToId(dataContract, id);
544586
return dataContract;
545587
}
546588

547-
type = GetDataContractAdapterType(type);
548-
dataContract = GetBuiltInDataContract(type);
549-
if (dataContract == null)
589+
dataContract = CreateDataContract(type);
590+
}
591+
}
592+
}
593+
594+
return dataContract;
595+
}
596+
597+
private static DataContract CreateDataContract(Type type)
598+
{
599+
type = UnwrapNullableType(type);
600+
Type originalType = type;
601+
type = GetDataContractAdapterType(type);
602+
603+
DataContract dataContract = GetBuiltInDataContract(type);
604+
if (dataContract == null)
605+
{
606+
if (type.IsArray)
607+
dataContract = new CollectionDataContract(type);
608+
else if (type.IsEnum)
609+
dataContract = new EnumDataContract(type);
610+
else if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type))
611+
dataContract = new XmlDataContract(type);
612+
else if (Globals.TypeOfScriptObject_IsAssignableFrom(type))
613+
dataContract = Globals.CreateScriptObjectClassDataContract();
614+
else
615+
{
616+
//if (type.ContainsGenericParameters)
617+
// ThrowInvalidDataContractException(SR.Format(SR.TypeMustNotBeOpenGeneric, type), type);
618+
619+
if (!CollectionDataContract.TryCreate(type, out dataContract))
620+
{
621+
if (!type.IsSerializable && !type.IsDefined(Globals.TypeOfDataContractAttribute, false) && !ClassDataContract.IsNonAttributedTypeValidForSerialization(type) && !ClassDataContract.IsKnownSerializableType(type))
622+
{
623+
ThrowInvalidDataContractException(SR.Format(SR.TypeNotSerializable, type), type);
624+
}
625+
dataContract = new ClassDataContract(type);
626+
if (type != originalType)
550627
{
551-
if (type.IsArray)
552-
dataContract = new CollectionDataContract(type);
553-
else if (type.IsEnum)
554-
dataContract = new EnumDataContract(type);
555-
else if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type))
556-
dataContract = new XmlDataContract(type);
557-
else if (Globals.TypeOfScriptObject_IsAssignableFrom(type))
558-
dataContract = Globals.CreateScriptObjectClassDataContract();
559-
else
628+
var originalDataContract = new ClassDataContract(originalType);
629+
if (dataContract.StableName != originalDataContract.StableName)
560630
{
561-
//if (type.ContainsGenericParameters)
562-
// ThrowInvalidDataContractException(SR.Format(SR.TypeMustNotBeOpenGeneric, type), type);
563-
564-
if (!CollectionDataContract.TryCreate(type, out dataContract))
565-
{
566-
if (!type.IsSerializable && !type.IsDefined(Globals.TypeOfDataContractAttribute, false) && !ClassDataContract.IsNonAttributedTypeValidForSerialization(type) && !ClassDataContract.IsKnownSerializableType(type))
567-
{
568-
ThrowInvalidDataContractException(SR.Format(SR.TypeNotSerializable, type), type);
569-
}
570-
dataContract = new ClassDataContract(type);
571-
if (type != originalType)
572-
{
573-
var originalDataContract = new ClassDataContract(originalType);
574-
if (dataContract.StableName != originalDataContract.StableName)
575-
{
576-
// for non-DC types, type adapters will not have the same stable name (contract name).
577-
dataContract.StableName = originalDataContract.StableName;
578-
}
579-
}
580-
}
631+
// for non-DC types, type adapters will not have the same stable name (contract name).
632+
dataContract.StableName = originalDataContract.StableName;
581633
}
582634
}
583635
}
584636
}
585637
}
638+
586639
return dataContract;
587640
}
588641

@@ -616,18 +669,6 @@ private static DataContract CreateGetOnlyCollectionDataContract(int id, RuntimeT
616669
return dataContract;
617670
}
618671

619-
// This method returns adapter types used to get DataContract from
620-
// generated assembly.
621-
private static Type GetDataContractAdapterTypeForGeneratedAssembly(Type type)
622-
{
623-
if (type == Globals.TypeOfDateTimeOffset)
624-
{
625-
return Globals.TypeOfDateTimeOffsetAdapter;
626-
}
627-
628-
return type;
629-
}
630-
631672
// This method returns adapter types used at runtime to create DataContract.
632673
internal static Type GetDataContractAdapterType(Type type)
633674
{

0 commit comments

Comments
 (0)