Using a Data Contract Resolver

A data contract resolver allows you to configure known types dynamically. Known types are required when serializing or deserializing a type not expected by a data contract. For more information about known types, see Data Contract Known Types. Known types are normally specified statically. This means you would have to know all the possible types an operation may receive while implementing the operation. There are scenarios in which this is not true and being able to specify known types dynamically is important.

Creating a Data Contract Resolver

Creating a data contract resolver involves implementing two methods, TryResolveType and ResolveName. These two methods implement callbacks that are used during serialization and deserialization, respectively. The TryResolveType method is invoked during serialization and takes a data contract type and maps it to an xsi:type name and namespace. The ResolveName method is invoked during deserialization and takes an xsi:type name and namespace and resolves it to a data contract type. Both of these methods have a knownTypeResolver parameter that can be used to use the default known type resolver in your implementation.

The following example shows how to implement a DataContractResolver to map to and from a data contract type named Customer derived from a data contract type Person.

public class MyCustomerResolver : DataContractResolver  
{  
    public override bool TryResolveType(Type dataContractType, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace)  
    {  
        if (dataContractType == typeof(Customer))  
        {  
            XmlDictionary dictionary = new XmlDictionary();  
            typeName = dictionary.Add("SomeCustomer");  
            typeNamespace = dictionary.Add("http://tempuri.com");  
            return true;  
        }  
        else  
        {  
            return knownTypeResolver.TryResolveType(dataContractType, declaredType, null, out typeName, out typeNamespace);  
        }  
    }  
  
    public override Type ResolveName(string typeName, string typeNamespace, DataContractResolver knownTypeResolver)  
    {  
        if (typeName == "SomeCustomer" && typeNamespace == "http://tempuri.com")  
        {  
            return typeof(Customer);  
        }  
        else  
        {  
            return knownTypeResolver.ResolveName(typeName, typeNamespace, null);  
        }  
    }  
}  

Once you have defined a DataContractResolver you can use it by passing it to the DataContractSerializer constructor as shown in the following example.

XmlObjectSerializer serializer = new DataContractSerializer(typeof(Customer), null, Int32.MaxValue, false, false, null, new MyCustomerResolver());  

You can specify a DataContractResolver in a call to the DataContractSerializer.ReadObject or DataContractSerializer.WriteObject methods, as shown in the following example.

MemoryStream ms = new MemoryStream();  
DataContractSerializer serializer = new DataContractSerializer(typeof(Customer));  
XmlDictionaryWriter writer = XmlDictionaryWriter.CreateDictionaryWriter(XmlWriter.Create(ms));  
serializer.WriteObject(writer, new Customer(), new MyCustomerResolver());  
writer.Flush();  
ms.Position = 0;  
Console.WriteLine(((Customer)serializer.ReadObject(XmlDictionaryReader.CreateDictionaryReader(XmlReader.Create(ms)), false, new MyCustomerResolver()));  

Or you can set it on the DataContractSerializerOperationBehavior as shown in the following example.

ServiceHost host = new ServiceHost(typeof(MyService));  
  
ContractDescription cd = host.Description.Endpoints[0].Contract;  
OperationDescription myOperationDescription = cd.Operations.Find("Echo");  
  
DataContractSerializerOperationBehavior serializerBehavior = myOperationDescription.Behaviors.Find<DataContractSerializerOperationBehavior>();  
if (serializerBehavior == null)  
{  
    serializerBehavior = new DataContractSerializerOperationBehavior(myOperationDescription);  
    myOperationDescription.Behaviors.Add(serializerBehavior);  
}  
  
SerializerBehavior.DataContractResolver = new MyCustomerResolver();  

You can declaratively specify a data contract resolver by implementing an attribute that can be applied to a service. For more information, see the KnownAssemblyAttribute sample. This sample implements an attribute called "KnownAssembly" that adds a custom data contract resolver to the service’s behavior.

See also