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;
16 using System.Runtime.Serialization.Configuration;
17 using System.Reflection;
19 public sealed class NetDataContractSerializer : XmlObjectSerializer, IFormatter
21 XmlDictionaryString rootName;
22 XmlDictionaryString rootNamespace;
23 StreamingContext context;
24 SerializationBinder binder;
25 ISurrogateSelector surrogateSelector;
26 int maxItemsInObjectGraph;
27 bool ignoreExtensionDataObject;
28 FormatterAssemblyStyle assemblyFormat;
29 DataContract cachedDataContract;
30 static Hashtable typeNameCache = new Hashtable();
32 public NetDataContractSerializer()
33 : this(new StreamingContext(StreamingContextStates.All))
37 public NetDataContractSerializer(StreamingContext context)
38 : this(context, Int32.MaxValue, false, FormatterAssemblyStyle.Full, null)
42 public NetDataContractSerializer(StreamingContext context,
43 int maxItemsInObjectGraph,
44 bool ignoreExtensionDataObject,
45 FormatterAssemblyStyle assemblyFormat,
46 ISurrogateSelector surrogateSelector)
48 Initialize(context, maxItemsInObjectGraph, ignoreExtensionDataObject, assemblyFormat, surrogateSelector);
51 public NetDataContractSerializer(string rootName, string rootNamespace)
52 : this(rootName, rootNamespace, new StreamingContext(StreamingContextStates.All), Int32.MaxValue, false, FormatterAssemblyStyle.Full, null)
56 public NetDataContractSerializer(string rootName, string rootNamespace,
57 StreamingContext context,
58 int maxItemsInObjectGraph,
59 bool ignoreExtensionDataObject,
60 FormatterAssemblyStyle assemblyFormat,
61 ISurrogateSelector surrogateSelector)
63 XmlDictionary dictionary = new XmlDictionary(2);
64 Initialize(dictionary.Add(rootName), dictionary.Add(DataContract.GetNamespace(rootNamespace)), context, maxItemsInObjectGraph, ignoreExtensionDataObject, assemblyFormat, surrogateSelector);
67 public NetDataContractSerializer(XmlDictionaryString rootName, XmlDictionaryString rootNamespace)
68 : this(rootName, rootNamespace, new StreamingContext(StreamingContextStates.All), Int32.MaxValue, false, FormatterAssemblyStyle.Full, null)
72 public NetDataContractSerializer(XmlDictionaryString rootName, XmlDictionaryString rootNamespace,
73 StreamingContext context,
74 int maxItemsInObjectGraph,
75 bool ignoreExtensionDataObject,
76 FormatterAssemblyStyle assemblyFormat,
77 ISurrogateSelector surrogateSelector)
79 Initialize(rootName, rootNamespace, context, maxItemsInObjectGraph, ignoreExtensionDataObject, assemblyFormat, surrogateSelector);
82 void Initialize(StreamingContext context,
83 int maxItemsInObjectGraph,
84 bool ignoreExtensionDataObject,
85 FormatterAssemblyStyle assemblyFormat,
86 ISurrogateSelector surrogateSelector)
88 this.context = context;
89 if (maxItemsInObjectGraph < 0)
90 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("maxItemsInObjectGraph", SR.GetString(SR.ValueMustBeNonNegative)));
91 this.maxItemsInObjectGraph = maxItemsInObjectGraph;
92 this.ignoreExtensionDataObject = ignoreExtensionDataObject;
93 this.surrogateSelector = surrogateSelector;
94 this.AssemblyFormat = assemblyFormat;
97 void Initialize(XmlDictionaryString rootName, XmlDictionaryString rootNamespace,
98 StreamingContext context,
99 int maxItemsInObjectGraph,
100 bool ignoreExtensionDataObject,
101 FormatterAssemblyStyle assemblyFormat,
102 ISurrogateSelector surrogateSelector)
104 Initialize(context, maxItemsInObjectGraph, ignoreExtensionDataObject, assemblyFormat, surrogateSelector);
105 this.rootName = rootName;
106 this.rootNamespace = rootNamespace;
109 static bool? unsafeTypeForwardingEnabled;
110 internal static bool UnsafeTypeForwardingEnabled
112 [Fx.Tag.SecurityNote(Critical = "Calls Security Critical method NetDataContractSerializerSection.TryUnsafeGetSection.", Safe = "The ConfigSection instance is not leaked.")]
113 [SecuritySafeCritical]
116 if (unsafeTypeForwardingEnabled == null)
118 NetDataContractSerializerSection section;
119 if (NetDataContractSerializerSection.TryUnsafeGetSection(out section))
121 unsafeTypeForwardingEnabled = section.EnableUnsafeTypeForwarding;
125 unsafeTypeForwardingEnabled = false;
128 Fx.Assert(unsafeTypeForwardingEnabled != null, "unsafeTypeForwardingEnabled should not be null.");
129 return unsafeTypeForwardingEnabled.Value;
133 public StreamingContext Context
135 get { return context; }
136 set { context = value; }
139 public SerializationBinder Binder
141 get { return binder; }
142 set { binder = value; }
145 public ISurrogateSelector SurrogateSelector
147 get { return surrogateSelector; }
148 set { surrogateSelector = value; }
151 public FormatterAssemblyStyle AssemblyFormat
153 get { return assemblyFormat; }
156 if (value != FormatterAssemblyStyle.Full && value != FormatterAssemblyStyle.Simple)
157 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.InvalidAssemblyFormat, value)));
158 assemblyFormat = value;
162 public int MaxItemsInObjectGraph
164 get { return maxItemsInObjectGraph; }
167 public bool IgnoreExtensionDataObject
169 get { return ignoreExtensionDataObject; }
172 public void Serialize(Stream stream, object graph)
174 base.WriteObject(stream, graph);
177 public object Deserialize(Stream stream)
179 return base.ReadObject(stream);
182 internal override void InternalWriteObject(XmlWriterDelegator writer, object graph)
184 Hashtable surrogateDataContracts = null;
185 DataContract contract = GetDataContract(graph, ref surrogateDataContracts);
187 InternalWriteStartObject(writer, graph, contract);
188 InternalWriteObjectContent(writer, graph, contract, surrogateDataContracts);
189 InternalWriteEndObject(writer);
192 public override void WriteObject(XmlWriter writer, object graph)
194 WriteObjectHandleExceptions(new XmlWriterDelegator(writer), graph);
197 public override void WriteStartObject(XmlWriter writer, object graph)
199 WriteStartObjectHandleExceptions(new XmlWriterDelegator(writer), graph);
202 public override void WriteObjectContent(XmlWriter writer, object graph)
204 WriteObjectContentHandleExceptions(new XmlWriterDelegator(writer), graph);
207 public override void WriteEndObject(XmlWriter writer)
209 WriteEndObjectHandleExceptions(new XmlWriterDelegator(writer));
212 public override void WriteStartObject(XmlDictionaryWriter writer, object graph)
214 WriteStartObjectHandleExceptions(new XmlWriterDelegator(writer), graph);
217 internal override void InternalWriteStartObject(XmlWriterDelegator writer, object graph)
219 Hashtable surrogateDataContracts = null;
220 DataContract contract = GetDataContract(graph, ref surrogateDataContracts);
221 InternalWriteStartObject(writer, graph, contract);
224 void InternalWriteStartObject(XmlWriterDelegator writer, object graph, DataContract contract)
226 WriteRootElement(writer, contract, rootName, rootNamespace, CheckIfNeedsContractNsAtRoot(rootName, rootNamespace, contract));
229 public override void WriteObjectContent(XmlDictionaryWriter writer, object graph)
231 WriteObjectContentHandleExceptions(new XmlWriterDelegator(writer), graph);
234 internal override void InternalWriteObjectContent(XmlWriterDelegator writer, object graph)
236 Hashtable surrogateDataContracts = null;
237 DataContract contract = GetDataContract(graph, ref surrogateDataContracts);
238 InternalWriteObjectContent(writer, graph, contract, surrogateDataContracts);
241 void InternalWriteObjectContent(XmlWriterDelegator writer, object graph, DataContract contract, Hashtable surrogateDataContracts)
243 if (MaxItemsInObjectGraph == 0)
244 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.ExceededMaxItemsQuota, MaxItemsInObjectGraph)));
246 if (IsRootXmlAny(rootName, contract))
248 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.IsAnyNotSupportedByNetDataContractSerializer, contract.UnderlyingType)));
250 else if (graph == null)
256 Type graphType = graph.GetType();
257 if (contract.UnderlyingType != graphType)
258 contract = GetDataContract(graph, ref surrogateDataContracts);
260 XmlObjectSerializerWriteContext context = null;
261 if (contract.CanContainReferences)
263 context = XmlObjectSerializerWriteContext.CreateContext(this, surrogateDataContracts);
264 context.HandleGraphAtTopLevel(writer, graph, contract);
267 WriteClrTypeInfo(writer, contract, binder);
268 contract.WriteXmlValue(writer, graph, context);
272 // Update the overloads whenever you are changing this method
273 internal static void WriteClrTypeInfo(XmlWriterDelegator writer, DataContract dataContract, SerializationBinder binder)
275 if (!dataContract.IsISerializable && !(dataContract is SurrogateDataContract))
277 TypeInformation typeInformation = null;
278 Type clrType = dataContract.OriginalUnderlyingType;
279 string clrTypeName = null;
280 string clrAssemblyName = null;
284 binder.BindToName(clrType, out clrAssemblyName, out clrTypeName);
287 if (clrTypeName == null)
289 typeInformation = NetDataContractSerializer.GetTypeInformation(clrType);
290 clrTypeName = typeInformation.FullTypeName;
293 if (clrAssemblyName == null)
295 clrAssemblyName = (typeInformation == null) ?
296 NetDataContractSerializer.GetTypeInformation(clrType).AssemblyString :
297 typeInformation.AssemblyString;
299 // Throw in the [TypeForwardedFrom] case to prevent a partially trusted assembly from forwarding itself to an assembly with higher privileges
300 if (!UnsafeTypeForwardingEnabled && !clrType.Assembly.IsFullyTrusted && !IsAssemblyNameForwardingSafe(clrType.Assembly.FullName, clrAssemblyName))
302 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.TypeCannotBeForwardedFrom, DataContract.GetClrTypeFullName(clrType), clrType.Assembly.FullName, clrAssemblyName)));
306 WriteClrTypeInfo(writer, clrTypeName, clrAssemblyName);
310 // Update the overloads whenever you are changing this method
311 internal static void WriteClrTypeInfo(XmlWriterDelegator writer, Type dataContractType, SerializationBinder binder, string defaultClrTypeName, string defaultClrAssemblyName)
313 string clrTypeName = null;
314 string clrAssemblyName = null;
318 binder.BindToName(dataContractType, out clrAssemblyName, out clrTypeName);
321 if (clrTypeName == null)
323 clrTypeName = defaultClrTypeName;
326 if (clrAssemblyName == null)
328 clrAssemblyName = defaultClrAssemblyName;
331 WriteClrTypeInfo(writer, clrTypeName, clrAssemblyName);
334 // Update the overloads whenever you are changing this method
335 internal static void WriteClrTypeInfo(XmlWriterDelegator writer, Type dataContractType, SerializationBinder binder, SerializationInfo serInfo)
337 TypeInformation typeInformation = null;
338 string clrTypeName = null;
339 string clrAssemblyName = null;
343 binder.BindToName(dataContractType, out clrAssemblyName, out clrTypeName);
346 if (clrTypeName == null)
348 if (serInfo.IsFullTypeNameSetExplicit)
350 clrTypeName = serInfo.FullTypeName;
354 typeInformation = NetDataContractSerializer.GetTypeInformation(serInfo.ObjectType);
355 clrTypeName = typeInformation.FullTypeName;
359 if (clrAssemblyName == null)
361 if (serInfo.IsAssemblyNameSetExplicit)
363 clrAssemblyName = serInfo.AssemblyName;
367 clrAssemblyName = (typeInformation == null) ?
368 NetDataContractSerializer.GetTypeInformation(serInfo.ObjectType).AssemblyString :
369 typeInformation.AssemblyString;
373 WriteClrTypeInfo(writer, clrTypeName, clrAssemblyName);
376 static void WriteClrTypeInfo(XmlWriterDelegator writer, string clrTypeName, string clrAssemblyName)
378 if (clrTypeName != null)
379 writer.WriteAttributeString(Globals.SerPrefix, DictionaryGlobals.ClrTypeLocalName, DictionaryGlobals.SerializationNamespace, DataContract.GetClrTypeString(clrTypeName));
380 if (clrAssemblyName != null)
381 writer.WriteAttributeString(Globals.SerPrefix, DictionaryGlobals.ClrAssemblyLocalName, DictionaryGlobals.SerializationNamespace, DataContract.GetClrTypeString(clrAssemblyName));
384 public override void WriteEndObject(XmlDictionaryWriter writer)
386 WriteEndObjectHandleExceptions(new XmlWriterDelegator(writer));
389 internal override void InternalWriteEndObject(XmlWriterDelegator writer)
391 writer.WriteEndElement();
394 public override object ReadObject(XmlReader reader)
396 return ReadObjectHandleExceptions(new XmlReaderDelegator(reader), true /*verifyObjectName*/);
399 public override object ReadObject(XmlReader reader, bool verifyObjectName)
401 return ReadObjectHandleExceptions(new XmlReaderDelegator(reader), verifyObjectName);
404 public override bool IsStartObject(XmlReader reader)
406 return IsStartObjectHandleExceptions(new XmlReaderDelegator(reader));
409 public override object ReadObject(XmlDictionaryReader reader, bool verifyObjectName)
411 return ReadObjectHandleExceptions(new XmlReaderDelegator(reader), verifyObjectName);
414 public override bool IsStartObject(XmlDictionaryReader reader)
416 return IsStartObjectHandleExceptions(new XmlReaderDelegator(reader));
419 internal override object InternalReadObject(XmlReaderDelegator xmlReader, bool verifyObjectName)
421 if (MaxItemsInObjectGraph == 0)
422 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.ExceededMaxItemsQuota, MaxItemsInObjectGraph)));
424 // verifyObjectName has no effect in SharedType mode
425 if (!IsStartElement(xmlReader))
427 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlObjectSerializer.CreateSerializationExceptionWithReaderDetails(SR.GetString(SR.ExpectingElementAtDeserialize, XmlNodeType.Element), xmlReader));
430 XmlObjectSerializerReadContext context = XmlObjectSerializerReadContext.CreateContext(this);
431 return context.InternalDeserialize(xmlReader, null, null, null);
434 internal override bool InternalIsStartObject(XmlReaderDelegator reader)
436 return IsStartElement(reader);
439 internal DataContract GetDataContract(object obj, ref Hashtable surrogateDataContracts)
441 return GetDataContract(((obj == null) ? Globals.TypeOfObject : obj.GetType()), ref surrogateDataContracts);
444 internal DataContract GetDataContract(Type type, ref Hashtable surrogateDataContracts)
446 return GetDataContract(type.TypeHandle, type, ref surrogateDataContracts);
449 internal DataContract GetDataContract(RuntimeTypeHandle typeHandle, Type type, ref Hashtable surrogateDataContracts)
451 DataContract dataContract = GetDataContractFromSurrogateSelector(surrogateSelector, Context, typeHandle, type, ref surrogateDataContracts);
452 if (dataContract != null)
455 if (cachedDataContract == null)
457 dataContract = DataContract.GetDataContract(typeHandle, type, SerializationMode.SharedType);
458 cachedDataContract = dataContract;
462 DataContract currentCachedDataContract = cachedDataContract;
463 if (currentCachedDataContract.UnderlyingType.TypeHandle.Equals(typeHandle))
464 return currentCachedDataContract;
466 return DataContract.GetDataContract(typeHandle, type, SerializationMode.SharedType);
469 [Fx.Tag.SecurityNote(Critical = "Calls the critical methods of ISurrogateSelector", Safe = "Demands for FullTrust")]
470 [SecuritySafeCritical]
471 [PermissionSet(SecurityAction.Demand, Unrestricted = true)]
472 [MethodImpl(MethodImplOptions.NoInlining)]
473 static ISerializationSurrogate GetSurrogate(Type type, ISurrogateSelector surrogateSelector, StreamingContext context)
475 ISurrogateSelector surrogateSelectorNotUsed;
476 return surrogateSelector.GetSurrogate(type, context, out surrogateSelectorNotUsed);
479 internal static DataContract GetDataContractFromSurrogateSelector(ISurrogateSelector surrogateSelector, StreamingContext context, RuntimeTypeHandle typeHandle, Type type, ref Hashtable surrogateDataContracts)
481 if (surrogateSelector == null)
485 type = Type.GetTypeFromHandle(typeHandle);
486 DataContract builtInDataContract = DataContract.GetBuiltInDataContract(type);
487 if (builtInDataContract != null)
488 return builtInDataContract;
489 if (surrogateDataContracts != null)
491 DataContract cachedSurrogateContract = (DataContract)surrogateDataContracts[type];
492 if (cachedSurrogateContract != null)
493 return cachedSurrogateContract;
495 DataContract surrogateContract = null;
496 ISerializationSurrogate surrogate = GetSurrogate(type, surrogateSelector, context);
497 if (surrogate != null)
498 surrogateContract = new SurrogateDataContract(type, surrogate);
499 else if (type.IsArray)
501 Type elementType = type.GetElementType();
502 DataContract itemContract = GetDataContractFromSurrogateSelector(surrogateSelector, context, elementType.TypeHandle, elementType, ref surrogateDataContracts);
503 if (itemContract == null)
504 itemContract = DataContract.GetDataContract(elementType.TypeHandle, elementType, SerializationMode.SharedType);
505 surrogateContract = new CollectionDataContract(type, itemContract);
507 if (surrogateContract != null)
509 if (surrogateDataContracts == null)
510 surrogateDataContracts = new Hashtable();
511 surrogateDataContracts.Add(type, surrogateContract);
512 return surrogateContract;
518 internal static TypeInformation GetTypeInformation(Type type)
520 TypeInformation typeInformation = null;
521 object typeInformationObject = typeNameCache[type];
522 if (typeInformationObject == null)
524 bool hasTypeForwardedFrom;
525 string assemblyName = DataContract.GetClrAssemblyName(type, out hasTypeForwardedFrom);
526 typeInformation = new TypeInformation(DataContract.GetClrTypeFullNameUsingTypeForwardedFromAttribute(type), assemblyName, hasTypeForwardedFrom);
529 typeNameCache[type] = typeInformation;
534 typeInformation = (TypeInformation)typeInformationObject;
536 return typeInformation;
539 static bool IsAssemblyNameForwardingSafe(string originalAssemblyName, string newAssemblyName)
541 if (originalAssemblyName == newAssemblyName)
546 AssemblyName originalAssembly = new AssemblyName(originalAssemblyName);
547 AssemblyName newAssembly = new AssemblyName(newAssemblyName);
549 // mscorlib will get loaded by the runtime regardless of its string casing or its public key token,
550 // so setting the assembly name to mscorlib is always unsafe
551 if (string.Equals(newAssembly.Name, Globals.MscorlibAssemblySimpleName, StringComparison.OrdinalIgnoreCase) ||
552 string.Equals(newAssembly.Name, Globals.MscorlibFileName, StringComparison.OrdinalIgnoreCase))
557 return IsPublicKeyTokenForwardingSafe(originalAssembly.GetPublicKeyToken(), newAssembly.GetPublicKeyToken());
560 static bool IsPublicKeyTokenForwardingSafe(byte[] sourceToken, byte[] destinationToken)
562 if (sourceToken == null || destinationToken == null || sourceToken.Length == 0 || destinationToken.Length == 0 || sourceToken.Length != destinationToken.Length)
567 for (int i = 0; i < sourceToken.Length; i++)
569 if (sourceToken[i] != destinationToken[i])