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

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

Создание арбитра контрактов данных

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

См. также