Utilizar una resolución del contrato de datos
Una resolución del contrato de datos le permite configurar los tipos conocidos dinámicamente. Se necesitan tipos conocidos al serializar o deserializar un tipo no esperado por un contrato de datos. Para obtener más información sobre los tipos conocidos, consulte Tipos conocidos de contratos de datos. Los tipos conocidos se suelen especificar de modo estático. Esto significa que tendría que conocer todos los tipos posibles que puede recibir una operación mientras la implementa. Hay escenarios en los que no esto no se cumple y es importante saber especificar los tipos conocidos de forma dinámica.
Crear una resolución del contrato de datos
La creación de una resolución del contrato de datos supone la implementación de dos métodos, TryResolveType y ResolveName. Estos dos métodos implementan devoluciones de llamada que se utilizan durante la serialización y la deserialización respectivamente. El método TryResolveType se invoca durante la serialización y toma un tipo de contrato de datos para asignarlo a un espacio de nombres y a un nombre xsi:type
. El método ResolveName se invoca durante la deserialización y toma un espacio de nombres y un nombre xsi:type
y lo resuelve como un tipo de contrato de datos. Ambos métodos tienen un parámetro knownTypeResolver
que se puede emplear para usar la resolución de tipo conocido predeterminada en la implementación.
En el siguiente ejemplo, se muestra cómo implementar una clase DataContractResolver para realizar asignaciones desde y hacia un tipo de contrato de datos denominado Customer
derivado de una Person
del tipo de contrato de datos.
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);
}
}
}
Cuando haya definido una DataContractResolver, puede utilizarla pasándola al constructor DataContractSerializer, tal y como se muestra en el siguiente ejemplo.
XmlObjectSerializer serializer = new DataContractSerializer(typeof(Customer), null, Int32.MaxValue, false, false, null, new MyCustomerResolver());
Puede especificar la clase DataContractResolver en una llamada a los métodos DataContractSerializer.ReadObject o DataContractSerializer.WriteObject, tal y como se muestra en el siguiente ejemplo.
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()));
También puede establecerla en DataContractSerializerOperationBehavior, tal y como se muestra en el siguiente ejemplo.
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();
Puede especificar mediante declaración una resolución de contrato de datos implementando un atributo que pueda aplicarse a un servicio. Para obtener más información, consulte el ejemplo de KnownAssemblyAttribute. En este ejemplo se implementa un atributo denominado "KnownAssembly", que agrega una resolución de contrato de datos personalizado al comportamiento del servicio.