Compartilhar via


Utilizando um resolvedor de contrato de dados

Um resolver de contrato de dados permite que você configure tipos conhecidos dinamicamente. Tipos conhecidos são necessários ao serializar ou desserializar um tipo não esperado por um contrato de dados. Para obter mais informações sobre tipos conhecidos, consulte Tipos de contratos de dados conhecidos. Os tipos conhecidos normalmente são especificados estaticamente. Isso significa que você precisa saber todos os tipos possíveis que uma operação pode receber durante a implementação da operação. Há cenários em que isso não é verdade e ser capaz de especificar tipos conhecidos dinamicamente é importante.

Criando um resolver de contrato de dados

A criação de um resolver de contrato de dados envolve a implementação de dois métodos, TryResolveType e ResolveName. Esses dois métodos implementam retornos de chamada usados durante a serialização e desserialização, respectivamente. O método TryResolveType é invocado durante a serialização e usa um tipo de contrato de dados e mapeia-o para um nome e um namespace xsi:type. O método ResolveName é invocado durante a desserialização e usa um nome e um namespace xsi:type e o resolve para um tipo de contrato de dados. Esses dois métodos têm um parâmetro knownTypeResolver que pode ser usado para usar o resolver de tipo conhecido padrão em sua implementação.

O exemplo a seguir mostra como implementar um DataContractResolver para mapear para e de um tipo de contrato de dados chamado Customer derivado de um tipo e contrato de dados 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);  
        }  
    }  
}  

Depois de definir um DataContractResolver, você pode usá-lo passando-o para o construtor DataContractSerializer, conforme mostrado no exemplo a seguir.

XmlObjectSerializer serializer = new DataContractSerializer(typeof(Customer), null, Int32.MaxValue, false, false, null, new MyCustomerResolver());  

Você pode especificar um DataContractResolver em uma chamada para os métodos DataContractSerializer.ReadObject ou DataContractSerializer.WriteObject, conforme mostrado no exemplo a seguir.

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()));  

Ou você pode configurá-lo no DataContractSerializerOperationBehavior como mostrado no exemplo a seguir.

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();  

Você pode especificar declarativamente um resolver de contrato de dados implementando um atributo que pode ser aplicado a um serviço. Para obter mais informações, consulte a amostra KnownAssemblyAttribute. Esta amostra implementa um atributo chamado "KnownAssembly" que adiciona um resolver de contrato de dados personalizado ao comportamento do serviço.

Confira também