{
KnownTypeCollection types;
IDataContractSurrogate surrogate;
+ DataContractResolver resolver; // new in 4.0.
// 3.5 SP1 supports deserialization by reference (id->obj).
// Though unlike XmlSerializer, it does not support forward-
// reference resolution i.e. a referenced object must appear
Hashtable references = new Hashtable ();
public static object Deserialize (XmlReader reader, Type type,
- KnownTypeCollection knownTypes, IDataContractSurrogate surrogate,
- string name, string Namespace, bool verifyObjectName)
+ KnownTypeCollection knownTypes, IDataContractSurrogate surrogate, DataContractResolver resolver,
+ string name, string ns, bool verifyObjectName)
{
- reader.MoveToContent();
+ reader.MoveToContent ();
if (verifyObjectName)
- Verify (knownTypes, type, name, Namespace, reader);
- return new XmlFormatterDeserializer (knownTypes, surrogate).Deserialize (type, reader);
+ if (reader.NodeType != XmlNodeType.Element ||
+ reader.LocalName != name ||
+ reader.NamespaceURI != ns)
+ throw new SerializationException (String.Format ("Expected element '{0}' in namespace '{1}', but found {2} node '{3}' in namespace '{4}'", name, ns, reader.NodeType, reader.LocalName, reader.NamespaceURI));
+// Verify (knownTypes, type, name, ns, reader);
+ return new XmlFormatterDeserializer (knownTypes, surrogate, resolver).Deserialize (type, reader);
}
// Verify the top element name and namespace.
private XmlFormatterDeserializer (
KnownTypeCollection knownTypes,
- IDataContractSurrogate surrogate)
+ IDataContractSurrogate surrogate,
+ DataContractResolver resolver)
{
this.types = knownTypes;
this.surrogate = surrogate;
+ this.resolver = resolver;
}
public Hashtable References {
get { return references; }
}
- // At the beginning phase, we still have to instantiate a new
- // target object even if fromContent is true.
+ // This method handles z:Ref, xsi:nil and primitive types, and then delegates to DeserializeByMap() for anything else.
public object Deserialize (Type type, XmlReader reader)
- {
- string label = reader.GetAttribute ("Id", KnownTypeCollection.MSSimpleNamespace);
- object o = DeserializeCore (type, reader);
-
- if (label != null)
- references.Add (label, o);
-
- return o;
- }
-
- public object DeserializeCore (Type type, XmlReader reader)
{
QName graph_qname = types.GetQName (type);
string itype = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
throw new SerializationException (String.Format ("Value type {0} cannot be null.", type));
}
- bool isEmpty = reader.IsEmptyElement;
- reader.ReadStartElement ();
-
- object res = DeserializeContent (graph_qname, type, reader, isEmpty);
-
- reader.MoveToContent ();
- if (!isEmpty && reader.NodeType == XmlNodeType.EndElement)
- reader.ReadEndElement ();
- else if (!isEmpty && reader.NodeType != XmlNodeType.None)
- throw new SerializationException (String.Format ("Deserializing type '{3}'. Expecting state 'EndElement'. Encountered state '{0}' with name '{1}' with namespace '{2}'.", reader.NodeType, reader.Name, reader.NamespaceURI, type.FullName));
- return res;
- }
+ if (KnownTypeCollection.GetPrimitiveTypeFromName (graph_qname.Name) != null) {
+ string id = reader.GetAttribute ("Id", KnownTypeCollection.MSSimpleNamespace);
- object DeserializeContent (QName name, Type type, XmlReader reader, bool isEmpty)
- {
- if (KnownTypeCollection.GetPrimitiveTypeFromName (name.Name) != null) {
string value;
- if (isEmpty) {
+ if (reader.IsEmptyElement) {
+ reader.Read (); // advance
if (type.IsValueType)
return Activator.CreateInstance (type);
else
value = String.Empty;
}
else
- value = reader.ReadContentAsString ();
- return KnownTypeCollection.PredefinedTypeStringToObject (value, name.Name, reader);
+ value = reader.ReadElementContentAsString ();
+ object ret = KnownTypeCollection.PredefinedTypeStringToObject (value, graph_qname.Name, reader);
+ if (id != null) {
+ if (references.ContainsKey (id))
+ throw new InvalidOperationException (String.Format ("Object with Id '{0}' already exists as '{1}'", id, references [id]));
+ references.Add (id, ret);
+ }
+ return ret;
}
+ return DeserializeByMap (graph_qname, type, reader);
+ }
+
+ object DeserializeByMap (QName name, Type type, XmlReader reader)
+ {
SerializationMap map = types.FindUserMap (name);
- if (map == null && (name.Namespace == KnownTypeCollection.MSArraysNamespace ||
+ if (map == null && (name.Name.StartsWith ("ArrayOf", StringComparison.Ordinal) ||
+ name.Namespace == KnownTypeCollection.MSArraysNamespace ||
name.Namespace.StartsWith (KnownTypeCollection.DefaultClrNamespaceBase, StringComparison.Ordinal))) {
var it = GetTypeFromNamePair (name.Name, name.Namespace);
types.TryRegister (it);
if (map == null)
throw new SerializationException (String.Format ("Unknown type {0} is used for DataContract with reference of name {1}. Any derived types of a data contract or a data member should be added to KnownTypes.", type, name));
- if (isEmpty)
- return map.DeserializeEmptyContent (reader, this);
- else
- return map.DeserializeContent (reader, this);
+ return map.DeserializeObject (reader, this);
}
Type GetTypeFromNamePair (string name, string ns)
Type p = KnownTypeCollection.GetPrimitiveTypeFromName (name); // FIXME: namespace?
if (p != null)
return p;
- if (name.StartsWith ("ArrayOf", StringComparison.Ordinal) && ns == KnownTypeCollection.MSArraysNamespace)
- return GetTypeFromNamePair (name.Substring (7), String.Empty).MakeArrayType ();
+ bool makeArray = false;
+ if (name.StartsWith ("ArrayOf", StringComparison.Ordinal)) {
+ name = name.Substring (7); // strip "ArrayOf"
+ if (ns == KnownTypeCollection.MSArraysNamespace)
+ return GetTypeFromNamePair (name, String.Empty).MakeArrayType ();
+ makeArray = true;
+ }
- int xlen = KnownTypeCollection.DefaultClrNamespaceBase.Length;
- string clrns = ns.Length > xlen ? ns.Substring (xlen) : null;
+ string dnsb = KnownTypeCollection.DefaultClrNamespaceBase;
+ string clrns = ns.StartsWith (dnsb, StringComparison.Ordinal) ? ns.Substring (dnsb.Length) : ns;
foreach (var ass in AppDomain.CurrentDomain.GetAssemblies ()) {
- foreach (var t in ass.GetTypes ()) {
- var dca = t.GetCustomAttribute<DataContractAttribute> (true);
- if (dca != null && dca.Name == name && dca.Namespace == ns)
- return t;
+ Type [] types;
+
+#if MOONLIGHT
+ try {
+ types = ass.GetTypes ();
+ } catch (System.Reflection.ReflectionTypeLoadException rtle) {
+ types = rtle.Types;
+ }
+#else
+ types = ass.GetTypes ();
+#endif
+ if (types == null)
+ continue;
+
+ foreach (var t in types) {
+ // there can be null entries or exception throw to access the attribute -
+ // at least when some referenced assemblies could not be loaded (affects moonlight)
+ if (t == null)
+ continue;
+
+ try {
+ var dca = t.GetCustomAttribute<DataContractAttribute> (true);
+ if (dca != null && dca.Name == name && dca.Namespace == ns)
+ return makeArray ? t.MakeArrayType () : t;
+ }
+ catch (TypeLoadException tle) {
+ Console.Error.WriteLine (tle);
+ continue;
+ }
+ catch (FileNotFoundException fnfe) {
+ Console.Error.WriteLine (fnfe);
+ continue;
+ }
+
if (clrns != null && t.Name == name && t.Namespace == clrns)
- return t;
+ return makeArray ? t.MakeArrayType () : t;
}
}
throw new XmlException (String.Format ("Type not found; name: {0}, namespace: {1}", name, ns));