数据协定解析程序允许动态配置已知类型。 序列化或反序列化数据协定不需要的类型时,需要已知类型。 有关已知类型的详细信息,请参阅 数据协定已知类型。 已知类型通常以静态方式指定。 这意味着,在实现操作时,必须知道操作可能接收的所有可能类型。 在某些情况下,这并不真实,并且能够动态指定已知类型非常重要。
创建数据协定解析程序
创建数据协定解析程序涉及实现两种方法, TryResolveType 以及 ResolveName。 这两个方法分别实现在序列化和反序列化期间使用的回调。 在序列化期间将调用 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());
可以在调用DataContractResolver或DataContractSerializer.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”的属性,该属性将自定义数据协定解析程序添加到服务的行为。