Procedimientos recomendados: Creación de versiones de contratos de datos

En este tema se hace una lista de los procedimientos recomendados para crear contratos de datos que pueden evolucionar con facilidad con el tiempo. Para obtener más información acerca de los contratos de datos, consulte los temas en Utilización de contratos de datos.

Aviso en validación del esquema

Para tratar las versiones de contrato de datos, es importante tener en cuenta que el esquema de contrato de datos exportado por Windows Communication Foundation (WCF) no tiene compatibilidad de versión, a excepción del hecho de que los elementos se marcan como opcionales de forma predeterminada.

Esto significa que no se puede implementar ni siquiera el escenario de versión más común, como agregar un nuevo miembro de datos, de un modo uniforme con respecto a un esquema determinado. Las versiones más recientes de un contrato de datos (con un nuevo miembro de datos, por ejemplo) no se validan mediante el esquema anterior.

Sin embargo, hay muchos escenarios en los cuales no se requiere compatibilidad de esquema estricta. Muchas plataformas de servicios web, incluido WCF y servicios web XML creadas utilizando ASP.NET, no realizan validación de esquema de forma predeterminada y, por lo tanto, toleran elementos adicionales que no describe el esquema. Cuando se trabaja con estas plataformas, muchos escenarios de versión son más fáciles de implementar.

De este modo, hay dos conjuntos de instrucciones de versión de contrato de datos: uno establecido para escenarios donde la validez estricta del esquema es importante, y otro conjunto para los escenarios cuando no lo es.

Controlar versiones cuando se requiere la validación del esquema

Si se requiere la validez estricta del esquema en todas las direcciones (nuevo a anterior y anterior a nuevo), los contratos de datos se deberían considerar inmutables. Si es necesario controlar las versiones, se debería crear un nuevo contrato de datos, con un espacio de nombres o nombre diferente, y se deberían controlar las versiones del contrato de servicio utilizando el tipo de datos según corresponda.

Imagine, por ejemplo, que un contrato de servicio de procesamiento de pedidos de compra denominado PoProcessing con una operación PostPurchaseOrder toma un parámetro que se ajusta a un contrato de datos PurchaseOrder. Si el contrato PurchaseOrder tiene que cambiar, debe crear un nuevo contrato de datos, es decir, PurchaseOrder2, que incluya los cambios. A continuación, debe administrar la versión en el nivel del contrato de servicios. Por ejemplo, creando una operación PostPurchaseOrder2 que toma el parámetro PurchaseOrder2 o creando un contrato de servicios PoProcessing2 donde la operación PostPurchaseOrder toma un contrato de datos PurchaseOrder2.

Tenga en cuenta que los cambios en los contratos de datos a los cuales hacen referencia otros contratos de datos también se extienden a la capa de modelo de servicio. Por ejemplo, en el escenario anterior, no es necesario cambiar el contrato de datos PurchaseOrder. Sin embargo, contiene un miembro de datos de un contrato de datos Customer que, a su vez, contiene un miembro de datos del contrato de datos Address, que debe cambiarse. En ese caso, necesitaría crear un contrato de datos Address2 con los cambios necesarios, un contrato de datos Customer2 que contenga el miembro de datos Address2 y un contrato de datos PurchaseOrder2 que contenga un miembro de datos Customer2. Como en el caso anterior, se tendrían que controlar las versiones del contrato de servicios también.

Aunque en estos nombres de ejemplos se cambian (anexando un "2"), la recomendación es cambiar los espacios de nombres en lugar de los nombres anexando los nuevos espacios de nombres con un número de versión o una fecha. Por ejemplo, el contrato de datos http://schemas.contoso.com/2005/05/21/PurchaseOrder cambiaría al contrato de datos http://schemas.contoso.com/2005/10/14/PurchaseOrder.

Para obtener más información, consulte Procedimientos recomendados: Control de versiones del servicio.

En algunos casos, debe garantizar la compatibilidad estricta del esquema para los mensajes enviados por su aplicación, pero no puede confiar en que los mensajes entrantes sean estrictamente compatibles con el esquema. En este caso, existe el peligro de que un mensaje entrante pueda contener datos extraños. WCF almacena y devuelve los valores extraños y, por lo tanto, se envían mensajes no válidos para el esquema. Para evitar este problema, la característica de ida y vuelta debería estar desactivada. Existen dos formas de lograr esto.

Para obtener más información acerca de los viajes de ida y vuelta (round trip), consulte Contratos de datos compatibles con el reenvío.

Controlar versiones cuando se requiere la validación del esquema

En raras ocasiones se requiere compatibilidad estricta de esquema. Muchas plataformas toleran elementos adicionales no descritos por un esquema. Siempre que se tolere, se puede utilizar el conjunto completo de características descrito en Versiones de contratos de datos y Contratos de datos compatibles con el reenvío. A continuación se indican algunas instrucciones recomendadas:

Algunas de las instrucciones se deben seguir con exactitud para enviar nuevas versiones de un tipo cuando se espera uno anterior o enviar uno anterior cuando se espera el nuevo. No se requieren otras instrucciones estrictamente, pero se enumeran aquí porque el futuro de versión del esquema puede afectar a.

  1. No intente controlar las versiones de los contratos de datos por herencia de tipo. Para crear versiones posteriores, cambie el contrato de datos en un tipo existente o cree un nuevo tipo no relacionado.
  2. Se permite el uso de herencia junto con los contratos de datos, siempre que la herencia no se utilice como un mecanismo de control de versiones y se sigan ciertas reglas. Si un tipo deriva de un cierto tipo base, no le haga derivar de un tipo base diferente en una versión futura (a menos que tenga el mismo contrato de datos). Existe una excepción: puede insertar un tipo en la jerarquía entre un tipo de contrato de datos y su tipo base, pero sólo si no contiene miembros de datos con los mismos nombres en calidad de otros miembros en ninguna versión posible de los otros tipos de la jerarquía. En general, el uso de miembros de datos con los mismos nombres en niveles diferentes de la misma jerarquía de herencia puede producir problemas de versión serios y se debería evitar.
  3. Iniciándose con la primera versión de un contrato de datos, siempre implemente IExtensibleDataObject para habilitar alrededor tropezando. Para obtener más información, consulte Contratos de datos compatibles con el reenvío. Si ha soltado una o más versiones de un tipo sin implementar esta interfaz, impleméntela en la versión siguiente del tipo.
  4. En versiones posteriores, no cambie el nombre de contrato de datos o espacio de nombres. Si cambia el nombre o espacio de nombres del tipo subyacente al contrato de datos, asegúrese de conservar el nombre de contrato de datos y espacio de nombres utilizando los mecanismos adecuados, como la propiedad Name de DataContractAttribute. Para obtener más información acerca de la nomenclatura, consulte Nombres de contratos de datos.
  5. En versiones posteriores, no cambie los nombres de ningún miembro de datos. Si cambia el nombre del campo, propiedad o evento subyacente al miembro de datos, utilice la propiedad Name de DataMemberAttribute para conservar el nombre del miembro de datos existente.
  6. En versiones posteriores, no cambie el tipo de ningún campo, propiedad o evento subyacente al miembro de datos de tal manera que el contrato de datos resultante para ese miembro de datos cambie. Tenga presente que los tipos de interfaz son equivalentes a Object con el fin de determinar el contrato de datos esperado.
  7. En versiones posteriores, no cambie el orden de los miembros de datos existentes mediante el ajuste de la propiedad Order del atributo DataMemberAttribute.
  8. En versiones posteriores, se pueden agregar nuevos miembros de datos. Deberían seguir siempre estas reglas:
    1. La propiedad IsRequired se debería dejar siempre en su valor predeterminado de false.
    2. Si el miembro no acepta el valor predeterminado null o cero, se debería proporcionar un método de devolución de llamada mediante OnDeserializingAttribute para proporcionar un valor predeterminado razonable en caso de que el miembro no se encuentre en la secuencia de entrada. Para obtener más información acerca de la devolución de llamada, consulte Devoluciones de llamadas en la serialización tolerante a versiones.
    3. La propiedad Order en DataMemberAttribute se debería utilizar para asegurarse de que todos los miembros de datos recientemente agregados aparecen después de los miembros de datos existentes. Para hacerlo, se recomienda lo siguiente: Ninguno de los miembros de datos en la primera versión del contrato de datos debería tener su propiedad Order establecida. Todos los miembros de datos agregados en la versión 2 del contrato de datos deberían tener su propiedad Order establecida en 2. Todos los miembros de datos agregados en la versión 3 del contrato de datos deberían tener su conjunto Order establecido a 3, etc. Se permite tener más de un miembro de datos establecido en el mismo número de Order.
  9. No quite los miembros de datos en versiones posteriores, ni siquiera si la propiedad IsRequired se dejó en su propiedad predeterminada de false en versiones anteriores.
  10. No cambie la propiedad IsRequired en ningún miembro de datos existente entre versiones.
  11. Para los miembros de datos necesarios (donde IsRequired es true), no cambie la propiedad EmitDefaultValue entre versiones.
  12. No intente crear jerarquías de versión bifurcadas. Es decir, siempre debería haber una ruta de acceso en al menos una dirección desde una versión a otra versión utilizando sólo los cambios permitidos por estas instrucciones.
    Por ejemplo, si la versión 1 de un contrato de datos Persona contiene sólo el Nombre de miembro de datos, no debería crear la versión 2a de la adición del contrato añadiendo sólo el miembro Edad y la versión 2 agregando sólo el miembro Dirección. Al ir de 2a a 2b, implicaría quitar Edad y agregar Dirección; al ir en la otra dirección, supondría quitar Dirección y agregar Edad. Estas instrucciones no permiten quitar los miembros.
  13. Generalmente no debería crear nuevos subtipos de tipos de contrato de datos existente en una nueva versión de su aplicación. Por la misma razón, no debería crear nuevos contratos de datos que se usen en lugar de miembros de datos declarados como Object o como tipos de interfaz. Se permite crear estas clases nuevas sólo cuando conoce que puede agregar los nuevos tipos a la lista de tipos conocida de todas las instancias de su aplicación anterior. Por ejemplo, en la versión 1 de su aplicación, puede tener el tipo de contrato de datos LibraryItem con Book y subtipos de contrato de datos Newspaper. LibraryItem entonces tendría una lista de tipos que contendría Book y Newspaper. Suponga que ahora agrega un tipo Magazine en la versión 2 qué es un subtipo de LibraryItem. Si envía una instancia Magazine de la versión 2 a la versión 1, el contrato de datos Magazine no se encuentra en la lista de tipos conocidos y se inicia una excepción.
  14. No debería agregar o quitar los miembros de enumeración entre las versiones. Tampoco debería cambiar el nombre de los miembros de la enumeración, a menos que use la propiedad Name en el atributo EnumMemberAttribute para mantener iguales sus nombres en el modelo del contrato de datos.
  15. Las colecciones son intercambiables en el modelo del contrato de datos tal y como se describe en Tipos de colección en contratos de datos. Esto permite un gran grado de flexibilidad. Sin embargo, asegúrese de que no cambia inadvertidamente un tipo de colección de una manera no intercambiable entre versiones. Por ejemplo, no cambie de una colección no personalizada (es decir, sin el atributo CollectionDataContractAttribute ) a una personalizada o una colección personalizada a una no personalizada. Tampoco cambie las propiedades de CollectionDataContractAttribute entre las versiones. El único cambio permitido es agregar una propiedad Name o Namespace si el nombre del tipo de colección subyacente o el espacio de nombres ha cambiado y necesita cambiar su nombre de contrato de datos y espacio de nombres al mismo nombre que en una versión anterior.

Se pueden omitir algunas de las instrucciones enumeradas aquí sin ningún riesgo cuando se aplican circunstancias especiales. Asegúrese de que entiende totalmente la serialización, deserialización y mecanismos de esquema implicados en caso de no cumplir las instrucciones.

Consulte también

Referencia

Name
DataContractAttribute
Order
IsRequired
IExtensibleDataObject
ServiceBehaviorAttribute
ExtensionData
ExtensionDataObject
OnDeserializingAttribute

Conceptos

Utilización de contratos de datos
Versiones de contratos de datos
Nombres de contratos de datos
Contratos de datos compatibles con el reenvío
Devoluciones de llamadas en la serialización tolerante a versiones