1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //------------------------------------------------------------
5 namespace System.Runtime.Serialization
10 using System.Security;
11 using System.Collections;
12 using System.Security.Permissions;
13 using System.Runtime.CompilerServices;
14 using System.Runtime.Serialization.Formatters;
15 using System.Collections.Generic;
17 using System.Runtime.Serialization.Configuration;
19 using System.Reflection;
21 public sealed class NetDataContractSerializer : XmlObjectSerializer, IFormatter
23 XmlDictionaryString rootName;
24 XmlDictionaryString rootNamespace;
25 StreamingContext context;
26 SerializationBinder binder;
27 ISurrogateSelector surrogateSelector;
28 int maxItemsInObjectGraph;
29 bool ignoreExtensionDataObject;
30 FormatterAssemblyStyle assemblyFormat;
31 DataContract cachedDataContract;
32 static Hashtable typeNameCache = new Hashtable();
34 public NetDataContractSerializer()
35 : this(new StreamingContext(StreamingContextStates.All))
39 public NetDataContractSerializer(StreamingContext context)
40 : this(context, Int32.MaxValue, false, FormatterAssemblyStyle.Full, null)
44 public NetDataContractSerializer(StreamingContext context,
45 int maxItemsInObjectGraph,
46 bool ignoreExtensionDataObject,
47 FormatterAssemblyStyle assemblyFormat,
48 ISurrogateSelector surrogateSelector)
50 Initialize(context, maxItemsInObjectGraph, ignoreExtensionDataObject, assemblyFormat, surrogateSelector);
53 public NetDataContractSerializer(string rootName, string rootNamespace)
54 : this(rootName, rootNamespace, new StreamingContext(StreamingContextStates.All), Int32.MaxValue, false, FormatterAssemblyStyle.Full, null)
58 public NetDataContractSerializer(string rootName, string rootNamespace,
59 StreamingContext context,
60 int maxItemsInObjectGraph,
61 bool ignoreExtensionDataObject,
62 FormatterAssemblyStyle assemblyFormat,
63 ISurrogateSelector surrogateSelector)
65 XmlDictionary dictionary = new XmlDictionary(2);
66 Initialize(dictionary.Add(rootName), dictionary.Add(DataContract.GetNamespace(rootNamespace)), context, maxItemsInObjectGraph, ignoreExtensionDataObject, assemblyFormat, surrogateSelector);
69 public NetDataContractSerializer(XmlDictionaryString rootName, XmlDictionaryString rootNamespace)
70 : this(rootName, rootNamespace, new StreamingContext(StreamingContextStates.All), Int32.MaxValue, false, FormatterAssemblyStyle.Full, null)
74 public NetDataContractSerializer(XmlDictionaryString rootName, XmlDictionaryString rootNamespace,
75 StreamingContext context,
76 int maxItemsInObjectGraph,
77 bool ignoreExtensionDataObject,
78 FormatterAssemblyStyle assemblyFormat,
79 ISurrogateSelector surrogateSelector)
81 Initialize(rootName, rootNamespace, context, maxItemsInObjectGraph, ignoreExtensionDataObject, assemblyFormat, surrogateSelector);
84 void Initialize(StreamingContext context,
85 int maxItemsInObjectGraph,
86 bool ignoreExtensionDataObject,
87 FormatterAssemblyStyle assemblyFormat,
88 ISurrogateSelector surrogateSelector)
90 this.context = context;
91 if (maxItemsInObjectGraph < 0)
92 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("maxItemsInObjectGraph", SR.GetString(SR.ValueMustBeNonNegative)));
93 this.maxItemsInObjectGraph = maxItemsInObjectGraph;
94 this.ignoreExtensionDataObject = ignoreExtensionDataObject;
95 this.surrogateSelector = surrogateSelector;
96 this.AssemblyFormat = assemblyFormat;
99 void Initialize(XmlDictionaryString rootName, XmlDictionaryString rootNamespace,
100 StreamingContext context,
101 int maxItemsInObjectGraph,
102 bool ignoreExtensionDataObject,
103 FormatterAssemblyStyle assemblyFormat,
104 ISurrogateSelector surrogateSelector)
106 Initialize(context, maxItemsInObjectGraph, ignoreExtensionDataObject, assemblyFormat, surrogateSelector);
107 this.rootName = rootName;
108 this.rootNamespace = rootNamespace;
111 static bool? unsafeTypeForwardingEnabled;
112 internal static bool UnsafeTypeForwardingEnabled
114 [Fx.Tag.SecurityNote(Critical = "Calls Security Critical method NetDataContractSerializerSection.TryUnsafeGetSection.", Safe = "The ConfigSection instance is not leaked.")]
115 [SecuritySafeCritical]
118 if (unsafeTypeForwardingEnabled == null)
121 unsafeTypeForwardingEnabled = false;
123 NetDataContractSerializerSection section;
124 if (NetDataContractSerializerSection.TryUnsafeGetSection(out section))
126 unsafeTypeForwardingEnabled = section.EnableUnsafeTypeForwarding;
130 unsafeTypeForwardingEnabled = false;
134 Fx.Assert(unsafeTypeForwardingEnabled != null, "unsafeTypeForwardingEnabled should not be null.");
135 return unsafeTypeForwardingEnabled.Value;
139 public StreamingContext Context
141 get { return context; }
142 set { context = value; }
145 public SerializationBinder Binder
147 get { return binder; }
148 set { binder = value; }
151 public ISurrogateSelector SurrogateSelector
153 get { return surrogateSelector; }
154 set { surrogateSelector = value; }
157 public FormatterAssemblyStyle AssemblyFormat
159 get { return assemblyFormat; }
162 if (value != FormatterAssemblyStyle.Full && value != FormatterAssemblyStyle.Simple)
163 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.InvalidAssemblyFormat, value)));
164 assemblyFormat = value;
168 public int MaxItemsInObjectGraph
170 get { return maxItemsInObjectGraph; }
173 public bool IgnoreExtensionDataObject
175 get { return ignoreExtensionDataObject; }
178 public void Serialize(Stream stream, object graph)
180 base.WriteObject(stream, graph);
183 public object Deserialize(Stream stream)
185 return base.ReadObject(stream);
188 internal override void InternalWriteObject(XmlWriterDelegator writer, object graph)
190 Hashtable surrogateDataContracts = null;
191 DataContract contract = GetDataContract(graph, ref surrogateDataContracts);
193 InternalWriteStartObject(writer, graph, contract);
194 InternalWriteObjectContent(writer, graph, contract, surrogateDataContracts);
195 InternalWriteEndObject(writer);
198 public override void WriteObject(XmlWriter writer, object graph)
200 WriteObjectHandleExceptions(new XmlWriterDelegator(writer), graph);
203 public override void WriteStartObject(XmlWriter writer, object graph)
205 WriteStartObjectHandleExceptions(new XmlWriterDelegator(writer), graph);
208 public override void WriteObjectContent(XmlWriter writer, object graph)
210 WriteObjectContentHandleExceptions(new XmlWriterDelegator(writer), graph);
213 public override void WriteEndObject(XmlWriter writer)
215 WriteEndObjectHandleExceptions(new XmlWriterDelegator(writer));
218 public override void WriteStartObject(XmlDictionaryWriter writer, object graph)
220 WriteStartObjectHandleExceptions(new XmlWriterDelegator(writer), graph);
223 internal override void InternalWriteStartObject(XmlWriterDelegator writer, object graph)
225 Hashtable surrogateDataContracts = null;
226 DataContract contract = GetDataContract(graph, ref surrogateDataContracts);
227 InternalWriteStartObject(writer, graph, contract);
230 void InternalWriteStartObject(XmlWriterDelegator writer, object graph, DataContract contract)
232 WriteRootElement(writer, contract, rootName, rootNamespace, CheckIfNeedsContractNsAtRoot(rootName, rootNamespace, contract));
235 public override void WriteObjectContent(XmlDictionaryWriter writer, object graph)
237 WriteObjectContentHandleExceptions(new XmlWriterDelegator(writer), graph);
240 internal override void InternalWriteObjectContent(XmlWriterDelegator writer, object graph)
242 Hashtable surrogateDataContracts = null;
243 DataContract contract = GetDataContract(graph, ref surrogateDataContracts);
244 InternalWriteObjectContent(writer, graph, contract, surrogateDataContracts);
247 void InternalWriteObjectContent(XmlWriterDelegator writer, object graph, DataContract contract, Hashtable surrogateDataContracts)
249 if (MaxItemsInObjectGraph == 0)
250 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.ExceededMaxItemsQuota, MaxItemsInObjectGraph)));
252 if (IsRootXmlAny(rootName, contract))
254 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.IsAnyNotSupportedByNetDataContractSerializer, contract.UnderlyingType)));
256 else if (graph == null)
262 Type graphType = graph.GetType();
263 if (contract.UnderlyingType != graphType)
264 contract = GetDataContract(graph, ref surrogateDataContracts);
266 XmlObjectSerializerWriteContext context = null;
267 if (contract.CanContainReferences)
269 context = XmlObjectSerializerWriteContext.CreateContext(this, surrogateDataContracts);
270 context.HandleGraphAtTopLevel(writer, graph, contract);
273 WriteClrTypeInfo(writer, contract, binder);
274 contract.WriteXmlValue(writer, graph, context);
278 // Update the overloads whenever you are changing this method
279 internal static void WriteClrTypeInfo(XmlWriterDelegator writer, DataContract dataContract, SerializationBinder binder)
281 if (!dataContract.IsISerializable && !(dataContract is SurrogateDataContract))
283 TypeInformation typeInformation = null;
284 Type clrType = dataContract.OriginalUnderlyingType;
285 string clrTypeName = null;
286 string clrAssemblyName = null;
290 binder.BindToName(clrType, out clrAssemblyName, out clrTypeName);
293 if (clrTypeName == null)
295 typeInformation = NetDataContractSerializer.GetTypeInformation(clrType);
296 clrTypeName = typeInformation.FullTypeName;
299 if (clrAssemblyName == null)
301 clrAssemblyName = (typeInformation == null) ?
302 NetDataContractSerializer.GetTypeInformation(clrType).AssemblyString :
303 typeInformation.AssemblyString;
305 // Throw in the [TypeForwardedFrom] case to prevent a partially trusted assembly from forwarding itself to an assembly with higher privileges
306 if (!UnsafeTypeForwardingEnabled && !clrType.Assembly.IsFullyTrusted && !IsAssemblyNameForwardingSafe(clrType.Assembly.FullName, clrAssemblyName))
308 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.TypeCannotBeForwardedFrom, DataContract.GetClrTypeFullName(clrType), clrType.Assembly.FullName, clrAssemblyName)));
312 WriteClrTypeInfo(writer, clrTypeName, clrAssemblyName);
316 // Update the overloads whenever you are changing this method
317 internal static void WriteClrTypeInfo(XmlWriterDelegator writer, Type dataContractType, SerializationBinder binder, string defaultClrTypeName, string defaultClrAssemblyName)
319 string clrTypeName = null;
320 string clrAssemblyName = null;
324 binder.BindToName(dataContractType, out clrAssemblyName, out clrTypeName);
327 if (clrTypeName == null)
329 clrTypeName = defaultClrTypeName;
332 if (clrAssemblyName == null)
334 clrAssemblyName = defaultClrAssemblyName;
337 WriteClrTypeInfo(writer, clrTypeName, clrAssemblyName);
340 // Update the overloads whenever you are changing this method
341 internal static void WriteClrTypeInfo(XmlWriterDelegator writer, Type dataContractType, SerializationBinder binder, SerializationInfo serInfo)
343 TypeInformation typeInformation = null;
344 string clrTypeName = null;
345 string clrAssemblyName = null;
349 binder.BindToName(dataContractType, out clrAssemblyName, out clrTypeName);
352 if (clrTypeName == null)
354 if (serInfo.IsFullTypeNameSetExplicit)
356 clrTypeName = serInfo.FullTypeName;
360 typeInformation = NetDataContractSerializer.GetTypeInformation(serInfo.ObjectType);
361 clrTypeName = typeInformation.FullTypeName;
365 if (clrAssemblyName == null)
367 if (serInfo.IsAssemblyNameSetExplicit)
369 clrAssemblyName = serInfo.AssemblyName;
373 clrAssemblyName = (typeInformation == null) ?
374 NetDataContractSerializer.GetTypeInformation(serInfo.ObjectType).AssemblyString :
375 typeInformation.AssemblyString;
379 WriteClrTypeInfo(writer, clrTypeName, clrAssemblyName);
382 static void WriteClrTypeInfo(XmlWriterDelegator writer, string clrTypeName, string clrAssemblyName)
384 if (clrTypeName != null)
385 writer.WriteAttributeString(Globals.SerPrefix, DictionaryGlobals.ClrTypeLocalName, DictionaryGlobals.SerializationNamespace, DataContract.GetClrTypeString(clrTypeName));
386 if (clrAssemblyName != null)
387 writer.WriteAttributeString(Globals.SerPrefix, DictionaryGlobals.ClrAssemblyLocalName, DictionaryGlobals.SerializationNamespace, DataContract.GetClrTypeString(clrAssemblyName));
390 public override void WriteEndObject(XmlDictionaryWriter writer)
392 WriteEndObjectHandleExceptions(new XmlWriterDelegator(writer));
395 internal override void InternalWriteEndObject(XmlWriterDelegator writer)
397 writer.WriteEndElement();
400 public override object ReadObject(XmlReader reader)
402 return ReadObjectHandleExceptions(new XmlReaderDelegator(reader), true /*verifyObjectName*/);
405 public override object ReadObject(XmlReader reader, bool verifyObjectName)
407 return ReadObjectHandleExceptions(new XmlReaderDelegator(reader), verifyObjectName);
410 public override bool IsStartObject(XmlReader reader)
412 return IsStartObjectHandleExceptions(new XmlReaderDelegator(reader));
415 public override object ReadObject(XmlDictionaryReader reader, bool verifyObjectName)
417 return ReadObjectHandleExceptions(new XmlReaderDelegator(reader), verifyObjectName);
420 public override bool IsStartObject(XmlDictionaryReader reader)
422 return IsStartObjectHandleExceptions(new XmlReaderDelegator(reader));
425 internal override object InternalReadObject(XmlReaderDelegator xmlReader, bool verifyObjectName)
427 if (MaxItemsInObjectGraph == 0)
428 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.ExceededMaxItemsQuota, MaxItemsInObjectGraph)));
430 // verifyObjectName has no effect in SharedType mode
431 if (!IsStartElement(xmlReader))
433 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationExceptionWithReaderDetails(SR.GetString(SR.ExpectingElementAtDeserialize, XmlNodeType.Element), xmlReader));
436 XmlObjectSerializerReadContext context = XmlObjectSerializerReadContext.CreateContext(this);
437 return context.InternalDeserialize(xmlReader, null, null, null);
440 internal override bool InternalIsStartObject(XmlReaderDelegator reader)
442 return IsStartElement(reader);
445 internal DataContract GetDataContract(object obj, ref Hashtable surrogateDataContracts)
447 return GetDataContract(((obj == null) ? Globals.TypeOfObject : obj.GetType()), ref surrogateDataContracts);
450 internal DataContract GetDataContract(Type type, ref Hashtable surrogateDataContracts)
452 return GetDataContract(type.TypeHandle, type, ref surrogateDataContracts);
455 internal DataContract GetDataContract(RuntimeTypeHandle typeHandle, Type type, ref Hashtable surrogateDataContracts)
457 DataContract dataContract = GetDataContractFromSurrogateSelector(surrogateSelector, Context, typeHandle, type, ref surrogateDataContracts);
458 if (dataContract != null)
461 if (cachedDataContract == null)
463 dataContract = DataContract.GetDataContract(typeHandle, type, SerializationMode.SharedType);
464 cachedDataContract = dataContract;
468 DataContract currentCachedDataContract = cachedDataContract;
469 if (currentCachedDataContract.UnderlyingType.TypeHandle.Equals(typeHandle))
470 return currentCachedDataContract;
472 return DataContract.GetDataContract(typeHandle, type, SerializationMode.SharedType);
475 [Fx.Tag.SecurityNote(Critical = "Calls the critical methods of ISurrogateSelector", Safe = "Demands for FullTrust")]
476 [SecuritySafeCritical]
477 [PermissionSet(SecurityAction.Demand, Unrestricted = true)]
478 [MethodImpl(MethodImplOptions.NoInlining)]
479 static ISerializationSurrogate GetSurrogate(Type type, ISurrogateSelector surrogateSelector, StreamingContext context)
481 ISurrogateSelector surrogateSelectorNotUsed;
482 return surrogateSelector.GetSurrogate(type, context, out surrogateSelectorNotUsed);
485 internal static DataContract GetDataContractFromSurrogateSelector(ISurrogateSelector surrogateSelector, StreamingContext context, RuntimeTypeHandle typeHandle, Type type, ref Hashtable surrogateDataContracts)
487 if (surrogateSelector == null)
491 type = Type.GetTypeFromHandle(typeHandle);
492 DataContract builtInDataContract = DataContract.GetBuiltInDataContract(type);
493 if (builtInDataContract != null)
494 return builtInDataContract;
495 if (surrogateDataContracts != null)
497 DataContract cachedSurrogateContract = (DataContract)surrogateDataContracts[type];
498 if (cachedSurrogateContract != null)
499 return cachedSurrogateContract;
501 DataContract surrogateContract = null;
502 ISerializationSurrogate surrogate = GetSurrogate(type, surrogateSelector, context);
503 if (surrogate != null)
504 surrogateContract = new SurrogateDataContract(type, surrogate);
505 else if (type.IsArray)
507 Type elementType = type.GetElementType();
508 DataContract itemContract = GetDataContractFromSurrogateSelector(surrogateSelector, context, elementType.TypeHandle, elementType, ref surrogateDataContracts);
509 if (itemContract == null)
510 itemContract = DataContract.GetDataContract(elementType.TypeHandle, elementType, SerializationMode.SharedType);
511 surrogateContract = new CollectionDataContract(type, itemContract);
513 if (surrogateContract != null)
515 if (surrogateDataContracts == null)
516 surrogateDataContracts = new Hashtable();
517 surrogateDataContracts.Add(type, surrogateContract);
518 return surrogateContract;
524 internal static TypeInformation GetTypeInformation(Type type)
526 TypeInformation typeInformation = null;
527 object typeInformationObject = typeNameCache[type];
528 if (typeInformationObject == null)
530 bool hasTypeForwardedFrom;
531 string assemblyName = DataContract.GetClrAssemblyName(type, out hasTypeForwardedFrom);
532 typeInformation = new TypeInformation(DataContract.GetClrTypeFullNameUsingTypeForwardedFromAttribute(type), assemblyName, hasTypeForwardedFrom);
535 typeNameCache[type] = typeInformation;
540 typeInformation = (TypeInformation)typeInformationObject;
542 return typeInformation;
545 static bool IsAssemblyNameForwardingSafe(string originalAssemblyName, string newAssemblyName)
547 if (originalAssemblyName == newAssemblyName)
552 AssemblyName originalAssembly = new AssemblyName(originalAssemblyName);
553 AssemblyName newAssembly = new AssemblyName(newAssemblyName);
555 // mscorlib will get loaded by the runtime regardless of its string casing or its public key token,
556 // so setting the assembly name to mscorlib is always unsafe
557 if (string.Equals(newAssembly.Name, Globals.MscorlibAssemblySimpleName, StringComparison.OrdinalIgnoreCase) ||
558 string.Equals(newAssembly.Name, Globals.MscorlibFileName, StringComparison.OrdinalIgnoreCase))
563 return IsPublicKeyTokenForwardingSafe(originalAssembly.GetPublicKeyToken(), newAssembly.GetPublicKeyToken());
566 static bool IsPublicKeyTokenForwardingSafe(byte[] sourceToken, byte[] destinationToken)
568 if (sourceToken == null || destinationToken == null || sourceToken.Length == 0 || destinationToken.Length == 0 || sourceToken.Length != destinationToken.Length)
573 for (int i = 0; i < sourceToken.Length; i++)
575 if (sourceToken[i] != destinationToken[i])