Использование разрешителя контракта данных

Разрешатель контракта данных позволяет динамически настраивать известные типы. Известные типы требуются при сериализации или десериализации типа, не ожидаемого контрактом данных. Дополнительные сведения об известных типах см. в известных типов контракта данных. Известные типы обычно задаются статически. Это означает, что при реализации операции необходимо знать все возможные типы операции. Существуют сценарии, в которых это не так, и важно иметь возможность динамически указывать известные типы.

Создание разрешителя данных контракта

Создание сопоставителя контракта данных требует реализации двух методов TryResolveType и ResolveName. Эти два метода реализуют обратные вызовы, используемые во время сериализации и десериализации соответственно. Метод 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", который добавляет в поведение службы настраиваемый сопоставитель контракта данных.

См. также