使用数据协定解析程序

使用数据协定解析程序可以动态配置已知类型。 序列化或反序列化并非数据协定所需的类型时,要求提供已知类型。 有关已知类型的详细信息,请参阅数据协定已知类型。 已知类型通常以静态方式指定。 这意味着您必须了解在实现某个操作期间,该操作可能接收的所有可能类型。 在某些方案中无法做到这一点,因此能够以动态方式指定已知类型十分重要。

创建数据协定解析程序

创建数据协定解析程序涉及到实现两个方法:TryResolveTypeResolveName。 这两个方法分别实现在序列化和反序列化期间使用的回调。 在序列化期间将调用 TryResolveType 方法,用于获取数据协定类型并将其映射到 xsi:type 名称和命名空间。 在反序列化期间将调用 ResolveName 方法,用于获取 xsi:type 名称和命名空间并将其解析为数据协定类型。 这两个方法均具有 knownTypeResolver 参数,该参数可用于在实现中使用默认已知类型解析程序。

下面的示例演示了如何实现 DataContractResolver,以映射到派生自数据协定类型 Customer 的数据协定类型 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);  
        }  
    }  
}  

一旦定义了 DataContractResolver,即可将它传递到 DataContractSerializer 构造函数加以使用,如下面的示例所示。

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

可以在对 DataContractResolverDataContractSerializer.ReadObject 方法的调用中指定 DataContractSerializer.WriteObject,如下面的示例所示。

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()));  

或者,可以在 DataContractSerializerOperationBehavior 上设置该构造函数,如下面的示例所示。

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();  

通过实现可以应用于服务的特性,可以通过声明方式指定数据协定解析程序。 有关详细信息,请参阅 KnownAssemblyAttribute 示例。 此示例实现名为“KnownAssembly”的特性,该特性向服务的行为添加一个自定义数据协定解析程序。

请参阅