Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Best Practices for Handling Change in Your WCF Applications : Page 2

Change is inevitable, but with a little planning and a few key principles, you can minimize the impact that changes have on your WCF service consumers.


advertisement

Data Contract Changes

The Person DataContract defines two attributes: FirstName and LastName. If a client were to reference this service and you were to subsequently change LastName to SurName, the client would not actually break but the LastName attribute on the client's proxy class would appear to be empty. This is because when the client deserializes the message into the Person class, it will no longer find any element named LastName to place into the attribute.

This simple change won't cause the client to experience an error; it will cause something even worse: an unexpected behavior. The error would be easy to track down, but tracking down the change in behavior is much more difficult.

This simple example demonstrates why it is critical to consider any service changes and their downstream effects. Unless you are personally aware of every client application utilizing your web service, changes can be disastrous. As a developer, you should do everything in your power to shield your clients from changes.



Initially, you can first apply a few best practices that will help isolate clients from internal changes. An updated version of the data contract might look like this:

[DataContract(Namespace="http://types.mycompany.com/2009/05/25", Name="PersonContract")] public class Person : IExtensibleDataObject { private string _firstName = string.Empty; private string _lastName = string.Empty; private ExtensionDataObject _extensionData; [DataMember(Name="FirstName")] public string FirstName { get { return _firstName; } set { _firstName = value; } } [DataMember(Name="LastName")] public string LastName { get { return _lastName; } set { _lastName = value; } } public ExtensionDataObject ExtensionData { get { return _extensionData; } set { _extensionData = value; } } }

The addition of the Namespace, Name, and Order parameters (you will see Order in an upcoming code example) on the DataContract and DataMember attributes controls the DataContractSerializer's behavior. This addition generates the client proxy when a reference to the service is added. The Name parameters cause the serializer to use the indicated value as opposed to the name of the actual public member or property. This approach allows the internal implementation to change without affecting the client. For example, consider the following change:

[DataMember(Name="LastName")] public string SurName { get { return _lastName; } set { _lastName = value; } }

The change of the property name from "LastName" to "SurName" will not break existing clients because the Name parameter that clients use is still "LastName." Only the internal implementation has changed.

The second noticeable change is the addition of the IExtensibleDataObject interface. Implementing this interface allows a client to retain data that is not explicitly defined in the contract. This may not seem immediately useful, but in cases where the client is expected to perform processing on the sample Person object and return it, the client can retain new data items. For example, updating the PersonContract with the following new member will not force existing clients to be updated:

[DataMember(Name = "MiddleName", Order = 3)] public string SurName { get { return _middleName; } set { _middleName = value; } }

This member will, in fact, allow existing clients to retain a value placed in "MiddleName" by the service over the round trip. Implementing the IExtensibleDataObject is a useful way to future-proof your data contracts. As a best practice, you should use it on all data contracts.

Keep in mind that clients actually have the option of validating messages against an external schema. (For a thorough discussion of adding message schema validation to a WCF application, read this article.) As a result, you have two scenarios to consider when dealing with changes to data contracts: those with schema validation and those without schema validation.

When clients add schema validation, adding, changing, or subtracting any items in a data contract will cause that validation to fail. So, in cases where strict schema validation is being used, contracts simply should not be changed. Instead, you should create an entirely new contract and use a different namespace in the contract to indicate the new version.

For example, from an implementation perspective, you would need two separate service endpoints to make both these versions available:

Original Version:
[DataContract(Namespace="http://schemas.mycompany.com/2009/05/25")] New Version:
[DataContract(Namespace="http://schemas.mycompany.com/2009/06/18")]

Fortunately, strict schema validation is not the default behavior. This means you can actually add and remove data members without breaking the client. However, because of the unexpected behavior previously discussed, removing a data member is not a good idea. On the other hand, adding a data member is easy to do, and consumers will ignore extra members that they are not aware of.

A key practice is to use the Order parameter of the DataMember attribute (as previously discussed). Using this parameter tells the serializer in what order each member should appear in the XML. An unintended change in the order can cause the XML to no longer conform to the original schema. Simply using the Order parameter from the beginning can avoid this problem. If you do not use the Order parameter, the serializer follows this order:

  1. Members from base types
  2. Members without an Order parameter (alphabetically)
  3. Members with an order parameter (in order by value)

The final scenario to consider with data contracts is changing the type of a data member. In this case, the best approach is to create a new version of the data contract along with a new service contract, implementation, and endpoint.



Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap