Two types of Changes:
- Backwards-Compatible Changes (or
Non-Breaking Changes) -> Changes to services that would not require changes
to existing clients.
- Non-Backwards-Compatible Changes (or Breaking Changes) -> Changes to services that would require changes to existing clients.
Versioning Decision Tree

Image courtesy:
http://blogs.msdn.com/b/craigmcmurtry/archive/2006/07/23/676104.aspx
It depicts all the logically possible ways in which we might have to modify a
service, how to implement each change, and what the consequences will be.
The diamonds represent alternative ways in which a service might have to change.
The rectangles and the circle represent procedures for implementing changes. The
procedures represented by the rectangles yield backwards-compatible changes,
whereas the procedure represented by the circle results in a
non-backwards-compatible change.
Now let us trace the routes through the decision tree to understand the
implications of each alternative.
1. Adding a New Operation
This change can be accomplished using a procedure called service contract
inheritance, and the result will be a backwards-compatible change.
E.g.,
Currently, I am having this Service Contract
[ServiceContract]
public interface IEcho
{
[OperationContract]
string Echo(string input);
}
public class Service : IEcho
{
public string Echo(string input)
{
return input;
}
}
Now to add new operation we need to define a new service contract (IExtendedEcho),
with the new operations to be added to the service, which derives from the
original service contract (IEcho):
[ServiceContract]
public interface IExtendedEcho: IEcho
{
[OperationContract]
string[] ExtendedEcho(string[] inputs);
}
The next step is to have the service type
implement the new contract in addition to the original one:
public
class Service : IEcho, IExtendedEcho
{
public string Echo(string input)
{
return input;
}
public string[] ExtendedEcho(string[] input)
{
return input;
}
}
The final step is to modify the configuration of the service endpoint so that
where it referred to the original contract
<endpoint
address="Echo"
binding="basicHttpBinding"
contract="IEcho"
/>
It now refers to the derived contract with the additional methods:
<endpoint
address="Echo"
binding="basicHttpBinding"
contract="IExtendedEcho"
/>
Now new clients that are aware of the additional operations of the derived
contract can make use of those operations. Yet existing clients, which might
know about only the original service contract, could still have the operations
of that original contract executed at the same endpoint. Thus, service contract
inheritance has the happy consequence of a backwards-compatible change.
2. Changing an Operation
The second decision posed by the versioning decision tree is whether or not an
existing
operation of a service has to be modified. If so, the next decision to make is
whether or not the change that is required is a change to the data contracts of
one or more parameters.
Changing the Data Contract of a Parameter
1. Adding\Removing nonrequired data members
[DataContract (Namespace=http://WCFVersioning/2011/09)]
public class StockPrice
{
[DataMember(IsRequired=true)]
public double CurrentPrice;
[DataMember(IsRequired=true)]
public DateTime CurrentTime;
[DataMember(IsRequired=true)]
public string Ticker;
[DataMember]
public string Currency;
}
[DataContract
(Namespace=http://WCFVersioning/2011/09)]
public class StockPrice
{
[DataMember(IsRequired=true)]
public double CurrentPrice;
[DataMember(IsRequired=true)]
public DateTime CurrentTime;
[DataMember(IsRequired=true)]
public string Ticker;
[DataMember]
public int DailyVolume;
}
The addition and removal of optional data members is a backwards-compatible
change.
For existing clients to properly pass around data after new members are added,
the original data contract must support extensibility. That is, the original
contract must support serialization of unknown future data.
A Data Contract that Implements IExtensibleDataObject
[DataContract (Namespace=http://WCFVersioning/2011/09)]
public class StockPrice : IExtensibleDataObject
{
[DataMember(IsRequired=true)]
public double CurrentPrice;
[DataMember(IsRequired=true)]
public DateTime CurrentTime;
[DataMember(IsRequired=true)]
public string Ticker;
[DataMember]
public string Currency;
private ExtensionDataObject unknownData = null;
public ExtensionDataObject ExtensionData
{
get { return this.extensionData; }
set { this.extensionData = value; }
}
}
Other Changes to Data Contracts
-
Change the name or namespace of a data contract
-
Rename an existing data member that was previously required.
-
Add a new data member with a name that has been used previously.
-
Change the data type of an existing data member.
-
Add new members with IsRequired=true on DataMemberAttribute.
-
Remove existing members with IsRequired=true on DataMemberAttribute.
2. Adding required data members
[DataContract (Namespace=http://WCFVersioning/2011/09)]
public sealed class ExServiceDef : IExtensibleDataObject
{
[DataMember(Order = 1)]
public string UploadUrl { get; set; }
[DataMember(Order = 2)]
public string Version { get; set; }
[DataMember(IsRequired=true, Order = 3)]
public string NewRequiredField { get; set; }
#region IExtensibleDataObject Members
public ExtensionDataObject ExtensionData { get; set; }
#endregion
}
Client Request
<ServicesForUsers
xmlns="http://
WCFVersioning/2011/09">
<securitytoken>123</securitytoken>
<username>ZodiacTest</username>
</ServicesForUsers>
Service Response
<ServicesForUsersResponse
xmlns="
http://
WCFVersioning/2011/09">
<ServicesForUsersResult
xmlns:d4p1="http://WCFVersioning/2011/09/DataContracts"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<d4p1:UploadUrl>\\nimittal\MRDF\JobFiles\</d4p1:UploadUrl>
<d4p1:Version>1.0.0.0</d4p1:Version>
<d4p1:NewRequiredField
i:nil="true"></d4p1:NewRequiredField>
</ServicesForUsersResult>
</ServicesForUsersResponse>
</s:Body>
The addition of required data members is a backwards-compatible change.
3. Removing required data members
The removal of required data members is a non-backwards-compatible change.
If we have removed the required data members and not updated client WSDL we will
get error message something like this:
Error Message:
The formatter threw an exception while trying to deserialize the message: There
was an error while trying to deserialize parameter http://WCFVersioning/2011/09:GetCustomerResult.
The InnerException message was 'Error in line 1 position 4874. 'EndElement' 'GetCustomerResult'
from namespace 'http://WCFVersioning/2011/09 is not expected. Expecting element
'NewRequiredField'.'. Please see InnerException for more details
3. Other Changes to Operations
Changes to existing operations:
-
Changing the name of the operation
-
Adding/Deleting a parameter
-
Deleting an operation
These all changes can be dealt with by defining a new service contract
incorporating the modified operation. Revised versions of service contracts must
be disambiguated
from earlier versions by defining them in new version-specific namespaces. Also,
after a new version of a service contract has been defined, it should be exposed
at a new service endpoint. Again, exposing a new service endpoint is a
backwards-compatible change.
4. Changing a Binding
If the change to be made to a service requires changing the binding of one of
its endpoints, the versioning decision tree indicates that the modified binding
should be
exposed at a new service endpoint. Exposing a new service endpoint is a
backwards-compatible change.
5. Deciding to Retire an Endpoint
If we want to retire an existing endpoint that means we are introducing new
endpoint for all existing client. This is a non-backwards-compatible change.
There are two ways of easing the consequences of this change to a service:

Join the conversation! Your thoughts help the community grow.