提交 47fd1c3a 编写于 作者: A Atsushi Eno

Implement DataContractResolver support. At least TryResolveType in serializer should work.

上级 2e0e15d7
...@@ -33,7 +33,6 @@ namespace System.Runtime.Serialization ...@@ -33,7 +33,6 @@ namespace System.Runtime.Serialization
{ {
// See http://msdn.microsoft.com/en-us/library/ee358759.aspx // See http://msdn.microsoft.com/en-us/library/ee358759.aspx
#if NET_4_0 #if NET_4_0
[MonoTODO ("not in use yet")]
public public
#else #else
internal internal
...@@ -44,4 +43,40 @@ namespace System.Runtime.Serialization ...@@ -44,4 +43,40 @@ namespace System.Runtime.Serialization
public abstract bool TryResolveType (Type type, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace); public abstract bool TryResolveType (Type type, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace);
} }
internal class DefaultDataContractResolver : DataContractResolver
{
public DefaultDataContractResolver (DataContractSerializer serializer)
{
this.serializer = serializer;
}
DataContractSerializer serializer;
XmlDictionary dictionary;
public override Type ResolveName (string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver)
{
var map = serializer.InternalKnownTypes.FindUserMap (new XmlQualifiedName (typeName, typeNamespace));
if (map == null)
serializer.InternalKnownTypes.Add (declaredType);
if (map != null)
return map.RuntimeType;
return null;
}
public override bool TryResolveType (Type type, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace)
{
var map = serializer.InternalKnownTypes.FindUserMap (type);
if (map == null) {
typeName = null;
typeNamespace = null;
return false;
} else {
dictionary = dictionary ?? new XmlDictionary ();
typeName = dictionary.Add (map.XmlName.Name);
typeNamespace = dictionary.Add (map.XmlName.Namespace);
return true;
}
}
}
} }
...@@ -52,6 +52,7 @@ namespace System.Runtime.Serialization ...@@ -52,6 +52,7 @@ namespace System.Runtime.Serialization
ReadOnlyCollection<Type> returned_known_types; ReadOnlyCollection<Type> returned_known_types;
KnownTypeCollection known_types; KnownTypeCollection known_types;
IDataContractSurrogate surrogate; IDataContractSurrogate surrogate;
DataContractResolver resolver, default_resolver;
int max_items = 0x10000; // FIXME: could be from config. int max_items = 0x10000; // FIXME: could be from config.
...@@ -70,9 +71,8 @@ namespace System.Runtime.Serialization ...@@ -70,9 +71,8 @@ namespace System.Runtime.Serialization
if (type == null) if (type == null)
throw new ArgumentNullException ("type"); throw new ArgumentNullException ("type");
this.type = type; this.type = type;
known_types = new KnownTypeCollection ();
PopulateTypes (knownTypes); PopulateTypes (knownTypes);
known_types.TryRegister (type); known_types.Add (type);
QName qname = known_types.GetQName (type); QName qname = known_types.GetQName (type);
FillDictionaryString (qname.Name, qname.Namespace); FillDictionaryString (qname.Name, qname.Namespace);
...@@ -220,7 +220,7 @@ namespace System.Runtime.Serialization ...@@ -220,7 +220,7 @@ namespace System.Runtime.Serialization
if (knownTypes != null) { if (knownTypes != null) {
foreach (Type t in knownTypes) foreach (Type t in knownTypes)
known_types.TryRegister (t); known_types.Add (t);
} }
Type elementType = type; Type elementType = type;
...@@ -231,7 +231,7 @@ namespace System.Runtime.Serialization ...@@ -231,7 +231,7 @@ namespace System.Runtime.Serialization
object [] attrs = elementType.GetCustomAttributes (typeof (KnownTypeAttribute), true); object [] attrs = elementType.GetCustomAttributes (typeof (KnownTypeAttribute), true);
for (int i = 0; i < attrs.Length; i ++) { for (int i = 0; i < attrs.Length; i ++) {
KnownTypeAttribute kt = (KnownTypeAttribute) attrs [i]; KnownTypeAttribute kt = (KnownTypeAttribute) attrs [i];
known_types.TryRegister (kt.Type); known_types.Add (kt.Type);
} }
} }
...@@ -255,8 +255,6 @@ namespace System.Runtime.Serialization ...@@ -255,8 +255,6 @@ namespace System.Runtime.Serialization
ignore_ext = ignoreExtensionDataObject; ignore_ext = ignoreExtensionDataObject;
preserve_refs = preserveObjectReferences; preserve_refs = preserveObjectReferences;
surrogate = dataContractSurrogate; surrogate = dataContractSurrogate;
PopulateTypes (Type.EmptyTypes);
} }
#if NET_4_0 #if NET_4_0
...@@ -264,7 +262,13 @@ namespace System.Runtime.Serialization ...@@ -264,7 +262,13 @@ namespace System.Runtime.Serialization
#else #else
internal internal
#endif #endif
DataContractResolver DataContractResolver { get; private set; } DataContractResolver DataContractResolver {
get { return resolver; }
private set {
resolver = value;
default_resolver = default_resolver ?? new DefaultDataContractResolver (this);
}
}
public bool IgnoreExtensionDataObject { public bool IgnoreExtensionDataObject {
get { return ignore_ext; } get { return ignore_ext; }
...@@ -278,6 +282,10 @@ namespace System.Runtime.Serialization ...@@ -278,6 +282,10 @@ namespace System.Runtime.Serialization
} }
} }
internal KnownTypeCollection InternalKnownTypes {
get { return known_types; }
}
public IDataContractSurrogate DataContractSurrogate { public IDataContractSurrogate DataContractSurrogate {
get { return surrogate; } get { return surrogate; }
} }
...@@ -323,7 +331,7 @@ namespace System.Runtime.Serialization ...@@ -323,7 +331,7 @@ namespace System.Runtime.Serialization
bool isEmpty = reader.IsEmptyElement; bool isEmpty = reader.IsEmptyElement;
object ret = XmlFormatterDeserializer.Deserialize (reader, type, object ret = XmlFormatterDeserializer.Deserialize (reader, type,
known_types, surrogate, DataContractResolver, root_name.Value, root_ns.Value, verifyObjectName); known_types, surrogate, DataContractResolver, default_resolver, root_name.Value, root_ns.Value, verifyObjectName);
// remove temporarily-added known types for // remove temporarily-added known types for
// rootType and object graph type. // rootType and object graph type.
...@@ -399,8 +407,8 @@ namespace System.Runtime.Serialization ...@@ -399,8 +407,8 @@ namespace System.Runtime.Serialization
int startTypeCount = known_types.Count; int startTypeCount = known_types.Count;
XmlFormatterSerializer.Serialize (writer, graph, XmlFormatterSerializer.Serialize (writer, graph,
known_types, type, known_types,
ignore_ext, max_items, root_ns.Value, preserve_refs); ignore_ext, max_items, root_ns.Value, preserve_refs, DataContractResolver, default_resolver);
// remove temporarily-added known types for // remove temporarily-added known types for
// rootType and object graph type. // rootType and object graph type.
...@@ -440,8 +448,21 @@ namespace System.Runtime.Serialization ...@@ -440,8 +448,21 @@ namespace System.Runtime.Serialization
return; return;
} }
QName instName = null; QName rootQName = null;
QName root_qname = known_types.GetQName (rootType); XmlDictionaryString name, ns;
if (DataContractResolver != null && DataContractResolver.TryResolveType (graph.GetType (), type, default_resolver, out name, out ns))
rootQName = new QName (name.Value, ns.Value);
// It is error unless 1) TypeResolver resolved the type name, 2) the object is the exact type, 3) the object is known or 4) the type is primitive.
if (rootQName == null &&
graph.GetType () != type &&
!known_types.Contains (graph.GetType ()) &&
KnownTypeCollection.GetPrimitiveTypeName (graph.GetType ()) == QName.Empty)
throw new SerializationException (String.Format ("Type '{0}' is unexpected. The type should either be registered as a known type, or DataContractResolver should be used.", graph.GetType ()));
QName instName = rootQName;
rootQName = rootQName ?? known_types.GetQName (rootType);
QName graph_qname = known_types.GetQName (graph.GetType ()); QName graph_qname = known_types.GetQName (graph.GetType ());
known_types.Add (graph.GetType ()); known_types.Add (graph.GetType ());
...@@ -450,24 +471,23 @@ namespace System.Runtime.Serialization ...@@ -450,24 +471,23 @@ namespace System.Runtime.Serialization
writer.WriteStartElement (root_name.Value, root_ns.Value); writer.WriteStartElement (root_name.Value, root_ns.Value);
else else
writer.WriteStartElement (root_name, root_ns); writer.WriteStartElement (root_name, root_ns);
if (root_ns.Value != root_qname.Namespace)
if (root_qname.Namespace != KnownTypeCollection.MSSimpleNamespace)
writer.WriteXmlnsAttribute (null, root_qname.Namespace);
if (root_qname == graph_qname) { if (rootQName != graph_qname || rootQName.Namespace != KnownTypeCollection.MSSimpleNamespace && !rootType.IsEnum)
if (root_qname.Namespace != KnownTypeCollection.MSSimpleNamespace && //FIXME: Hack, when should the "i:type" be written?
!rootType.IsEnum) //Not used in case of enums
//FIXME: Hack, when should the "i:type" be written? writer.WriteXmlnsAttribute ("i", XmlSchema.InstanceNamespace);
//Not used in case of enums
writer.WriteXmlnsAttribute ("i", XmlSchema.InstanceNamespace);
if (root_ns.Value != rootQName.Namespace)
if (rootQName.Namespace != KnownTypeCollection.MSSimpleNamespace)
writer.WriteXmlnsAttribute (null, rootQName.Namespace);
if (rootQName == graph_qname)
return; return;
}
/* Different names */ /* Different names */
known_types.Add (rootType); known_types.Add (rootType);
instName = KnownTypeCollection.GetPredefinedTypeName (graph.GetType ()); instName = instName ?? KnownTypeCollection.GetPredefinedTypeName (graph.GetType ());
if (instName == QName.Empty) if (instName == QName.Empty)
/* Not a primitive type */ /* Not a primitive type */
instName = graph_qname; instName = graph_qname;
...@@ -475,10 +495,12 @@ namespace System.Runtime.Serialization ...@@ -475,10 +495,12 @@ namespace System.Runtime.Serialization
/* FIXME: Hack, .. see test WriteObject7 () */ /* FIXME: Hack, .. see test WriteObject7 () */
instName = new QName (instName.Name, XmlSchema.Namespace); instName = new QName (instName.Name, XmlSchema.Namespace);
/* // disabled as it now generates extraneous i:type output.
// output xsi:type as rootType is not equivalent to the graph's type. // output xsi:type as rootType is not equivalent to the graph's type.
writer.WriteStartAttribute ("i", "type", XmlSchema.InstanceNamespace); writer.WriteStartAttribute ("i", "type", XmlSchema.InstanceNamespace);
writer.WriteQualifiedName (instName.Name, instName.Namespace); writer.WriteQualifiedName (instName.Name, instName.Namespace);
writer.WriteEndAttribute (); writer.WriteEndAttribute ();
*/
} }
public override void WriteEndObject (XmlDictionaryWriter writer) public override void WriteEndObject (XmlDictionaryWriter writer)
......
...@@ -451,7 +451,7 @@ namespace System.Runtime.Serialization ...@@ -451,7 +451,7 @@ namespace System.Runtime.Serialization
GetDataMemberAttribute (pi); GetDataMemberAttribute (pi);
if (dma == null) if (dma == null)
continue; continue;
KnownTypes.TryRegister (pi.PropertyType); KnownTypes.Add (pi.PropertyType);
var map = KnownTypes.FindUserMap (pi.PropertyType); var map = KnownTypes.FindUserMap (pi.PropertyType);
if (!pi.CanRead || (!pi.CanWrite && !(map is ICollectionTypeMap))) if (!pi.CanRead || (!pi.CanWrite && !(map is ICollectionTypeMap)))
throw new InvalidDataContractException (String.Format ( throw new InvalidDataContractException (String.Format (
......
...@@ -43,15 +43,15 @@ namespace System.Runtime.Serialization ...@@ -43,15 +43,15 @@ namespace System.Runtime.Serialization
{ {
KnownTypeCollection types; KnownTypeCollection types;
IDataContractSurrogate surrogate; IDataContractSurrogate surrogate;
DataContractResolver resolver; // new in 4.0. DataContractResolver resolver, default_resolver; // new in 4.0.
// 3.5 SP1 supports deserialization by reference (id->obj). // 3.5 SP1 supports deserialization by reference (id->obj).
// Though unlike XmlSerializer, it does not support forward- // Though unlike XmlSerializer, it does not support forward-
// reference resolution i.e. a referenced object must appear // reference resolution i.e. a referenced object must appear
// before any references to it. // before any references to it.
Hashtable references = new Hashtable (); Hashtable references = new Hashtable ();
public static object Deserialize (XmlReader reader, Type type, public static object Deserialize (XmlReader reader, Type declaredType,
KnownTypeCollection knownTypes, IDataContractSurrogate surrogate, DataContractResolver resolver, KnownTypeCollection knownTypes, IDataContractSurrogate surrogate, DataContractResolver resolver, DataContractResolver defaultResolver,
string name, string ns, bool verifyObjectName) string name, string ns, bool verifyObjectName)
{ {
reader.MoveToContent (); reader.MoveToContent ();
...@@ -60,14 +60,14 @@ namespace System.Runtime.Serialization ...@@ -60,14 +60,14 @@ namespace System.Runtime.Serialization
reader.LocalName != name || reader.LocalName != name ||
reader.NamespaceURI != ns) 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)); 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); // Verify (knownTypes, declaredType, name, ns, reader);
return new XmlFormatterDeserializer (knownTypes, surrogate, resolver).Deserialize (type, reader); return new XmlFormatterDeserializer (knownTypes, surrogate, resolver, defaultResolver).Deserialize (declaredType, reader);
} }
// Verify the top element name and namespace. // Verify the top element name and namespace.
private static void Verify (KnownTypeCollection knownTypes, Type type, string name, string Namespace, XmlReader reader) private static void Verify (KnownTypeCollection knownTypes, Type type, string name, string Namespace, XmlReader reader)
{ {
QName graph_qname = new QName (reader.Name, reader.NamespaceURI); QName graph_qname = new QName (reader.LocalName, reader.NamespaceURI);
if (graph_qname.Name == name && graph_qname.Namespace == Namespace) if (graph_qname.Name == name && graph_qname.Namespace == Namespace)
return; return;
...@@ -90,11 +90,13 @@ namespace System.Runtime.Serialization ...@@ -90,11 +90,13 @@ namespace System.Runtime.Serialization
private XmlFormatterDeserializer ( private XmlFormatterDeserializer (
KnownTypeCollection knownTypes, KnownTypeCollection knownTypes,
IDataContractSurrogate surrogate, IDataContractSurrogate surrogate,
DataContractResolver resolver) DataContractResolver resolver,
DataContractResolver defaultResolver)
{ {
this.types = knownTypes; this.types = knownTypes;
this.surrogate = surrogate; this.surrogate = surrogate;
this.resolver = resolver; this.resolver = resolver;
this.default_resolver = defaultResolver;
} }
public Hashtable References { public Hashtable References {
...@@ -135,6 +137,9 @@ namespace System.Runtime.Serialization ...@@ -135,6 +137,9 @@ namespace System.Runtime.Serialization
throw new SerializationException (String.Format ("Value type {0} cannot be null.", type)); throw new SerializationException (String.Format ("Value type {0} cannot be null.", type));
} }
if (resolver != null)
type = resolver.ResolveName (graph_qname.Name, graph_qname.Namespace, type, default_resolver) ?? type;
if (KnownTypeCollection.GetPrimitiveTypeFromName (graph_qname.Name) != null) { if (KnownTypeCollection.GetPrimitiveTypeFromName (graph_qname.Name) != null) {
string id = reader.GetAttribute ("Id", KnownTypeCollection.MSSimpleNamespace); string id = reader.GetAttribute ("Id", KnownTypeCollection.MSSimpleNamespace);
...@@ -168,7 +173,7 @@ namespace System.Runtime.Serialization ...@@ -168,7 +173,7 @@ namespace System.Runtime.Serialization
name.Namespace == KnownTypeCollection.MSArraysNamespace || name.Namespace == KnownTypeCollection.MSArraysNamespace ||
name.Namespace.StartsWith (KnownTypeCollection.DefaultClrNamespaceBase, StringComparison.Ordinal))) { name.Namespace.StartsWith (KnownTypeCollection.DefaultClrNamespaceBase, StringComparison.Ordinal))) {
var it = GetTypeFromNamePair (name.Name, name.Namespace); var it = GetTypeFromNamePair (name.Name, name.Namespace);
types.TryRegister (it); types.Add (it);
map = types.FindUserMap (name); map = types.FindUserMap (name);
} }
if (map == null) if (map == null)
......
...@@ -47,28 +47,30 @@ namespace System.Runtime.Serialization ...@@ -47,28 +47,30 @@ namespace System.Runtime.Serialization
bool save_id; bool save_id;
bool ignore_unknown; bool ignore_unknown;
IDataContractSurrogate surrogate; IDataContractSurrogate surrogate;
DataContractResolver resolver, default_resolver; // new in 4.0
int max_items; int max_items;
ArrayList objects = new ArrayList (); ArrayList objects = new ArrayList ();
Hashtable references = new Hashtable (); // preserve possibly referenced objects to ids. (new in 3.5 SP1) Hashtable references = new Hashtable (); // preserve possibly referenced objects to ids. (new in 3.5 SP1)
public static void Serialize (XmlDictionaryWriter writer, object graph, public static void Serialize (XmlDictionaryWriter writer, object graph, Type declaredType, KnownTypeCollection types,
KnownTypeCollection types, bool ignoreUnknown, int maxItems, string root_ns, bool preserveObjectReferences, DataContractResolver resolver, DataContractResolver defaultResolver)
bool ignoreUnknown, int maxItems, string root_ns, bool preserveObjectReferences)
{ {
new XmlFormatterSerializer (writer, types, ignoreUnknown, maxItems, root_ns, preserveObjectReferences) new XmlFormatterSerializer (writer, types, ignoreUnknown, maxItems, root_ns, preserveObjectReferences, resolver, defaultResolver)
.Serialize (graph != null ? graph.GetType () : null, graph); .Serialize (/*graph != null ? graph.GetType () : */declaredType, graph); // FIXME: I believe it should always use declaredType, but such a change brings some test breakages.
} }
public XmlFormatterSerializer (XmlDictionaryWriter writer, public XmlFormatterSerializer (XmlDictionaryWriter writer, KnownTypeCollection types, bool ignoreUnknown,
KnownTypeCollection types, int maxItems, string root_ns, bool preserveObjectReferences,
bool ignoreUnknown, int maxItems, string root_ns, bool preserveObjectReferences) DataContractResolver resolver, DataContractResolver defaultResolver)
{ {
this.writer = writer; this.writer = writer;
this.types = types; this.types = types;
ignore_unknown = ignoreUnknown; ignore_unknown = ignoreUnknown;
max_items = maxItems; max_items = maxItems;
PreserveObjectReferences = preserveObjectReferences; PreserveObjectReferences = preserveObjectReferences;
this.resolver = resolver;
this.default_resolver = defaultResolver;
} }
public bool PreserveObjectReferences { get; private set; } public bool PreserveObjectReferences { get; private set; }
...@@ -90,9 +92,17 @@ namespace System.Runtime.Serialization ...@@ -90,9 +92,17 @@ namespace System.Runtime.Serialization
if (graph == null) if (graph == null)
writer.WriteAttributeString ("nil", XmlSchema.InstanceNamespace, "true"); writer.WriteAttributeString ("nil", XmlSchema.InstanceNamespace, "true");
else { else {
QName resolvedQName = null;
if (resolver != null) {
XmlDictionaryString rname, rns;
if (resolver.TryResolveType (graph != null ? graph.GetType () : typeof (object), type, default_resolver, out rname, out rns))
resolvedQName = new QName (rname.Value, rns.Value);
}
Type actualType = graph.GetType (); Type actualType = graph.GetType ();
SerializationMap map = types.FindUserMap (actualType); SerializationMap map;
map = types.FindUserMap (actualType);
// For some collection types, the actual type does not matter. So get nominal serialization type instead. // For some collection types, the actual type does not matter. So get nominal serialization type instead.
// (The code below also covers the lines above, but I don't remove above lines to avoid extra search cost.) // (The code below also covers the lines above, but I don't remove above lines to avoid extra search cost.)
if (map == null) { if (map == null) {
...@@ -106,7 +116,7 @@ namespace System.Runtime.Serialization ...@@ -106,7 +116,7 @@ namespace System.Runtime.Serialization
} }
if (actualType != type && (map == null || map.OutputXsiType)) { if (actualType != type && (map == null || map.OutputXsiType)) {
QName qname = types.GetXmlName (actualType); QName qname = resolvedQName ?? types.GetXmlName (actualType);
string name = qname.Name; string name = qname.Name;
string ns = qname.Namespace; string ns = qname.Namespace;
if (qname == QName.Empty) { if (qname == QName.Empty) {
...@@ -116,7 +126,7 @@ namespace System.Runtime.Serialization ...@@ -116,7 +126,7 @@ namespace System.Runtime.Serialization
ns = XmlSchema.Namespace; ns = XmlSchema.Namespace;
if (writer.LookupPrefix (ns) == null) // it goes first (extraneous, but it makes att order compatible) if (writer.LookupPrefix (ns) == null) // it goes first (extraneous, but it makes att order compatible)
writer.WriteXmlnsAttribute (null, ns); writer.WriteXmlnsAttribute (null, ns);
writer.WriteStartAttribute ("type", XmlSchema.InstanceNamespace); writer.WriteStartAttribute ("i", "type", XmlSchema.InstanceNamespace);
writer.WriteQualifiedName (name, ns); writer.WriteQualifiedName (name, ns);
writer.WriteEndAttribute (); writer.WriteEndAttribute ();
} }
......
...@@ -172,7 +172,7 @@ namespace System.Runtime.Serialization ...@@ -172,7 +172,7 @@ namespace System.Runtime.Serialization
if (predefined_types.FirstOrDefault (i => i.ClrType == type) != null) if (predefined_types.FirstOrDefault (i => i.ClrType == type) != null)
return true; return true;
known_types.TryRegister (type); known_types.Add (type);
return known_types.FindUserMap (type) != null; return known_types.FindUserMap (type) != null;
} }
...@@ -219,7 +219,7 @@ namespace System.Runtime.Serialization ...@@ -219,7 +219,7 @@ namespace System.Runtime.Serialization
if (imported_types.FirstOrDefault (i => i.ClrType == type) != null) if (imported_types.FirstOrDefault (i => i.ClrType == type) != null)
return false; return false;
known_types.TryRegister (type); known_types.Add (type);
var map = known_types.FindUserMap (type); var map = known_types.FindUserMap (type);
if (map == null) if (map == null)
return false; return false;
......
System.Runtime.Serialization/DataContractResolverTest.cs
System.Runtime.Serialization/XmlObjectSerializerTest.cs System.Runtime.Serialization/XmlObjectSerializerTest.cs
System.Runtime.Serialization/XsdDataContractExporterTest.cs System.Runtime.Serialization/XsdDataContractExporterTest.cs
System.Runtime.Serialization/XsdDataContractImporterTest.cs System.Runtime.Serialization/XsdDataContractImporterTest.cs
......
//
// XmlObjectSerializerTest.cs
//
// Author:
// Atsushi Enomoto <atsushi@ximian.com>
// Ankit Jain <JAnkit@novell.com>
//
// Copyright (C) 2005 Novell, Inc. http://www.novell.com
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
#if NET_4_0
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.IO;
using System.Net;
using System.Runtime.Serialization;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using NUnit.Framework;
namespace MonoTests.System.Runtime.Serialization
{
[TestFixture]
public class DataContractResolverTest
{
[Test]
public void UseCase1 ()
{
var ds = new DataContractSerializer (typeof (Colors), null, 10000, false, false, null, new MyResolver ());
var sw = new StringWriter ();
using (var xw = XmlWriter.Create (sw))
ds.WriteObject (xw, new ResolvedClass ());
// xml and xml2 are equivalent in infoset, except for prefixes and position of namespace nodes. So the difference should not matter.
string xml = @"<?xml version='1.0' encoding='utf-16'?><Colors xmlns:i='http://www.w3.org/2001/XMLSchema-instance' xmlns:d1p1='urn:dummy' i:type='d1p1:ResolvedClass' xmlns='http://schemas.datacontract.org/2004/07/MonoTests.System.Runtime.Serialization'><Baz xmlns='http://schemas.datacontract.org/2004/07/'>c74376f0-5517-4cb7-8a07-35026423f565</Baz></Colors>".Replace ('\'', '"');
string xml2 = @"<?xml version='1.0' encoding='utf-16'?><Colors xmlns:i='http://www.w3.org/2001/XMLSchema-instance' xmlns:d1p1='urn:dummy' xmlns:d1p2='http://schemas.datacontract.org/2004/07/' i:type='d1p2:ResolvedClass' xmlns='http://schemas.datacontract.org/2004/07/MonoTests.System.Runtime.Serialization'><d1p2:Baz>c74376f0-5517-4cb7-8a07-35026423f565</d1p2:Baz></Colors>".Replace ('\'', '"');
try {
Assert.AreEqual (xml, sw.ToString ());
} catch (AssertionException) {
Assert.AreEqual (xml2, sw.ToString ());
}
}
}
public class MyResolver : DataContractResolver
{
public override bool TryResolveType (Type type, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace)
{
//Console.WriteLine ("TryResolveType: {0} {1}", type, declaredType);
if (knownTypeResolver.TryResolveType (type, declaredType, null, out typeName, out typeNamespace))
return true;
return SafeResolveType (type, out typeName, out typeNamespace);
}
XmlDictionary dic = new XmlDictionary ();
bool SafeResolveType (Type type, out XmlDictionaryString name, out XmlDictionaryString ns)
{
// Console.WriteLine ("SafeResolveType: {0}", type);
name = dic.Add (type.Name);
ns = dic.Add (type.Namespace ?? "urn:dummy");
return true;
}
public override Type ResolveName (string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver)
{
//Console.WriteLine ("ResolveName: {0} {1} {2}", typeName, typeNamespace, declaredType);
return knownTypeResolver.ResolveName (typeName, typeNamespace, declaredType, null);
}
}
}
[DataContract]
public class ResolvedClass
{
[DataMember]
public Guid Baz = Guid.Parse ("c74376f0-5517-4cb7-8a07-35026423f565");
}
#endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册