>
 Saturday, September 16, 2006
« Service Contract Versioning | Main | Book Updates »

To follow my post on Service Contract Versioning, here's a snip from my book on Data Contract Versioning.

-----

This lab illustrates several versioning scenarios for data contracts. Table 2-5 summarizes possible changes to a data contract and the affect it has on existing clients, if any.

Data Contract Changes

Impact on Existing Clients

Add new non-required members

Client unaffected. Missing values are initialized to defaults.

Add new required members

An exception is thrown for missing values.

Remove non-required members

Data lost at the service. Unable to return the full data set back to the client, for example. No exceptions.

Remove required members

An exception is thrown when client receives responses from the service with missing values.

Modify existing member data types

If types are compatible no exception but may receive unexpected results.

 

Making changes to data contracts once they have been published is a delicate matter. Even if no exception is thrown for the change, the data may lack integrity once deserialized on either end. To avoid this, a few general guidelines should be followed if you are not creating a new data contract version:

            Require data members the business depends on.

            Do not remove or change data types for members, ever.

            If adding new members, make sure they are not required so that version 1 clients don’t break. Remember that missing fields will be initialized to default values — so you must be sure these defaults are acceptable, or perform some low level message inspection to provide meaningful defaults prior to deserialization.

            Support IExtensibleDataObject so that extra data sent by clients, or returned by services, is preserved for round trips.

IExtensibleDataObject

As the lab illustrates, implementing this interface allows you to preserve unknown members sent in the data contract message element (for example if a version 2 client sends a message to a version 1 service). Predicting future versioning issues is difficult, so providing this property bag for unknown members can ease versioning pain.

If at a later time you decide this is not a desirable feature, you can suppress support for unknown members with the dataContractSerializer behavior:

<behavior name="serviceBehavior">

  <dataContractSerializer ignoreExtensionDataObject ="true"/>

</behavior>

If you are wondering about the client side it so happens that SvcUtil generates data contracts that implement IExtensibleDataObject. This ensures that extra data sent to clients by the service will not be lost in a round trip.

On either side the result is that the DataContractSerializer populates the ExtensionDataObject dictionary on deserialization, and uses the same dictionary to serialize additional elements in outgoing messages.

Explicit Versioning

To properly version a data contract you should create a new type and supply it with a new data contract name and/or namespace using the DataContractAttribute.  Since it is a new type, you are free to remove, add, or change any member but remember that if the semantics of the type are significantly different then it should probably be a new type altogether, without relation to the original.

When you change a data contract that is included in a service contract operation, you are also affecting the service contract that exposes the type. In fact, the minute you decide to version a data contract you must also version any service contract that uses it, or supply new contracts for the new type.

In summary, existing clients must always be able to access an endpoint that exposes the original contract. The only way this is possible is if the original contract does not change!

Versioning Flow Diagrams

Figure 2-7 and Figure 2-8 illustrate the decision flow for data contract versioning based on non-strict and strict approaches, respectively.

With non-strict versioning you can add optional members and ignore (yet preserve) superfluous members that may result from future versions of the contract. Ignoring optional members requires you to be aware of the default initialization of members that are missing, if you want to differentiate from version 1 and version 2 clients. Allowing superfluous members to be ignored solves the problem of newer version clients pushing data to an older version of the data contract, but this carries risks if clients send an inordinate amount of extra data. You should still consider IExtensibleDataObject for your own versioning needs, but perhaps monitor the message size for possible denial-of-service attacks.

With strict data contract versioning all changes lead to a new data contract. That means that any service contract that exposes this new data contract must also be versioned per the rules of strict service contract versioning.

 

Click image for full view...

 

 

9/16/2006 12:20 AM WCF  | Comments [4]  |  View reactions  |  Trackback
    ON THIS PAGE
    SEARCH
    CATEGORIES
    ARCHIVES
    BLOGROLL

Designed by NUKEATION STUDIOS