Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En el ejemplo DataContract se muestra cómo se pueden personalizar procesos como la serialización, la deserialización, la exportación de esquemas y la importación de esquema mediante una clase suplente de contrato de datos. En este ejemplo se muestra cómo usar un suplente en un escenario de cliente y servidor en el que los datos se serializan y transmiten entre un cliente y un servicio de Windows Communication Foundation (WCF).
Nota:
El procedimiento de instalación y las instrucciones de compilación de este ejemplo se encuentran al final de este tema.
En el ejemplo se usa el siguiente contrato de servicio:
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
[AllowNonSerializableTypes]
public interface IPersonnelDataService
{
[OperationContract]
void AddEmployee(Employee employee);
[OperationContract]
Employee GetEmployee(string name);
}
La AddEmployee operación permite a los usuarios agregar datos sobre los nuevos empleados y la operación admite la GetEmployee búsqueda de empleados basados en el nombre.
Estas operaciones usan el siguiente tipo de datos:
[DataContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
class Employee
{
[DataMember]
public DateTime dateHired;
[DataMember]
public Decimal salary;
[DataMember]
public Person person;
}
En el tipo Employee, la clase Person (que se muestra en el código de ejemplo siguiente) no se puede serializar mediante DataContractSerializer porque no es una clase de contrato de datos válida.
public class Person
{
public string firstName;
public string lastName;
public int age;
public Person() { }
}
Puede aplicar el DataContractAttribute atributo a la Person clase , pero esto no siempre es posible. Por ejemplo, la clase Person se puede definir en un ensamblado independiente sobre el cual no tiene ningún control.
Dada esta restricción, una manera de serializar la Person clase es sustituirla por otra clase marcada con DataContractAttribute y copiar los datos necesarios en la nueva clase. El objetivo es hacer que la Person clase aparezca como DataContract en .DataContractSerializer Tenga en cuenta que se trata de una manera de serializar clases de contrato que no son de datos.
El ejemplo reemplaza lógicamente la Person clase por otra clase denominada PersonSurrogated.
[DataContract(Name="Person", Namespace = "http://Microsoft.ServiceModel.Samples")]
public class PersonSurrogated
{
[DataMember]
public string FirstName;
[DataMember]
public string LastName;
[DataMember]
public int Age;
}
El suplente del contrato de datos se utiliza para lograr este reemplazo. Un suplente del contrato de datos es una clase que implementa IDataContractSurrogate. En este ejemplo, la AllowNonSerializableTypesSurrogate clase implementa esta interfaz.
En la implementación de la interfaz, la primera tarea consiste en establecer una asignación de tipos de Person a PersonSurrogated. Esto se usa tanto en el momento de la serialización como en el tiempo de exportación del esquema. Esta asignación se logra implementando el método GetDataContractType(Type).
public Type GetDataContractType(Type type)
{
if (typeof(Person).IsAssignableFrom(type))
{
return typeof(PersonSurrogated);
}
return type;
}
El GetObjectToSerialize(Object, Type) método asigna una Person instancia a una PersonSurrogated instancia durante la serialización, como se muestra en el código de ejemplo siguiente.
public object GetObjectToSerialize(object obj, Type targetType)
{
if (obj is Person)
{
Person person = (Person)obj;
PersonSurrogated personSurrogated = new PersonSurrogated();
personSurrogated.FirstName = person.firstName;
personSurrogated.LastName = person.lastName;
personSurrogated.Age = person.age;
return personSurrogated;
}
return obj;
}
El método GetDeserializedObject(Object, Type) proporciona la asignación inversa para la deserialización, como se muestra en el código muestra siguiente.
public object GetDeserializedObject(object obj,
Type targetType)
{
if (obj is PersonSurrogated)
{
PersonSurrogated personSurrogated = (PersonSurrogated)obj;
Person person = new Person();
person.firstName = personSurrogated.FirstName;
person.lastName = personSurrogated.LastName;
person.age = personSurrogated.Age;
return person;
}
return obj;
}
Para asignar el PersonSurrogated contrato de datos a la clase existente Person durante la importación de esquema, el ejemplo implementa el GetReferencedTypeOnImport(String, String, Object) método , como se muestra en el código de ejemplo siguiente.
public Type GetReferencedTypeOnImport(string typeName,
string typeNamespace, object customData)
{
if (
typeNamespace.Equals("http://schemas.datacontract.org/2004/07/DCSurrogateSample")
)
{
if (typeName.Equals("PersonSurrogated"))
{
return typeof(Person);
}
}
return null;
}
El código de ejemplo siguiente completa la implementación de la IDataContractSurrogate interfaz.
public System.CodeDom.CodeTypeDeclaration ProcessImportedType(
System.CodeDom.CodeTypeDeclaration typeDeclaration,
System.CodeDom.CodeCompileUnit compileUnit)
{
return typeDeclaration;
}
public object GetCustomDataToExport(Type clrType,
Type dataContractType)
{
return null;
}
public object GetCustomDataToExport(
System.Reflection.MemberInfo memberInfo, Type dataContractType)
{
return null;
}
public void GetKnownCustomDataTypes(
KnownTypeCollection customDataTypes)
{
// It does not matter what we do here.
throw new NotImplementedException();
}
En este ejemplo, el suplente está habilitado en ServiceModel por un atributo denominado AllowNonSerializableTypesAttribute. Los desarrolladores necesitarían aplicar este atributo en su contrato de servicio, tal como se muestra en el IPersonnelDataService contrato de servicio anterior. Este atributo implementa IContractBehavior y establece el suplente en operaciones en suApplyClientBehavior y métodos ApplyDispatchBehavior.
El atributo no es necesario en este caso; se usa con fines de demostración en este ejemplo. Los usuarios también pueden habilitar un suplente agregando manualmente un elemento similarIContractBehaviorIEndpointBehavior, o IOperationBehavior mediante código o mediante la configuración.
La IContractBehavior implementación busca operaciones que usan DataContract comprobando si tienen un DataContractSerializerOperationBehavior registrado. Si lo tienen, establece la propiedad DataContractSurrogate en ese comportamiento. En el código de ejemplo siguiente se muestra cómo se hace esto. Establecer el suplente en este comportamiento de la operación lo habilita para la serialización y deserialización.
public void ApplyClientBehavior(ContractDescription description, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime proxy)
{
foreach (OperationDescription opDesc in description.Operations)
{
ApplyDataContractSurrogate(opDesc);
}
}
public void ApplyDispatchBehavior(ContractDescription description, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatch)
{
foreach (OperationDescription opDesc in description.Operations)
{
ApplyDataContractSurrogate(opDesc);
}
}
private static void ApplyDataContractSurrogate(OperationDescription description)
{
DataContractSerializerOperationBehavior dcsOperationBehavior = description.Behaviors.Find<DataContractSerializerOperationBehavior>();
if (dcsOperationBehavior != null)
{
if (dcsOperationBehavior.DataContractSurrogate == null)
dcsOperationBehavior.DataContractSurrogate = new AllowNonSerializableTypesSurrogate();
}
}
Es necesario realizar pasos adicionales para conectar el suplente para su uso durante la generación de metadatos. Un mecanismo para hacerlo es proporcionar un IWsdlExportExtension que es lo que muestra este ejemplo. Otra manera es modificar el WsdlExporter directamente.
El AllowNonSerializableTypesAttribute atributo implementa IWsdlExportExtension y IContractBehavior. La extensión puede ser bien un IContractBehavior o un IEndpointBehavior en este caso. Su implementación de método IWsdlExportExtension.ExportContract habilita el suplente agregándolo a XsdDataContractExporter usado durante la generación del esquema para DataContract. El siguiente fragmento de código muestra cómo hacerlo.
public void ExportContract(WsdlExporter exporter, WsdlContractConversionContext context)
{
if (exporter == null)
throw new ArgumentNullException("exporter");
object dataContractExporter;
XsdDataContractExporter xsdDCExporter;
if (!exporter.State.TryGetValue(typeof(XsdDataContractExporter), out dataContractExporter))
{
xsdDCExporter = new XsdDataContractExporter(exporter.GeneratedXmlSchemas);
exporter.State.Add(typeof(XsdDataContractExporter), xsdDCExporter);
}
else
{
xsdDCExporter = (XsdDataContractExporter)dataContractExporter;
}
if (xsdDCExporter.Options == null)
xsdDCExporter.Options = new ExportOptions();
if (xsdDCExporter.Options.DataContractSurrogate == null)
xsdDCExporter.Options.DataContractSurrogate = new AllowNonSerializableTypesSurrogate();
}
Al ejecutar el ejemplo, el cliente llama a AddEmployee seguido de una llamada GetEmployee para comprobar si la primera llamada se realizó correctamente. El resultado de la solicitud de operación GetEmployee se muestra en la ventana de la consola del cliente. La operación GetEmployee debe encontrar al empleado e imprimir "encontrado".
Nota:
En este ejemplo se muestra cómo conectar un suplente para serializar, deserializar y generar metadatos. No muestra cómo conectar un suplente para la generación de código a partir de metadatos. Para ver un ejemplo de cómo se puede usar un subrogado para integrarse en la generación de código del cliente, consulte el ejemplo de publicación de WSDL personalizado.
Para configurar, compilar y ejecutar el ejemplo
Asegúrese de que ha realizado el procedimiento de instalación única para los ejemplos de Windows Communication Foundation.
Para compilar la edición de C# de la solución, siga las instrucciones de Creación de ejemplos de Windows Communication Foundation.
Para ejecutar el ejemplo en una configuración de una máquina única o entre máquinas, siga las instrucciones de Ejecución de los ejemplos de Windows Communication Foundation.