データ コントラクト リゾルバーの使用
データ コントラクト リゾルバーでは、既知の型を動的に構成できます。 データ コントラクトが予期しない型をシリアル化または逆シリアル化するときには、既知の型が必要です。 既知の型の詳細については、「既知のデータ コントラクト型」を参照してください。 通常、既知の型は静的に指定されます。 これは、操作を実装する間に操作が受け取る可能性のあるすべての型を把握しておく必要があることを意味します。 これが当てはまらず、既知の型を動的に指定できることが重要である場合もあります。
データ コントラクト リゾルバーの作成
データ コントラクト リゾルバーを作成する際には、2 つのメソッド、TryResolveType および ResolveName を実装します。 これらの 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" と呼ばれる属性を実装します。これはサービスの動作にカスタム データ コントラクト リゾルバーを追加します。