Суррогаты контрактов данныхData Contract Surrogates

Суррогат контракта данных — это расширенная функция, созданная на основе модели контракта данных.The data contract surrogate is an advanced feature built upon the Data Contract model. Эта возможность предназначена для настройки и подстановки типов, когда необходимо изменить способ сериализации типа, десериализации или преобразования типа в метаданные.This feature is designed to be used for type customization and substitution in situations where users want to change how a type is serialized, deserialized or projected into metadata. Например, суррогат может использоваться в сценариях, когда для типа не задан контракт данных, поля и свойства не помечены атрибутом DataMemberAttribute или пользователи хотят динамически создавать вариации схемы.Some scenarios where a surrogate may be used is when a data contract has not been specified for the type, fields and properties are not marked with the DataMemberAttribute attribute or users wish to dynamically create schema variations.

Сериализация и десериализация выполняются с суррогатом контракта данных при использовании DataContractSerializer для преобразования из .NET Framework в подходящий формат, например XML.Serialization and deserialization are accomplished with the data contract surrogate when using DataContractSerializer to convert from .NET Framework to a suitable format, such as XML. Суррогат контракта данных также может использоваться для изменения метаданных, экспортированных для типов, при создании представлений метаданных, например документов схемы XML (XSD).Data contract surrogate can also be used to modify the metadata exported for types, when producing metadata representations such as XML Schema Documents (XSD). Во время импорта из метаданных создается код, суррогат может также использоваться для настройки создаваемого кода.Upon import, code is created from metadata and the surrogate can be used in this case to customize the generated code as well.

Как работает суррогатHow the Surrogate Works

Суррогат сопоставляет один тип ("исходный" тип) с другим типом ("суррогатным" типом).A surrogate works by mapping one type (the "original" type) to another type (the "surrogated" type). В следующем примере показаны исходный тип Inventory и новый суррогатный тип InventorySurrogated.The following example shows the original type Inventory and a new surrogate InventorySurrogated type. Тип Inventory не позволяет сериализацию, а тип InventorySurrogated позволяет:The Inventory type is not serializable but the InventorySurrogated type is:

public class Inventory
{
    public int pencils;
    public int pens;
    public int paper;
}

Так как для этого класса контракт данных не определен, класс преобразуется в суррогатный класс с контрактом данных.Because a data contract has not been defined for this class, convert the class to a surrogate class with a data contract. Суррогатный класс показан в следующем примере:The surrogated class is shown in the following example:

[DataContract(Name = "Inventory")]
public class InventorySurrogated
{
    [DataMember]
    public int numpencils;
    [DataMember]
    public int numpaper;
    [DataMember]
    private int numpens;

    public int pens
    {
        get { return numpens; }
        set { numpens = value; }
    }
}

Реализация IDataContractSurrogateImplementing the IDataContractSurrogate

Для использования суррогата контракта данных необходимо реализовать интерфейс IDataContractSurrogate.To use the data contract surrogate, implement the IDataContractSurrogate interface.

Ниже приведен обзор каждого метода интерфейса IDataContractSurrogate с возможной реализацией.The following is an overview of each method of IDataContractSurrogate with a possible implementation.

GetDataContractTypeGetDataContractType

Метод GetDataContractType сопоставляет один тип с другим.The GetDataContractType method maps one type to another. Этот метод требуется для сериализации, десериализации, импорта и экспорта.This method is required for serialization, deserialization, import, and export.

Первая задача - определить, какие типы будут сопоставляться с другими типами.The first task is defining what types will be mapped to other types. Пример:For example:

public Type GetDataContractType(Type type)
{
    Console.WriteLine("GetDataContractType");
    if (typeof(Inventory).IsAssignableFrom(type))
    {
        return typeof(InventorySurrogated);
    }
    return type;
}
  • При сериализации сопоставление, которое возвращает этот метод, используется затем для преобразования исходного экземпляра в суррогатный экземпляр вызовом метода GetObjectToSerialize.On serialization, the mapping returned by this method is subsequently used to transform the original instance to a surrogated instance by calling the GetObjectToSerialize method.

  • При десериализации сопоставление, которое возвращает этот метод, используется сериализатором для десериализации в экземпляр суррогатного типа.On deserialization, the mapping returned by this method is used by the serializer to deserialize into an instance of the surrogate type. Затем вызывается метод GetDeserializedObject для преобразования суррогатного экземпляра в экземпляр исходного типа.It subsequently calls GetDeserializedObject to transform the surrogated instance into an instance of the original type.

  • При экспорте суррогатный тип, возвращенный этим методом, применяется для получения контракта данных, который будет использоваться для генерирования метаданных.On export, the surrogate type returned by this method is reflected to get the data contract to use for generating metadata.

  • При импорте исходный тип заменяется на суррогатный, который применяется для получения контракта данных, необходимого, например для поддержки возможности ссылок.On import, the initial type is changed to a surrogate type that is reflected to get the data contract to use for purposes like referencing support.

Параметр Type является типом объекта, который подвергается сериализации, десериализации, импорту или экспорту.The Type parameter is the type of the object that is being serialized, deserialized, imported, or exported. Метод GetDataContractType должен возвращать тип, который был на входе, если суррогат не обрабатывает тип.The GetDataContractType method must return the input type if the surrogate does not handle the type. В противном случае возвращается соответствующий суррогатный тип.Otherwise, return the appropriate surrogated type. Если существует несколько суррогатных типов, метод позволяет определить несколько сопоставлений.If several surrogate types exist, numerous mappings can be defined in this method.

Метод GetDataContractType не вызывается для встроенных примитивов контрактов данных, например Int32 или String.The GetDataContractType method is not called for built-in data contract primitives, such as Int32 or String. Для других типов, таких как массивы, типы, определяемые пользователем, и других структур данных, метод вызывается для каждого типа.For other types, such as arrays, user-defined types, and other data structures, this method will be called for each type.

В предыдущем примере метод проверяет, совместим ли параметр type и Inventory.In the previous example, the method checks if the type parameter and Inventory are comparable. Если да, то метод сопоставляет его с InventorySurrogated.If so, the method maps it to InventorySurrogated. Каждый раз при сериализации, десериализации, импорте схемы или экспорте схемы сперва вызывается эта функция для определения соответствия типов.Whenever a serialization, deserialization, import schema, or export schema is called, this function is called first to determine the mapping between types.

Метод GetObjectToSerializeGetObjectToSerialize Method

Метод GetObjectToSerialize преобразует экземпляр исходного типа в экземпляр суррогатного типа.The GetObjectToSerialize method converts the original type instance to the surrogated type instance. Этот метод требуется для сериализации.The method is required for serialization.

На втором этапе необходимо определить, каким образом физические данные из исходного экземпляра будут преобразовываться в данные суррогатного, при помощи реализации метода GetObjectToSerialize.The next step is to define the way the physical data will be mapped from the original instance to the surrogate by implementing the GetObjectToSerialize method. Пример:For example:

public object GetObjectToSerialize(object obj, Type targetType)
{
    Console.WriteLine("GetObjectToSerialize");
    if (obj is Inventory)
    {
        InventorySurrogated isur = new InventorySurrogated();
        isur.numpaper = ((Inventory)obj).paper;
        isur.numpencils = ((Inventory)obj).pencils;
        isur.pens = ((Inventory)obj).pens;
        return isur;
    }
    return obj;
}

Метод GetObjectToSerialize вызывается при сериализации объекта.The GetObjectToSerialize method is called when an object is serialized. Этот метод передает данные из исходного типа в поля суррогатного типа.This method transfers data from the original type to the fields of the surrogated type. Поля могут быть напрямую сопоставлены с суррогатными полями, либо в суррогате можно сохранить результат манипуляций с исходными данными.Fields can be directly mapped to surrogate fields, or manipulations of the original data may be stored in the surrogate. Некоторые варианты использования: прямое сопоставление полей; выполнение операций над данными, которые нужно сохранить в суррогатных полях; сохранение XML исходного типа в суррогатном поле.Some possible uses include: directly mapping the fields, performing operations on the data to be stored in the surrogated fields, or storing the XML of the original type in the surrogated field.

Параметр targetType относится к объявленному типу элемента.The targetType parameter refers to the declared type of the member. Этот параметр является суррогатным типом, возвращенным методом GetDataContractType.This parameter is the surrogated type returned by the GetDataContractType method. Сериализатор не требует, чтобы возвращенный объект можно было назначить этому типу.The serializer does not enforce that the object returned is assignable to this type. objПараметр — это объект для сериализации, который будет преобразован в его суррогат при необходимости.The obj parameter is the object to serialize, and will be converted to its surrogate if necessary. Этот метод возвращает входной объект, если суррогатный не обрабатывает этот объект.This method must return the input object if the surrogated does not handle the object. В противном случае возвращается новый суррогатный объект.Otherwise, the new surrogate object will be returned. Суррогат не вызывается, если объект пустой.The surrogate is not called if the object is null. Метод позволяет определить несколько суррогатных сопоставлений для различных экземпляров.Numerous surrogate mappings for different instances may be defined within this method.

При создании объекта DataContractSerializer можно задать для него сохранение ссылок на объекты.When creating a DataContractSerializer, you can instruct it to preserve object references. (Дополнительные сведения см. в разделе сериализация и десериализация.) Это делается путем задания preserveObjectReferences для параметра в конструкторе значения true .(For more information, see Serialization and Deserialization.) This is done by setting the preserveObjectReferences parameter in its constructor to true. В таком случае суррогат вызывается для объекта только один раз, так как все последующие сериализации просто записывают в поток ссылку.In that case, the surrogate is called only once for an object since all subsequent serializations just write the reference into the stream. Если параметр preserveObjectReferences имеет значение false, суррогат вызывается для каждого вхождения экземпляра.If preserveObjectReferences is set to false, then the surrogate is called every time an instance is encountered.

Если тип экземпляра, подвергающегося сериализации, отличается от объявленного типа, сведения о типе записываются в поток (например xsi:type), чтобы экземпляр затем можно было десериализовать.If the type of the instance serialized differs from the declared type, type information is written into the stream, for example, xsi:type to allow the instance to be deserialized at the other end. Это происходит независимо от того, является объект суррогатным, или нет.This process occurs whether the object is surrogated or not.

В приведенном выше примере данные экземпляра Inventory преобразуются в данные InventorySurrogated.The example above converts the data of the Inventory instance to that of InventorySurrogated. Проверяется тип объекта и выполняются необходимые операции для преобразования в суррогатный тип.It checks the type of the object and performs the necessary manipulations to convert to the surrogated type. В данном случае поля класса Inventory напрямую копируются в поля класса InventorySurrogated.In this case, the fields of the Inventory class are directly copied over to the InventorySurrogated class fields.

Метод GetDeserializedObjectGetDeserializedObject Method

Метод GetDeserializedObject преобразует экземпляр суррогатного типа в экземпляр исходного типа.The GetDeserializedObject method converts the surrogated type instance to the original type instance. Этот метод требуется для десериализации.It is required for deserialization.

Следующая задача - определить, каким образом физические данные из суррогатного экземпляра будут сопоставляться с данными исходного экземпляра.The next task is to define the way the physical data will be mapped from the surrogate instance to the original. Пример:For example:

public object GetDeserializedObject(object obj, Type targetType)
{
    Console.WriteLine("GetDeserializedObject");
    if (obj is InventorySurrogated)
    {
        Inventory invent = new Inventory();
        invent.pens = ((InventorySurrogated)obj).pens;
        invent.pencils = ((InventorySurrogated)obj).numpencils;
        invent.paper = ((InventorySurrogated)obj).numpaper;
        return invent;
    }
    return obj;
}

Этот метод вызывается только во время десериализации объекта.This method is called only during the deserialization of an object. Он предоставляет возможность обратного сопоставления данных для десериализации из суррогатного типа обратно в исходный тип.It provides reverse data mapping for the deserialization from the surrogate type back to its original type. Аналогично методу GetObjectToSerialize, возможен прямой обмен данными полей, выполнение операций над данными или хранение XML-данных.Similar to the GetObjectToSerialize method, some possible uses may be to directly exchange field data, perform operations on the data, and store XML data. При десериализации не всегда получаются данные, идентичные исходным, что связано с операциями при преобразовании данных.When deserializing, you may not always obtain the exact data values from original due to manipulations in the data conversion.

Параметр targetType относится к объявленному типу элемента.The targetType parameter refers to the declared type of the member. Этот параметр является суррогатным типом, возвращенным методом GetDataContractType.This parameter is the surrogated type returned by the GetDataContractType method. objПараметр ссылается на объект, который был десериализован.The obj parameter refers to the object that has been deserialized. Объект может быть преобразован обратно в свой исходный тип, если он был заменен на суррогатный.The object can be converted back to its original type if it is surrogated. Этот метод возвращает входной объект, если суррогатный не обрабатывает этот объект.This method returns the input object if the surrogate does not handle the object. В противном случае после завершения преобразования возвращается десериализованный объект.Otherwise, the deserialized object will be returned once its conversion has been completed. Если есть несколько суррогатных типов, можно задать преобразование данных из суррогатного типа в исходный для каждого из них, указав каждый тип и его преобразование.If several surrogate types exist, you may provide data conversion from surrogate to primary type for each by indicating each type and its conversion.

Когда возвращается объект, внутренние таблицы объектов обновляются, получая объект, возвращенный суррогатом.When returning an object, the internal object tables are updated with the object returned by this surrogate. Все дальнейшие ссылки на экземпляр будут получать суррогатный экземпляр из таблиц объектов.Any subsequent references to an instance will obtain the surrogated instance from the object tables.

В предшествующем примере объекты типа InventorySurrogated преобразуются обратно в исходный тип Inventory.The previous example converts objects of type InventorySurrogated back to the initial type Inventory. В данном случае данные напрямую передаются из полей InventorySurrogated в соответствующие поля Inventory.In this case, data is directly transferred back from InventorySurrogated to its corresponding fields in Inventory. Так как операций с данными не производилось, все поля элементов будут содержать те же данные, что и до сериализации.Because there are no data manipulations, the each of the member fields will contain the same values as before the serialization.

Метод GetCustomDataToExportGetCustomDataToExport Method

При экспорте схемы метод GetCustomDataToExport является необязательным.When exporting a schema, the GetCustomDataToExport method is optional. Он применяется для вставки дополнительных данных или указаний в экспортированную схему.It is used to insert additional data or hints into the exported schema. Дополнительные данные могут быть добавлены на уровне элемента или типа.Additional data can be inserted at the member level or type level. Пример:For example:

public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType)
{
    Console.WriteLine("GetCustomDataToExport(Member)");
    System.Reflection.FieldInfo fieldInfo = (System.Reflection.FieldInfo)memberInfo;
    if (fieldInfo.IsPublic)
    {
        return "public";
    }
    else
    {
        return "private";
    }
}

Этот метод (с двумя перегрузками) позволяет включение дополнительных сведений в метаданные на уровне элемента или типа.This method (with two overloads) enables the inclusion of extra information into the metadata either at the member or type level. Можно добавить указания о том, является ли элемент открытым или закрытым, а также комментарии, которые сохраняются при экспорте и импорте схемы.It is possible to include hints about whether a member is public or private, and comments which would be preserved throughout the export and import of the schema. Если не применять этот метод, такая информация теряется.Such information would be lost without this method. Этот метод не позволяет добавлять или удалять элементы и типы, а дает возможность добавлять дополнительные данные в схемы на любом из этих двух уровней.This method does not cause the insertion or deletion of members or types, but rather adds additional data to the schemas at either of these levels.

Этот метод перегружен и может принимать либо объект Type (параметр clrtype), либо объект MemberInfo (параметр memberInfo).The method is overloaded and can take either a Type (clrtype parameter) or MemberInfo (memberInfo parameter). Второй параметр всегда будет объектом Type (параметр dataContractType).The second parameter is always a Type (dataContractType parameter). Этот метод вызывается для каждого элемента и типа суррогатного типа dataContractType.This method is called for every member and type of the surrogated dataContractType type.

Каждая из перегрузок возвращает либо null, либо объект, который можно сериализовать.Either of these overloads must return either null or a serializable object. Непустой объект сериализуется как заметка в экспортированной схеме.A non-null object will be serialized as annotation into the exported schema. Для перегрузки Type каждый тип, экспортированный в схему, предается этому методу в первом параметре с суррогатным типом в качестве параметра dataContractType.For the Type overload, each type that is exported to schema is sent to this method in the first parameter along with the surrogated type as the dataContractType parameter. Для перегрузки MemberInfo каждый элемент, экспортированный в схему, отправляет свои сведения как параметр memberInfo с суррогатным типом в качестве второго параметра.For the MemberInfo overload, each member that is exported to schema sends its information as the memberInfo parameter with the surrogated type in the second parameter.

Метод GetCustomDataToExport (Type, Type)GetCustomDataToExport Method (Type, Type)

Метод IDataContractSurrogate.GetCustomDataToExport(Type, Type) вызывается во время экспорта схемы для каждого определения типа.The IDataContractSurrogate.GetCustomDataToExport(Type, Type) method is called during schema export for every type definition. Этот метод добавляет информацию в типы схемы при экспорте.The method adds information to the types within the schema when exporting. Каждый определенный тип отправляется этому методу с целью определить, есть ли дополнительные данные, которые необходимо включить в схему.Each type defined is sent to this method to determine whether there is any additional data that needs to be included in the schema.

Метод GetCustomDataToExport (MemberInfo, Type)GetCustomDataToExport Method (MemberInfo, Type)

Метод IDataContractSurrogate.GetCustomDataToExport(MemberInfo, Type) вызывается во время экспорта для каждого элемента в экспортируемых типах.The IDataContractSurrogate.GetCustomDataToExport(MemberInfo, Type) is called during export for every member in the types that are exported. Эта функция дает возможность настроить для элементов любые комментарии, которые будут включены в схему при экспорте.This function enables you to customize any comments for the members that will be included in the schema upon export. Сведения для каждого элемента класса отправляются в этот метод для проверки, не нужно ли включить в схему какие-либо дополнительные данные.The information for every member within the class is sent to this method to check whether any additional data need to be added in the schema.

В приведенном выше примере выполняется поиск по dataContractType для каждого элемента суррогата.The example above searches through the dataContractType for each member of the surrogate. Затем возвращается соответствующий модификатор доступа для каждого поля.It then returns the appropriate access modifier for each field. Без такой настойки значение по умолчанию для любого модификатора доступа - открытый.Without this customization, the default value for access modifiers is public. Поэтому в коде, сгенерированном при помощи экспортированной схемы, все элементы будут определены как открытые, независимо от их реальных ограничений доступа.Therefore, all members would be defined as public in the code generated using the exported schema no matter what their actual access restrictions are. Если бы эта реализация не использовалась, элемент numpens был бы открытым в экспортированной схеме, хотя он определен как закрытый в суррогате.When not using this implementation, the member numpens would be public in the exported schema even though it was defined in the surrogate as private. Благодаря этому методу в экспортированной схеме модификатор доступа может быть сгенерирован как закрытый.Through the use of this method, in the exported schema, the access modifier can be generated as private.

Метод GetReferencedTypeOnImportGetReferencedTypeOnImport Method

Этот метод сопоставляет тип Type суррогата с исходным типом.This method maps the Type of the surrogate to the original type. Этот метод является необязательным для импорта схем.This method is optional for schema importation.

При создании суррогата, импортирующего схему и генерирующего код для нее, следующая задача - перейти от типа суррогатного экземпляра к исходному типу.When creating a surrogate that imports a schema and generates code for it, the next task is to define the type of a surrogate instance to its original type.

Если в сгенерированном коде необходимо сослаться на существующий пользовательский тип, это можно сделать реализацией метода GetReferencedTypeOnImport.If the generated code needs to reference an existing user type, this is done by implementing the GetReferencedTypeOnImport method.

При импорте схемы этот метод вызывается для каждого объявления типа, чтобы сопоставить суррогатный контракт данных с типом.When importing a schema, this method is called for every type declaration to map the surrogated data contract to a type. Строковые параметры typeName и typeNamespace определяют имя и пространство имен суррогатного типа.The string parameters typeName and typeNamespace define the name and namespace of the surrogated type. Возвращаемое значение для метода GetReferencedTypeOnImport используется для определения, нужно ли сгенерировать новый тип.The return value for GetReferencedTypeOnImport is used to determine whether a new type needs to be generated. Этот метод возвращает либо допустимый тип, либо значение NULL.This method must return either a valid type or null. В случае допустимого типа возвращаемый тип используется как тип, на который существует ссылка в сгенерированном коде.For valid types, the type returned will be used as a referenced type in the generated code. Если возвращается значение NULL, ссылки на тип не будет, должен быть создан новый тип.If null is returned, no type will be referenced and a new type must be created. Если есть несколько суррогатов, можно выполнить сопоставление каждого суррогатного типа и его исходного типа.If several surrogates exist, it is possible to perform the mapping for each surrogate type back to its initial type.

Параметр customData является объектом, возвращенным методом GetCustomDataToExport.The customData parameter is the object originally returned from GetCustomDataToExport. Параметр customData используется, когда создатели суррогата хотят поместить дополнительные данные или указания в метаданные, которые используются при импорте для генерирования кода.This customData is used when surrogate authors want to insert extra data/hints into the metadata to use during import to generate code.

Метод ProcessImportedTypeProcessImportedType Method

Метод ProcessImportedType позволяет настроить любой тип, созданный при импорте схемы.The ProcessImportedType method customizes any type created from schema importation. Этот метод является необязательным.This method is optional.

При импорте схемы этот метод позволяет настройку любого импортированного типа и сведений о компиляции.When importing a schema, this method allows for any imported type and compilation information to be customized. Пример:For example:

public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
{
    Console.WriteLine("ProcessImportedType");
    foreach (CodeTypeMember member in typeDeclaration.Members)
    {
        object memberCustomData = member.UserData[typeof(IDataContractSurrogate)];
        if (memberCustomData != null
          && memberCustomData is string
          && ((string)memberCustomData == "private"))
        {
            member.Attributes = ((member.Attributes & ~MemberAttributes.AccessMask) | MemberAttributes.Private);
        }
    }
    return typeDeclaration;
}

Во время импорта этот метод вызывается для каждого генерируемого типа.During import, this method is called for every type generated. Измените объект CodeTypeDeclaration или CodeCompileUnit.Change the specified CodeTypeDeclaration or modify the CodeCompileUnit. Это означает в том числе изменение имени, элементов, атрибутов и многих других свойств объекта CodeTypeDeclaration.This includes changing the name, members, attributes, and many other properties of the CodeTypeDeclaration. Обрабатывая объект CodeCompileUnit, можно изменить директивы, пространства имен, сборки, на которые существуют ссылки, и некоторые другие аспекты.By processing the CodeCompileUnit, it is possible to modify the directives, namespaces, referenced assemblies, and several other aspects.

Параметр CodeTypeDeclaration содержит объявление типа Code DOM.The CodeTypeDeclaration parameter contains the code DOM type declaration. Параметр CodeCompileUnit позволяет изменение обработки кода.The CodeCompileUnit parameter allows for modification for processing the code. Если возвращается результат null, в объявлении типа он уничтожается.Returning null results in the type declaration being discarded. В противном случае, если возвращается объект CodeTypeDeclaration, изменения сохраняются.Conversely, when returning a CodeTypeDeclaration, the modifications are preserved.

Если при экспорте метаданных добавляются пользовательские данные, необходимо, чтобы они были предоставлены пользователю при импорте для их использования.If custom data is inserted during metadata export, it needs to be provided to the user during import so that it can be used. Такие пользовательские данные могут использоваться для указаний о модели программирования или других комментариев.This custom data can be used for programming model hints, or other comments. Каждый экземпляр CodeTypeDeclaration и CodeTypeMember включает в себя пользовательские данные в виде свойства UserData, приведенного к типу IDataContractSurrogate.Each CodeTypeDeclaration and CodeTypeMember instance includes custom data as the UserData property, cast to the IDataContractSurrogate type.

В приведенном выше примере в импортированной схеме производится несколько изменений.The example above performs some changes on the schema imported. Код сохраняет закрытые элементы исходного типа при помощи суррогата.The code preserves private members of the original type by using a surrogate. При импорте схемы модификатор доступа по умолчанию имеет значение public (открытый).The default access modifier when importing a schema is public. Поэтому все элементы суррогатной схемы будут открытыми, если не изменить их, как в этом примере.Therefore, all members of the surrogate schema will be public unless modified, as in this example. При экспорте в метаданные вставляются пользовательские данные, указывающие, какие элементы являются закрытыми.During export, custom data is inserted into the metadata about which members are private. Производится поиск в пользовательских данных и проверка, должен ли модификатор доступа быть закрытым. Затем выполняется изменение соответствующего элемента, он делается закрытым при помощи атрибутов.The example looks up the custom data, checks whether the access modifier is private, and then modifies the appropriate member to be private by setting its attributes. Без такой настройки элемент numpens был бы определен как открытый вместо закрытого.Without this customization, the numpens member would be defined as public instead of private.

Метод GetKnownCustomDataTypesGetKnownCustomDataTypes Method

Этот метод получает определенные типы пользовательских данных из схемы.This method obtains custom data types defined from the schema. Этот метод является необязательным для импорта схем.The method is optional for schema importation.

Этот метод вызывается в начале экспорта или импорта схемы.The method is called at the beginning of schema export and import. Метод возвращает типы пользовательских данных, которые используются в экспортируемой или импортируемой схеме.The method returns the custom data types used in the schema exported or imported. Методу передается объект Collection<T> (параметр customDataTypes), который представляет собой коллекцию типов.The method is passed a Collection<T> (the customDataTypes parameter), which is a collection of types. Метод добавляет дополнительные известные типы в эту коллекцию.The method should add additional known types to this collection. Известные типы пользовательских данных необходимы для сериализации и десериализации пользовательских данных при помощи DataContractSerializer.The known custom data types are needed to enable serialization and deserialization of custom data using the DataContractSerializer. Дополнительные сведения см. в статье о известных типах контрактов данных.For more information, see Data Contract Known Types.

Реализация суррогатаImplementing a Surrogate

Чтобы использовать суррогат контракта данных в WCF, необходимо выполнить несколько особых процедур.To use the data contract surrogate within WCF, you must follow a few special procedures.

Использование суррогата для сериализации и десериализацииTo Use a Surrogate for Serialization and Deserialization

Для выполнения сериализации и десериализации данных с суррогатом используйте DataContractSerializer.Use the DataContractSerializer to perform serialization and deserialization of data with the surrogate. Объект DataContractSerializer создается при помощи DataContractSerializerOperationBehavior.The DataContractSerializer is created by the DataContractSerializerOperationBehavior. Необходимо также задать суррогат.The surrogate must also be specified.

Реализация сериализации и десериализацииTo implement serialization and deserialization
  1. Создайте экземпляр ServiceHost для службы.Create an instance of the ServiceHost for your service. Полные инструкции см. в разделе Базовая программирование WCF.For complete instructions, see Basic WCF Programming.

  2. Для каждого объекта ServiceEndpoint заданного узла службы найдите соответствующий объект OperationDescription.For every ServiceEndpoint of the specified service host, find its OperationDescription.

  3. Выполните поиск экземпляра DataContractSerializerOperationBehavior в поведениях операций.Search through the operation behaviors to determine if an instance of the DataContractSerializerOperationBehavior is found.

  4. Если найден экземпляр DataContractSerializerOperationBehavior, задайте в его свойстве DataContractSurrogate новый экземпляр суррогата.If a DataContractSerializerOperationBehavior is found, set its DataContractSurrogate property to a new instance of the surrogate. Если экземпляр DataContractSerializerOperationBehavior не найден, создайте новый экземпляр и задайте для элемента DataContractSurrogate нового расширения новый экземпляр суррогата.If no DataContractSerializerOperationBehavior is found, then create a new instance and set the DataContractSurrogate member of the new behavior to a new instance of the surrogate.

  5. Наконец, добавьте это новое поведение в текущие поведения операций, как показано в примере:Finally, add this new behavior to the current operation behaviors, as shown in the following example:

    using (ServiceHost serviceHost = new ServiceHost(typeof(InventoryCheck)))
        foreach (ServiceEndpoint ep in serviceHost.Description.Endpoints)
        {
            foreach (OperationDescription op in ep.Contract.Operations)
            {
                DataContractSerializerOperationBehavior dataContractBehavior =
                    op.Behaviors.Find<DataContractSerializerOperationBehavior>()
                    as DataContractSerializerOperationBehavior;
                if (dataContractBehavior != null)
                {
                    dataContractBehavior.DataContractSurrogate = new InventorySurrogated();
                }
                else
                {
                    dataContractBehavior = new DataContractSerializerOperationBehavior(op);
                    dataContractBehavior.DataContractSurrogate = new InventorySurrogated();
                    op.Behaviors.Add(dataContractBehavior);
                }
            }
        }
    

Использование суррогата для импорта метаданныхTo Use a Surrogate for Metadata Import

При импорте метаданных, таких как WSDL и XSD, для генерации клиентского кода суррогат необходимо добавить в компонент, отвечающий за генерирование кода из схемы XSD, XsdDataContractImporter.When importing metadata like WSDL and XSD to generate client-side code, the surrogate needs to be added to the component responsible for generating code from XSD schema, XsdDataContractImporter. Для этого напрямую измените объект WsdlImporter, который используется для импорта метаданных.To do this, directly modify the WsdlImporter used to import metadata.

Реализация суррогата для импорта метаданныхTo implement a surrogate for metadata importation
  1. Импортируйте метаданные при помощи класса WsdlImporter.Import the metadata using the WsdlImporter class.

  2. Чтобы проверить, определен ли объект TryGetValue, воспользуйтесь методом XsdDataContractImporter.Use the TryGetValue method to check whether an XsdDataContractImporter has been defined.

  3. Если метод TryGetValue возвращает значение false, создайте новый объект XsdDataContractImporter и задайте в его свойстве Options новый экземпляр класса ImportOptions.If the TryGetValue method returns false, create a new XsdDataContractImporter and set its Options property to a new instance of the ImportOptions class. В противном случае используйте импортер, возвращенный параметром out метода TryGetValue.Otherwise, use the importer returned by the out parameter of the TryGetValue method.

  4. Если для импортера XsdDataContractImporter не определено свойство ImportOptions, задайте для свойства новый экземпляр класса ImportOptions.If the XsdDataContractImporter has no ImportOptions defined, then set the property to be a new instance of the ImportOptions class.

  5. Задайте для свойства DataContractSurrogate объекта ImportOptions импортера XsdDataContractImporter в качестве значения новый экземпляр суррогата.Set the DataContractSurrogate property of the ImportOptions of the XsdDataContractImporter to a new instance of the surrogate.

  6. Добавьте объект XsdDataContractImporter в коллекцию, возвращенную свойством State объекта WsdlImporter (унаследован от класса MetadataExporter).Add the XsdDataContractImporter to the collection returned by the State property of the WsdlImporter (inherited from the MetadataExporter class.)

  7. Используйте метод ImportAllContracts объекта WsdlImporter для импорта всех контрактов данных схемы.Use the ImportAllContracts method of the WsdlImporter to import all of the data contracts within the schema. Во время последнего действия генерируется код из схем, загруженных при вызове суррогата.During the last step, code is generated from the schemas loaded by calling into the surrogate.

    MetadataExchangeClient mexClient = new MetadataExchangeClient(metadataAddress);
    mexClient.ResolveMetadataReferences = true;
    MetadataSet metaDocs = mexClient.GetMetadata();
    WsdlImporter importer = new WsdlImporter(metaDocs);
    object dataContractImporter;
    XsdDataContractImporter xsdInventoryImporter;
    if (!importer.State.TryGetValue(typeof(XsdDataContractImporter),
        out dataContractImporter))
        xsdInventoryImporter = new XsdDataContractImporter();
    
    xsdInventoryImporter = (XsdDataContractImporter)dataContractImporter;
    xsdInventoryImporter.Options ??= new ImportOptions();
    xsdInventoryImporter.Options.DataContractSurrogate = new InventorySurrogated();
    importer.State.Add(typeof(XsdDataContractImporter), xsdInventoryImporter);
    
    Collection<ContractDescription> contracts = importer.ImportAllContracts();
    

Использование суррогата для экспорта метаданныхTo Use a surrogate for Metadata Export

По умолчанию при экспорте метаданных из WCF для службы необходимо создать схему WSDL и XSD.By default, when exporting metadata from WCF for a service, both WSDL and XSD schema needs to be generated. Суррогат необходимо добавить в компонент, отвечающий за генерацию XSD-схемы для типов контрактов данных, XsdDataContractExporter.The surrogate needs to be added to the component responsible for generating XSD schema for data contract types, XsdDataContractExporter. Для этого используйте либо поведение, реализующее IWsdlExportExtension для изменения WsdlExporter, либо напрямую измените объект WsdlExporter, который используется для экспорта метаданных.To do this, either use a behavior that implements IWsdlExportExtension to modify the WsdlExporter, or directly modify the WsdlExporter used to export metadata.

Использование суррогата для экспорта метаданныхTo use a surrogate for metadata export
  1. Создайте новый объект WsdlExporter или используйте параметр wsdlExporter, переданный методу ExportContract.Create a new WsdlExporter or use the wsdlExporter parameter passed to the ExportContract method.

  2. Чтобы проверить, определен ли объект TryGetValue, воспользуйтесь функцией XsdDataContractExporter.Use the TryGetValue function to check whether an XsdDataContractExporter has been defined.

  3. Если метод TryGetValue возвращает значение false, создайте новый объект XsdDataContractExporter со сгенерированными схемами XML из объекта WsdlExporter, и добавьте его в коллекцию, возвращенную свойством State объекта WsdlExporter.If TryGetValue returns false, create a new XsdDataContractExporter with the generated XML schemas from the WsdlExporter, and add it to the collection returned by the State property of the WsdlExporter. В противном случае используйте экспортер, возвращенный параметром out метода TryGetValue.Otherwise, use the exporter returned by the out parameter of the TryGetValue method.

  4. Если для экспортера XsdDataContractExporter не определен объект ExportOptions, задайте для свойства Options в качестве значения новый экземпляр класса ExportOptions.If the XsdDataContractExporter has no ExportOptions defined, then set the Options property to a new instance of the ExportOptions class.

  5. Задайте для свойства DataContractSurrogate объекта ExportOptions импортера XsdDataContractExporter в качестве значения новый экземпляр суррогата.Set the DataContractSurrogate property of the ExportOptions of the XsdDataContractExporter to a new instance of the surrogate. Дальнейшие шаги по экспорту метаданных остаются без изменений.Subsequent steps for exporting metadata do not require any changes.

    WsdlExporter exporter = new WsdlExporter();
    //or
    //public void ExportContract(WsdlExporter exporter,
    // WsdlContractConversionContext context) { ... }
    object dataContractExporter;
    XsdDataContractExporter xsdInventoryExporter;
    if (!exporter.State.TryGetValue(typeof(XsdDataContractExporter),
        out dataContractExporter))
    {
        xsdInventoryExporter = new XsdDataContractExporter(exporter.GeneratedXmlSchemas);
    }
    else
    {
        xsdInventoryExporter = (XsdDataContractExporter)dataContractExporter;
    }
    
    exporter.State.Add(typeof(XsdDataContractExporter), xsdInventoryExporter);
    
    if (xsdInventoryExporter.Options == null)
        xsdInventoryExporter.Options = new ExportOptions();
    xsdInventoryExporter.Options.DataContractSurrogate = new InventorySurrogated();
    

См. такжеSee also