Använda en datakontraktslösare

Med en datakontraktslösare kan du konfigurera kända typer dynamiskt. Kända typer krävs vid serialisering eller deserialisering av en typ som inte förväntas av ett datakontrakt. Mer information om kända typer finns i Kända typer av datakontrakt. Kända typer anges normalt statiskt. Det innebär att du måste känna till alla möjliga typer som en operation kan ta emot under implementeringen av operationen. Det finns scenarier där detta inte är sant och det är viktigt att kunna ange kända typer dynamiskt.

Skapa en dataavtalslösare

När du skapar en datakontraktslösare innebär det att implementera två metoder, TryResolveType och ResolveName. Dessa två metoder implementerar återanrop som används under serialisering respektive deserialisering. Metoden TryResolveType anropas under serialiseringen och tar en datakontraktstyp och mappar den till ett xsi:type namn och namnområde. Metoden ResolveName anropas under deserialiseringen och tar ett xsi:type namn och namnområde och löser den till en datakontraktstyp. Båda dessa metoder har en knownTypeResolver parameter som kan användas för att använda den kända standardtyplösaren i implementeringen.

I följande exempel visas hur du implementerar en DataContractResolver för att mappa till och från en datakontraktstyp som heter Customer, vilken är härledd från en datakontraktstyp 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);
        }
    }
}

När du har definierat en DataContractResolver kan du använda den genom att skicka den DataContractSerializer till konstruktorn enligt följande exempel.

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

Du kan ange ett DataContractResolver i ett anrop till DataContractSerializer.ReadObject metoderna eller DataContractSerializer.WriteObject som du ser i följande exempel.

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

Eller så kan du ställa in det på DataContractSerializerOperationBehavior, som visas i följande exempel.

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

Du kan deklarativt ange en lösning för datakontrakt genom att implementera ett attribut som kan tillämpas på en tjänst. Mer information finns i exemplet KnownAssemblyAttribute . Det här exemplet implementerar ett attribut med namnet "KnownAssembly" som lägger till en anpassad datakontraktslösare i tjänstens beteende.

Se även