Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / WCF / Serialization / System / Runtime / Serialization / Json / XmlObjectSerializerWriteContextComplexJson.cs / 1305376 / XmlObjectSerializerWriteContextComplexJson.cs
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
{
bool alwaysEmitXsiType;
bool perCallXsiTypeAlreadyEmitted;
public XmlObjectSerializerWriteContextComplexJson(DataContractJsonSerializer serializer, DataContract rootTypeDataContract)
: base(serializer,
serializer.MaxItemsInObjectGraph,
new StreamingContext(StreamingContextStates.All),
serializer.IgnoreExtensionDataObject)
{
this.alwaysEmitXsiType = serializer.AlwaysEmitTypeInformation;
this.rootTypeDataContract = rootTypeDataContract;
this.serializerKnownTypeList = serializer.knownTypeList;
this.dataContractSurrogate = serializer.DataContractSurrogate;
}
internal static XmlObjectSerializerWriteContextComplexJson CreateContext(DataContractJsonSerializer serializer, DataContract rootTypeDataContract)
{
return new XmlObjectSerializerWriteContextComplexJson(serializer, rootTypeDataContract);
}
internal IList SerializerKnownTypeList
{
get
{
return this.serializerKnownTypeList;
}
}
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 (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))
{
// 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[]
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);
obj.GetObjectData(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 ClassDataContract.CreateClassDataContractForKeyValue(oldItemContract.UnderlyingType, oldItemContract.Namespace, new string[] { JsonGlobals.KeyString, JsonGlobals.ValueString });
}
return oldItemContract;
}
protected override void WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, object obj, RuntimeTypeHandle declaredTypeHandle)
{
JsonDataContract jsonDataContract = JsonDataContract.GetJsonDataContract(dataContract);
if (alwaysEmitXsiType && !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