データ コントラクト リゾルバーを使用すると、既知の型を動的に構成できます。 データ コントラクトで予期されない型をシリアル化または逆シリアル化する場合は、既知の型が必要です。 既知の型の詳細については、「 データ コントラクトの既知の型」を参照してください。 既知の型は、通常は静的に指定されます。 つまり、操作の実装中に操作が受け取る可能性のあるすべての型を把握する必要があります。 これが正しくなく、既知の型を動的に指定できることが重要なシナリオがあります。
データ コントラクト リゾルバーの作成
データ コントラクト リゾルバーの作成には、 TryResolveType と ResolveNameの 2 つのメソッドを実装する必要があります。 これら 2 つのメソッドは、それぞれシリアル化と逆シリアル化の間に使用されるコールバックを実装します。
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" という名前の属性を実装します。