1 // created on 24/04/2003 at 15:35
3 // System.Runtime.Serialization.Formatters.Soap.SoapReader
6 // Jean-Marc Andre (jean-marc.andre@polymtl.ca)
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System
.Xml
.Schema
;
34 using System
.Reflection
;
35 using System
.Collections
;
36 using System
.Runtime
.Remoting
;
37 using System
.Runtime
.Serialization
;
38 using System
.Runtime
.Remoting
.Messaging
;
40 namespace System
.Runtime
.Serialization
.Formatters
.Soap
{
41 internal sealed class SoapReader
{
45 private SerializationBinder _binder
;
46 private SoapTypeMapper mapper
;
47 private ObjectManager objMgr
;
48 private StreamingContext _context
;
49 private long _nextAvailableId
= long.MaxValue
;
50 private ISurrogateSelector _surrogateSelector
;
51 private XmlTextReader xmlReader
;
52 private Hashtable _fieldIndices
;
53 private long _topObjectId
= 1;
57 public MemberInfo
[] MemberInfos
;
58 public Hashtable Indices
;
65 private long NextAvailableId
70 return _nextAvailableId
;
78 public SoapReader(SerializationBinder binder
, ISurrogateSelector selector
, StreamingContext context
)
81 objMgr
= new ObjectManager(selector
, context
);
83 _surrogateSelector
= selector
;
84 _fieldIndices
= new Hashtable();
89 #region Public Methods
91 public object Deserialize(Stream inStream
, ISoapMessage soapMessage
)
93 ArrayList headers
= null;
94 xmlReader
= new XmlTextReader(inStream
);
95 xmlReader
.WhitespaceHandling
= WhitespaceHandling
.None
;
96 mapper
= new SoapTypeMapper(_binder
);
101 xmlReader
.MoveToContent();
102 xmlReader
.ReadStartElement ();
103 xmlReader
.MoveToContent();
106 while (!(xmlReader
.NodeType
== XmlNodeType
.Element
&& xmlReader
.LocalName
== "Body" && xmlReader
.NamespaceURI
== SoapTypeMapper
.SoapEnvelopeNamespace
))
108 if (xmlReader
.NodeType
== XmlNodeType
.Element
&& xmlReader
.LocalName
== "Header" && xmlReader
.NamespaceURI
== SoapTypeMapper
.SoapEnvelopeNamespace
)
110 if (headers
== null) headers
= new ArrayList ();
111 DeserializeHeaders (headers
);
115 xmlReader
.MoveToContent();
119 xmlReader
.ReadStartElement();
120 xmlReader
.MoveToContent();
123 if (soapMessage
!= null)
125 if (DeserializeMessage (soapMessage
)) {
126 _topObjectId
= NextAvailableId
;
127 RegisterObject (_topObjectId
, soapMessage
, null, 0, null, null);
129 xmlReader
.MoveToContent();
132 soapMessage
.Headers
= (Header
[]) headers
.ToArray (typeof(Header
));
135 while (xmlReader
.NodeType
!= XmlNodeType
.EndElement
)
139 xmlReader
.ReadEndElement ();
140 xmlReader
.MoveToContent();
143 xmlReader
.ReadEndElement ();
147 if(xmlReader
!= null) xmlReader
.Close();
155 #region Private Methods
157 private object TopObject
162 objMgr
.RaiseDeserializationEvent();
163 return objMgr
.GetObject(_topObjectId
);
167 private bool IsNull()
169 string tmp
= xmlReader
["null", XmlSchema
.InstanceNamespace
];
170 return (tmp
== null || tmp
== string.Empty
)?false:true;
177 string strId
= xmlReader
["id"];
178 if(strId
== null || strId
== String
.Empty
) return 0;
179 id
= Convert
.ToInt64(strId
.Substring(4));
183 private long GetHref()
187 string strHref
= xmlReader
["href"];
188 if(strHref
== null || strHref
== string.Empty
) return 0;
189 href
= Convert
.ToInt64(strHref
.Substring(5));
193 private Type
GetComponentType()
197 string strValue
= xmlReader
["type", XmlSchema
.InstanceNamespace
];
198 if(strValue
== null) {
199 if(GetId() != 0) return typeof(string);
202 string[] strName
= strValue
.Split(':');
203 string namespaceURI
= xmlReader
.LookupNamespace(strName
[0]);
204 type
= mapper
[new Element(string.Empty
, strName
[1], namespaceURI
)];
209 private bool DeserializeMessage(ISoapMessage message
)
211 string typeNamespace
, assemblyName
;
213 if(xmlReader
.Name
== SoapTypeMapper
.SoapEnvelopePrefix
+ ":Fault")
219 SoapServices
.DecodeXmlNamespaceForClrTypeNamespace(
220 xmlReader
.NamespaceURI
,
223 message
.MethodName
= xmlReader
.LocalName
;
224 message
.XmlNameSpace
= xmlReader
.NamespaceURI
;
226 ArrayList paramNames
= new ArrayList();
227 ArrayList paramValues
= new ArrayList();
228 long paramValuesId
= NextAvailableId
;
229 int[] indices
= new int[1];
231 if (!xmlReader
.IsEmptyElement
)
233 int initialDepth
= xmlReader
.Depth
;
236 while(xmlReader
.Depth
> initialDepth
)
238 long paramId
, paramHref
;
239 object objParam
= null;
240 paramNames
.Add (xmlReader
.Name
);
241 Type paramType
= null;
243 if (message
.ParamTypes
!= null) {
244 if (i
>= message
.ParamTypes
.Length
)
245 throw new SerializationException ("Not enough parameter types in SoapMessages");
246 paramType
= message
.ParamTypes
[i
];
250 objParam
= DeserializeComponent(
257 indices
[0] = paramValues
.Add(objParam
);
260 RecordFixup(paramValuesId
, paramHref
, paramValues
.ToArray(), null, null, null, indices
);
262 else if(paramId
!= 0)
264 // RegisterObject(paramId, objParam, null, paramValuesId, null, indices);
271 xmlReader
.ReadEndElement();
278 message
.ParamNames
= (string[]) paramNames
.ToArray(typeof(string));
279 message
.ParamValues
= paramValues
.ToArray();
280 RegisterObject(paramValuesId
, message
.ParamValues
, null, 0, null, null);
284 void DeserializeHeaders (ArrayList headers
)
286 xmlReader
.ReadStartElement ();
287 xmlReader
.MoveToContent ();
289 while (xmlReader
.NodeType
!= XmlNodeType
.EndElement
)
291 if (xmlReader
.NodeType
!= XmlNodeType
.Element
) { xmlReader.Skip(); continue; }
293 if (xmlReader
.GetAttribute ("root", SoapTypeMapper
.SoapEncodingNamespace
) == "1")
294 headers
.Add (DeserializeHeader ());
298 xmlReader
.MoveToContent ();
301 xmlReader
.ReadEndElement ();
303
Header
DeserializeHeader ()
305 Header h
= new Header (xmlReader
.LocalName
, null);
306 h
.HeaderNamespace
= xmlReader
.NamespaceURI
;
307 h
.MustUnderstand
= xmlReader
.GetAttribute ("mustUnderstand", SoapTypeMapper
.SoapEnvelopeNamespace
) == "1";
310 long fieldId
, fieldHref
;
311 long idHeader
= NextAvailableId
;
312 FieldInfo fieldInfo
= typeof(Header
).GetField ("Value");
314 value = DeserializeComponent (null, out fieldId
, out fieldHref
, idHeader
, fieldInfo
, null);
317 if(fieldHref
!= 0 && value == null)
319 RecordFixup (idHeader
, fieldHref
, h
, null, null, fieldInfo
, null);
321 else if(value != null && value.GetType().IsValueType
&& fieldId
!= 0)
323 RecordFixup (idHeader
, fieldId
, h
, null, null, fieldInfo
, null);
325 else if(fieldId
!= 0)
327 RegisterObject (fieldId
, value, null, idHeader
, fieldInfo
, null);
330 RegisterObject (idHeader
, h
, null, 0, null, null);
335 private object DeserializeArray(long id
)
337 // Special case for base64 byte arrays
338 if (GetComponentType () == typeof(byte[])) {
339 byte[] data
= Convert
.FromBase64String (xmlReader
.ReadElementString());
340 RegisterObject(id
, data
, null, 0, null, null);
344 // Get the array properties
345 string strArrayType
= xmlReader
["arrayType", SoapTypeMapper
.SoapEncodingNamespace
];
346 string[] arrayInfo
= strArrayType
.Split(':','[',',',']');
347 int numberOfDims
= arrayInfo
.Length
- 3;
348 int[] lengths
= new int[numberOfDims
];
349 string[] arrayDims
= new String
[numberOfDims
];
350 Array
.Copy(arrayInfo
, 2, arrayDims
, 0, numberOfDims
);
351 for (int i
=0; i
< numberOfDims
; i
++)
353 lengths
[i
] = Convert
.ToInt32(arrayDims
[i
]);
356 int[] indices
= new int[numberOfDims
];
359 Type arrayType
= mapper
[new Element(arrayInfo
[0], arrayInfo
[1], xmlReader
.LookupNamespace(arrayInfo
[0]))];
360 Array array
= Array
.CreateInstance(
364 for(int i
= 0; i
< numberOfDims
; i
++)
366 indices
[i
] = array
.GetLowerBound(i
);
369 // Deserialize the array items
370 int arrayDepth
= xmlReader
.Depth
;
372 while(xmlReader
.Depth
> arrayDepth
)
374 Type itemType
= GetComponentType();
376 itemType
= array
.GetType().GetElementType();
377 long itemId
, itemHref
;
379 object objItem
= DeserializeComponent(itemType
,
387 object obj
= objMgr
.GetObject(itemHref
);
389 array
.SetValue(obj
, indices
);
391 RecordFixup(id
, itemHref
, array
, null, null, null, indices
);
393 else if(objItem
!= null && objItem
.GetType().IsValueType
&& itemId
!= 0)
395 RecordFixup(id
, itemId
, array
, null, null, null, indices
);
399 RegisterObject(itemId
, objItem
, null, id
, null, indices
);
400 array
.SetValue(objItem
, indices
);
404 array
.SetValue(objItem
, indices
);
407 // Get the next indice
408 for(int dim
= array
.Rank
- 1; dim
>= 0; dim
--)
411 if(indices
[dim
] > array
.GetUpperBound(dim
))
415 indices
[dim
] = array
.GetLowerBound(dim
);
424 RegisterObject(id
, array
, null, 0, null, null);
425 xmlReader
.ReadEndElement();
431 private object Deserialize()
433 object objReturn
= null;
434 Element element
= new Element(
437 xmlReader
.NamespaceURI
);
440 Type type
= mapper
[element
];
446 if(type
== typeof(Array
))
448 objReturn
= DeserializeArray(id
);
452 objReturn
= DeserializeObject(type
, id
, 0, null, null);
460 private object DeserializeObject(
464 MemberInfo parentMemberInfo
,
467 SerializationInfo info
= null;
468 bool NeedsSerializationInfo
= false;
471 if(SoapTypeMapper
.CanBeValue(type
))
473 string elementString
= xmlReader
.ReadElementString();
474 object obj
= SoapTypeMapper
.ParseXsdValue (elementString
, type
);
477 RegisterObject(id
, obj
, info
, parentId
, parentMemberInfo
, indices
);
482 FormatterServices
.GetUninitializedObject(type
);
483 if(objReturn
is ISerializable
)
484 NeedsSerializationInfo
= true;
486 if(_surrogateSelector
!= null && NeedsSerializationInfo
== false)
488 ISurrogateSelector selector
;
489 ISerializationSurrogate surrogate
= _surrogateSelector
.GetSurrogate(
493 NeedsSerializationInfo
|= (surrogate
!= null);
496 if(NeedsSerializationInfo
)
499 DeserializeISerializableObject(objReturn
, id
, out info
, out hasFixup
);
504 DeserializeSimpleObject(objReturn
, id
, out hasFixup
);
505 if(!hasFixup
&& objReturn
is IObjectReference
)
506 objReturn
= ((IObjectReference
)objReturn
).GetRealObject(_context
);
509 RegisterObject(id
, objReturn
, info
, parentId
, parentMemberInfo
, indices
);
510 xmlReader
.ReadEndElement();
515 private object DeserializeSimpleObject(
522 Type currentType
= obj
.GetType();
523 TypeMetadata tm
= GetTypeMetadata (currentType
);
525 int objDepth
= xmlReader
.Depth
;
526 object[] data
= new object[tm
.MemberInfos
.Length
];
528 for(int i
= 0; i
< tm
.MemberInfos
.Length
; i
++)
531 long fieldId
, fieldHref
;
532 int index
= (int) tm
.Indices
[xmlReader
.LocalName
];
533 FieldInfo fieldInfo
= (tm
.MemberInfos
[index
]) as FieldInfo
;
534 if(fieldInfo
== null) continue;
537 DeserializeComponent(fieldInfo
.FieldType
,
544 data
[index
] = fieldObject
;
546 if(fieldHref
!= 0 && fieldObject
== null)
548 RecordFixup(id
, fieldHref
, obj
, null, null, fieldInfo
, null);
552 if(fieldObject
!= null && fieldObject
.GetType().IsValueType
&& fieldId
!= 0)
554 RecordFixup(id
, fieldId
, obj
, null, null, fieldInfo
, null);
561 RegisterObject(fieldId
, fieldObject
, null, id
, fieldInfo
, null);
565 FormatterServices
.PopulateObjectMembers (obj
, tm
.MemberInfos
, data
);
570 private object DeserializeISerializableObject(
573 out SerializationInfo info
,
577 long fieldId
, fieldHref
;
578 info
= new SerializationInfo(obj
.GetType(), new FormatterConverter());
581 int initialDepth
= xmlReader
.Depth
;
583 while(xmlReader
.Depth
> initialDepth
)
585 Type fieldType
= GetComponentType();
586 string fieldName
= xmlReader
.LocalName
;
587 object objField
= DeserializeComponent(
594 if(fieldHref
!= 0 && objField
== null)
596 RecordFixup(id
, fieldHref
, obj
, info
, fieldName
, null, null);
600 else if(fieldId
!= 0 && objField
.GetType().IsValueType
)
602 RecordFixup(id
, fieldId
, obj
, info
, fieldName
, null, null);
609 RegisterObject(fieldId
, objField
, null, id
, null, null);
612 info
.AddValue(fieldName
, objField
, (fieldType
!= null)?fieldType
:typeof(object));
619 private object DeserializeComponent(
621 out long componentId
,
622 out long componentHref
,
624 MemberInfo parentMemberInfo
,
637 Type xsiType
= GetComponentType();
638 if(xsiType
!= null) componentType
= xsiType
;
640 if(xmlReader
.HasAttributes
)
642 componentId
= GetId();
643 componentHref
= GetHref();
649 return xmlReader
.ReadElementString();
651 if(componentHref
!= 0)
653 // Move the cursor to the next node
655 return objMgr
.GetObject(componentHref
);
658 if(componentType
== null)
659 return xmlReader
.ReadElementString();
661 componentId
= NextAvailableId
;
662 objReturn
= DeserializeObject(
671 public void RecordFixup(
675 SerializationInfo info
,
677 MemberInfo memberInfo
,
682 objMgr
.RecordDelayedFixup(parentObjectId
, fieldName
, childObjectId
);
684 else if (parentObject
is Array
)
686 if (indices
.Length
== 1)
687 objMgr
.RecordArrayElementFixup (parentObjectId
, indices
[0], childObjectId
);
689 objMgr
.RecordArrayElementFixup (parentObjectId
, (int[])indices
.Clone(), childObjectId
);
693 objMgr
.RecordFixup (parentObjectId
, memberInfo
, childObjectId
);
697 private void RegisterObject (
699 object objectInstance
,
700 SerializationInfo info
,
702 MemberInfo parentObjectMember
,
705 if (parentObjectId
== 0) indices
= null;
707 if (!objectInstance
.GetType().IsValueType
|| parentObjectId
== 0)
708 objMgr
.RegisterObject (objectInstance
, objectId
, info
, 0, null, null);
711 if(objMgr
.GetObject(objectId
) != null)
712 throw new SerializationException("Object already registered");
713 if (indices
!= null) indices
= (int[])indices
.Clone();
714 objMgr
.RegisterObject (
724 TypeMetadata
GetTypeMetadata (Type type
)
726 TypeMetadata tm
= _fieldIndices
[type
] as TypeMetadata
;
727 if (tm
!= null) return tm
;
729 tm
= new TypeMetadata ();
730 tm
.MemberInfos
= FormatterServices
.GetSerializableMembers (type
, _context
);
732 tm
.Indices
= new Hashtable();
733 for(int i
= 0; i
< tm
.MemberInfos
.Length
; i
++)
734 tm
.Indices
.Add (tm
.MemberInfos
[i
].Name
, i
);
736 _fieldIndices
[type
] = tm
;