| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418 |
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Xml;
- using System.Reflection;
- using System.ServiceModel;
- using System.Collections;
- namespace System.Runtime.Serialization.Json
- {
- #if USE_REFEMIT
- public class XmlObjectSerializerWriteContextComplexJson : XmlObjectSerializerWriteContextComplex
- #else
- internal class XmlObjectSerializerWriteContextComplexJson : XmlObjectSerializerWriteContextComplex
- #endif
- {
- EmitTypeInformation emitXsiType;
- bool perCallXsiTypeAlreadyEmitted;
- bool useSimpleDictionaryFormat;
- public XmlObjectSerializerWriteContextComplexJson(DataContractJsonSerializer serializer, DataContract rootTypeDataContract)
- : base(serializer,
- serializer.MaxItemsInObjectGraph,
- new StreamingContext(StreamingContextStates.All),
- serializer.IgnoreExtensionDataObject)
- {
- this.emitXsiType = serializer.EmitTypeInformation;
- this.rootTypeDataContract = rootTypeDataContract;
- this.serializerKnownTypeList = serializer.knownTypeList;
- this.dataContractSurrogate = serializer.DataContractSurrogate;
- this.serializeReadOnlyTypes = serializer.SerializeReadOnlyTypes;
- this.useSimpleDictionaryFormat = serializer.UseSimpleDictionaryFormat;
- }
- internal static XmlObjectSerializerWriteContextComplexJson CreateContext(DataContractJsonSerializer serializer, DataContract rootTypeDataContract)
- {
- return new XmlObjectSerializerWriteContextComplexJson(serializer, rootTypeDataContract);
- }
- internal IList<Type> SerializerKnownTypeList
- {
- get
- {
- return this.serializerKnownTypeList;
- }
- }
- public bool UseSimpleDictionaryFormat
- {
- get
- {
- return this.useSimpleDictionaryFormat;
- }
- }
- internal override bool WriteClrTypeInfo(XmlWriterDelegator xmlWriter, Type dataContractType, string clrTypeName, string clrAssemblyName)
- {
- return false;
- }
- internal override bool WriteClrTypeInfo(XmlWriterDelegator xmlWriter, DataContract dataContract)
- {
- return false;
- }
- internal override void WriteArraySize(XmlWriterDelegator xmlWriter, int size)
- {
- }
- protected override void WriteTypeInfo(XmlWriterDelegator writer, string dataContractName, string dataContractNamespace)
- {
- if (this.emitXsiType != EmitTypeInformation.Never)
- {
- if (string.IsNullOrEmpty(dataContractNamespace))
- {
- WriteTypeInfo(writer, dataContractName);
- }
- else
- {
- WriteTypeInfo(writer, string.Concat(dataContractName, JsonGlobals.NameValueSeparatorString, TruncateDefaultDataContractNamespace(dataContractNamespace)));
- }
- }
- }
- internal static string TruncateDefaultDataContractNamespace(string dataContractNamespace)
- {
- if (!string.IsNullOrEmpty(dataContractNamespace))
- {
- if (dataContractNamespace[0] == '#')
- {
- return string.Concat("\\", dataContractNamespace);
- }
- else if (dataContractNamespace[0] == '\\')
- {
- return string.Concat("\\", dataContractNamespace);
- }
- else if (dataContractNamespace.StartsWith(Globals.DataContractXsdBaseNamespace, StringComparison.Ordinal))
- {
- return string.Concat("#", dataContractNamespace.Substring(JsonGlobals.DataContractXsdBaseNamespaceLength));
- }
- }
- return dataContractNamespace;
- }
- static bool RequiresJsonTypeInfo(DataContract contract)
- {
- return (contract is ClassDataContract);
- }
- void WriteTypeInfo(XmlWriterDelegator writer, string typeInformation)
- {
- writer.WriteAttributeString(null, JsonGlobals.serverTypeString, null, typeInformation);
- }
- protected override bool WriteTypeInfo(XmlWriterDelegator writer, DataContract contract, DataContract declaredContract)
- {
- if (!((object.ReferenceEquals(contract.Name, declaredContract.Name) &&
- object.ReferenceEquals(contract.Namespace, declaredContract.Namespace)) ||
- (contract.Name.Value == declaredContract.Name.Value &&
- contract.Namespace.Value == declaredContract.Namespace.Value)) &&
- (contract.UnderlyingType != Globals.TypeOfObjectArray) &&
- (this.emitXsiType != EmitTypeInformation.Never))
- {
- // We always deserialize collections assigned to System.Object as object[]
- // Because of its common and JSON-specific nature,
- // we don't want to validate known type information for object[]
- // Don't validate known type information when emitXsiType == Never because
- // known types are not used without type information in the JSON
- if (RequiresJsonTypeInfo(contract))
- {
- perCallXsiTypeAlreadyEmitted = true;
- WriteTypeInfo(writer, contract.Name.Value, contract.Namespace.Value);
- }
- else
- {
- // check if the declared type is System.Enum and throw because
- // __type information cannot be written for enums since it results in invalid JSON.
- // Without __type, the resulting JSON cannot be deserialized since a number cannot be directly assigned to System.Enum.
- if (declaredContract.UnderlyingType == typeof(Enum))
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SerializationException
- (SR.GetString(SR.EnumTypeNotSupportedByDataContractJsonSerializer, declaredContract.UnderlyingType)));
- }
- }
- // Return true regardless of whether we actually wrote __type information
- // E.g. We don't write __type information for enums, but we still want verifyKnownType
- // to be true for them.
- return true;
- }
- return false;
- }
- #if USE_REFEMIT
- public void WriteJsonISerializable(XmlWriterDelegator xmlWriter, ISerializable obj)
- #else
- internal void WriteJsonISerializable(XmlWriterDelegator xmlWriter, ISerializable obj)
- #endif
- {
- Type objType = obj.GetType();
- SerializationInfo serInfo = new SerializationInfo(objType, XmlObjectSerializer.FormatterConverter);
- GetObjectData(obj, serInfo, GetStreamingContext());
- if (DataContract.GetClrTypeFullName(objType) != serInfo.FullTypeName)
- {
- throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.ChangingFullTypeNameNotSupported, serInfo.FullTypeName, DataContract.GetClrTypeFullName(objType))));
- }
- else
- {
- base.WriteSerializationInfo(xmlWriter, objType, serInfo);
- }
- }
- #if USE_REFEMIT
- public static DataContract GetRevisedItemContract(DataContract oldItemContract)
- #else
- internal static DataContract GetRevisedItemContract(DataContract oldItemContract)
- #endif
- {
- if ((oldItemContract != null) &&
- oldItemContract.UnderlyingType.IsGenericType &&
- (oldItemContract.UnderlyingType.GetGenericTypeDefinition() == Globals.TypeOfKeyValue))
- {
- return DataContract.GetDataContract(oldItemContract.UnderlyingType);
- }
- return oldItemContract;
- }
- protected override void WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, object obj, RuntimeTypeHandle declaredTypeHandle)
- {
- JsonDataContract jsonDataContract = JsonDataContract.GetJsonDataContract(dataContract);
- if (emitXsiType == EmitTypeInformation.Always && !perCallXsiTypeAlreadyEmitted && RequiresJsonTypeInfo(dataContract))
- {
- WriteTypeInfo(xmlWriter, jsonDataContract.TypeName);
- }
- perCallXsiTypeAlreadyEmitted = false;
- DataContractJsonSerializer.WriteJsonValue(jsonDataContract, xmlWriter, obj, this, declaredTypeHandle);
- }
- protected override void WriteNull(XmlWriterDelegator xmlWriter)
- {
- DataContractJsonSerializer.WriteJsonNull(xmlWriter);
- }
- #if USE_REFEMIT
- public XmlDictionaryString CollectionItemName
- #else
- internal XmlDictionaryString CollectionItemName
- #endif
- {
- get { return JsonGlobals.itemDictionaryString; }
- }
- #if USE_REFEMIT
- public static void WriteJsonNameWithMapping(XmlWriterDelegator xmlWriter, XmlDictionaryString[] memberNames, int index)
- #else
- internal static void WriteJsonNameWithMapping(XmlWriterDelegator xmlWriter, XmlDictionaryString[] memberNames, int index)
- #endif
- {
- xmlWriter.WriteStartElement("a", JsonGlobals.itemString, JsonGlobals.itemString);
- xmlWriter.WriteAttributeString(null, JsonGlobals.itemString, null, memberNames[index].Value);
- }
- internal override void WriteExtensionDataTypeInfo(XmlWriterDelegator xmlWriter, IDataNode dataNode)
- {
- Type dataType = dataNode.DataType;
- if (dataType == Globals.TypeOfClassDataNode ||
- dataType == Globals.TypeOfISerializableDataNode)
- {
- xmlWriter.WriteAttributeString(null, JsonGlobals.typeString, null, JsonGlobals.objectString);
- base.WriteExtensionDataTypeInfo(xmlWriter, dataNode);
- }
- else if (dataType == Globals.TypeOfCollectionDataNode)
- {
- xmlWriter.WriteAttributeString(null, JsonGlobals.typeString, null, JsonGlobals.arrayString);
- // Don't write __type for collections
- }
- else if (dataType == Globals.TypeOfXmlDataNode)
- {
- // Don't write type or __type for XML types because we serialize them to strings
- }
- else if ((dataType == Globals.TypeOfObject) && (dataNode.Value != null))
- {
- DataContract dc = GetDataContract(dataNode.Value.GetType());
- if (RequiresJsonTypeInfo(dc))
- {
- base.WriteExtensionDataTypeInfo(xmlWriter, dataNode);
- }
- }
- }
- protected override void SerializeWithXsiType(XmlWriterDelegator xmlWriter, object obj, RuntimeTypeHandle objectTypeHandle, Type objectType, int declaredTypeID, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
- {
- DataContract dataContract;
- bool verifyKnownType = false;
- bool isDeclaredTypeInterface = declaredType.IsInterface;
- if (isDeclaredTypeInterface && CollectionDataContract.IsCollectionInterface(declaredType))
- {
- dataContract = GetDataContract(declaredTypeHandle, declaredType);
- }
- else if (declaredType.IsArray) // If declared type is array do not write __serverType. Instead write__serverType for each item
- {
- dataContract = GetDataContract(declaredTypeHandle, declaredType);
- }
- else
- {
- dataContract = GetDataContract(objectTypeHandle, objectType);
- DataContract declaredTypeContract = (declaredTypeID >= 0)
- ? GetDataContract(declaredTypeID, declaredTypeHandle)
- : GetDataContract(declaredTypeHandle, declaredType);
- verifyKnownType = WriteTypeInfo(xmlWriter, dataContract, declaredTypeContract);
- HandleCollectionAssignedToObject(declaredType, ref dataContract, ref obj, ref verifyKnownType);
- }
- if (isDeclaredTypeInterface)
- {
- VerifyObjectCompatibilityWithInterface(dataContract, obj, declaredType);
- }
- SerializeAndVerifyType(dataContract, xmlWriter, obj, verifyKnownType, declaredType.TypeHandle, declaredType);
- }
- static void VerifyObjectCompatibilityWithInterface(DataContract contract, object graph, Type declaredType)
- {
- Type contractType = contract.GetType();
- if ((contractType == typeof(XmlDataContract)) && !Globals.TypeOfIXmlSerializable.IsAssignableFrom(declaredType))
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.XmlObjectAssignedToIncompatibleInterface, graph.GetType(), declaredType)));
- }
- if ((contractType == typeof(CollectionDataContract)) && !CollectionDataContract.IsCollectionInterface(declaredType))
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.CollectionAssignedToIncompatibleInterface, graph.GetType(), declaredType)));
- }
- }
- void HandleCollectionAssignedToObject(Type declaredType, ref DataContract dataContract, ref object obj, ref bool verifyKnownType)
- {
- if ((declaredType != dataContract.UnderlyingType) && (dataContract is CollectionDataContract))
- {
- if (verifyKnownType)
- {
- VerifyType(dataContract, declaredType);
- verifyKnownType = false;
- }
- if (((CollectionDataContract)dataContract).Kind == CollectionKind.Dictionary)
- {
- // Convert non-generic dictionary to generic dictionary
- IDictionary dictionaryObj = obj as IDictionary;
- Dictionary<object, object> genericDictionaryObj = new Dictionary<object, object>();
- foreach (DictionaryEntry entry in dictionaryObj)
- {
- genericDictionaryObj.Add(entry.Key, entry.Value);
- }
- obj = genericDictionaryObj;
- }
- dataContract = GetDataContract(Globals.TypeOfIEnumerable);
- }
- }
- internal override void SerializeWithXsiTypeAtTopLevel(DataContract dataContract, XmlWriterDelegator xmlWriter, object obj, RuntimeTypeHandle originalDeclaredTypeHandle, Type graphType)
- {
- bool verifyKnownType = false;
- Type declaredType = rootTypeDataContract.UnderlyingType;
- bool isDeclaredTypeInterface = declaredType.IsInterface;
- if (!(isDeclaredTypeInterface && CollectionDataContract.IsCollectionInterface(declaredType))
- && !declaredType.IsArray)//Array covariance is not supported in XSD. If declared type is array do not write xsi:type. Instead write xsi:type for each item
- {
- verifyKnownType = WriteTypeInfo(xmlWriter, dataContract, rootTypeDataContract);
- HandleCollectionAssignedToObject(declaredType, ref dataContract, ref obj, ref verifyKnownType);
- }
- if (isDeclaredTypeInterface)
- {
- VerifyObjectCompatibilityWithInterface(dataContract, obj, declaredType);
- }
- SerializeAndVerifyType(dataContract, xmlWriter, obj, verifyKnownType, declaredType.TypeHandle, declaredType);
- }
- void VerifyType(DataContract dataContract, Type declaredType)
- {
- bool knownTypesAddedInCurrentScope = false;
- if (dataContract.KnownDataContracts != null)
- {
- scopedKnownTypes.Push(dataContract.KnownDataContracts);
- knownTypesAddedInCurrentScope = true;
- }
- if (!IsKnownType(dataContract, declaredType))
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.DcTypeNotFoundOnSerialize, DataContract.GetClrTypeFullName(dataContract.UnderlyingType), dataContract.StableName.Name, dataContract.StableName.Namespace)));
- }
- if (knownTypesAddedInCurrentScope)
- {
- scopedKnownTypes.Pop();
- }
- }
- internal override DataContract GetDataContract(RuntimeTypeHandle typeHandle, Type type)
- {
- DataContract dataContract = base.GetDataContract(typeHandle, type);
- DataContractJsonSerializer.CheckIfTypeIsReference(dataContract);
- return dataContract;
- }
- internal override DataContract GetDataContractSkipValidation(int typeId, RuntimeTypeHandle typeHandle, Type type)
- {
- DataContract dataContract = base.GetDataContractSkipValidation(typeId, typeHandle, type);
- DataContractJsonSerializer.CheckIfTypeIsReference(dataContract);
- return dataContract;
- }
- internal override DataContract GetDataContract(int id, RuntimeTypeHandle typeHandle)
- {
- DataContract dataContract = base.GetDataContract(id, typeHandle);
- DataContractJsonSerializer.CheckIfTypeIsReference(dataContract);
- return dataContract;
- }
- internal static DataContract ResolveJsonDataContractFromRootDataContract(XmlObjectSerializerContext context, XmlQualifiedName typeQName, DataContract rootTypeDataContract)
- {
- if (rootTypeDataContract.StableName == typeQName)
- return rootTypeDataContract;
- CollectionDataContract collectionContract = rootTypeDataContract as CollectionDataContract;
- while (collectionContract != null)
- {
- DataContract itemContract;
- if (collectionContract.ItemType.IsGenericType
- && collectionContract.ItemType.GetGenericTypeDefinition() == typeof(KeyValue<,>))
- {
- itemContract = context.GetDataContract(Globals.TypeOfKeyValuePair.MakeGenericType(collectionContract.ItemType.GetGenericArguments()));
- }
- else
- {
- itemContract = context.GetDataContract(context.GetSurrogatedType(collectionContract.ItemType));
- }
- if (itemContract.StableName == typeQName)
- {
- return itemContract;
- }
- collectionContract = itemContract as CollectionDataContract;
- }
- return null;
- }
- protected override DataContract ResolveDataContractFromRootDataContract(XmlQualifiedName typeQName)
- {
- return XmlObjectSerializerWriteContextComplexJson.ResolveJsonDataContractFromRootDataContract(this, typeQName, rootTypeDataContract);
- }
- }
- }
|