Uso di un resolver del contratto dati
Un resolver del contratto dati consente di configurare tipi noti in modo dinamico. I tipi noti sono necessari se si serializza o deserializza un tipo non previsto da un contratto dati. Per altre informazioni sui tipi noti, vedere Tipi noti del contratto di dati. I tipi noti vengono in genere specificati in modo statico. Ciò significa che è necessario conoscere tutti i tipi possibili che un'operazione può ricevere durante l'implementazione dell'operazione. Poiché in alcuni scenari tale condizione non è possibile, è importante specificare i tipi noti in modo dinamico.
Creazione di un resolver del contratto dati
La creazione di un resolver del contratto dati prevede l'implementazione di due metodi, TryResolveType e ResolveName. Questi due metodi implementano callback utilizzati rispettivamente durante la serializzazione e la deserializzazione. Il metodo TryResolveType viene richiamato durante la serializzazione, utilizza un tipo di contratto dati e ne esegue il mapping a un nome e a uno spazio dei nomi xsi:type
. Il metodo ResolveName viene richiamato durante la deserializzazione, utilizza un nome e uno spazio dei nomi xsi:type
e lo risolve in un tipo di contratto dati. Entrambi questi metodi dispongono di un parametro knownTypeResolver
che può essere impiegato per utilizzare il resolver del tipo noto predefinito nell'implementazione.
Nell'esempio seguente viene mostrato come implementare un DataContractResolver con cui eseguire il mapping con un tipo di contratto dati denominato Customer
derivato da un tipo di contratto dati 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);
}
}
}
Una volta definito un DataContractResolver, è possibile utilizzarlo passandolo al costruttore DataContractSerializer, come indicato nell'esempio seguente.
XmlObjectSerializer serializer = new DataContractSerializer(typeof(Customer), null, Int32.MaxValue, false, false, null, new MyCustomerResolver());
È possibile specificare un DataContractResolver in una chiamata ai metodi DataContractSerializer.ReadObject o DataContractSerializer.WriteObject, come indicato nell'esempio seguente.
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()));
È in alternativa possibile impostarlo su DataContractSerializerOperationBehavior, come indicato nell'esempio seguente.
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();
È possibile specificare in modo dichiarativo un resolver del contratto dati implementando un attributo che possa essere applicato a un servizio. Per altre informazioni, vedere l'esempio KnownAssemblyAttribute. In questo esempio viene implementato un attributo denominato "KnownAssembly" che aggiunge un resolver del contratto dati personalizzato al comportamento del servizio.