“Interfaces are immutable…” Yes, we’ve heard that for years... The reality, however, is that contracts, both -- service and data, do change as more requirements are discovered, etc. Moreover, it’s not reasonable to expect that all clients of your V1 service will migrate to V2 service at the same time; so, you need to be able to release a new version without breaking old clients.
The rule of thumb is simple: if it’s a new data member on a data type (i.e. data contract) and it’s not a required element or it’s a new method (operation) on a service type and it’s not a callback interface, then you can add it to same class; otherwise, the versioning best practices recommend that you create a new data type in a new versioned namespace (versioned namespace allows you to keep the class name the same).
Here are some “good practices” I follow:
namespace YourCompany.Services.V1
{
[ServiceContract(Namespace="urn:yourcompany-com:v1")]
public interface ISomeService
}
[DataContract(Namespace="urn:yourcompany-com:v1")]
public class SomeData : System.Runtime.Serialization.IExtensibleDataObject
private int _dataX; // this data element was part of the version 1 release
private int _dataY; // this data element was part of the version 1 release
private int? _dataZ; // this data element was added after version 1 release
[DataMember(Order=1)] public int DataX
get { return _dataX; }
set { _dataX = value; }
[DataMember(Order=1)] public int? DataY
get { return _dataY; }
set { _dataY = value; }
// Note that order = 2 as DataZ was added after version 1 (dataX and dataY only) was already released
[DataMember(Order=2, IsRequired = false)] public int DataZ
get { return _dataZ; }
set { _dataZ = value; }
[OnDeserialized]
internal void OnDeserialized(StreamingContext ctx)
if (DataZ.HasValue == false)
DataZ = 0;
#region IExtensibleDataObject Members
private System.Runtime.Serialization.ExtensionDataObject _extData;
public virtual System.Runtime.Serialization.ExtensionDataObject ExtensionData
get { return _extData; }
set { _extData = value; }
#endregion
[ServiceContract(Namespace = "urn:YourCompany-com:v1"), DataContractFormat]
[OperationContract]
string SomeMethod(YourDataClass data);
private int _dataX;
[DataMember]
public int DataX
instead of
public int DataX;
Note: you could choose to use XmlSerializer rather than DataContractSerializer. If that’s your choice, then:
private int _dataY;
[XmlElement(Order = 1)]
[XmlElement(Order = 2)]
public int DataY
[XmlAnyElement(Order = 999999)]
public XmlElement[] ExtensionData;
at the end of your data class definitions