Поделиться через


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

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

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

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

См. также