Introduction
The article illustrates the several aspects of WCF Data Contract and Service Contract versioning and the practices adopted for providing backwards
compatibility to contracts. Once the service is developed and rolled over to production, any changes in contracts should be backwards compatible
so that existing clients are not affected when changes are deployed. We will explore the effects of changes in Data Contract and Service
contracts and try to adopt a versioning strategy depending on the scenario. In the first part of this article, we will explore the WCF framework’s behavior
in different cases of versioning of operations in Service Contracts.
Backwards Compatibility Across Contracts
Modification in a WCF service can happen in Data Contracts or in the operations of Service Contracts. In both cases,
by default, WCF is version tolerant. The framework tries its best to serve existing clients with backwards compatibility. Let’s explore the different cases
through an example. In order to explore WCF’s backwards compatibility behavior, we will develop a simple WCF service project. The WCF service has a single method GetData()
.
Implementing a WCF Service
In order to explore WCF’s backwards compatibility behavior, we will develop a simple WCF service project. The WCF service has a
single method GetData()
which has a parameter of “integer” type and returns “string”.
The service implementation is as follows:
Once you are done with the development of the WCF service, Right click -> View in Browser on the file MyService.svc in order to check the WSDL generated by the WCF service.
Develop a console application in order to test the service.
Right click on References->Add Service Reference. Click on Discover or type the service URL in the Address box. Once you click on OK, the
stub code will be generated. Now call the service in the console application using the following code:
Run the console application. The following output should be generated:
Modification of Service Contracts
Now let’s check the behavior of the client in the case of modification of Service Contracts:
Case 1: Adding new parameters to the operation signature
Modify the service method GetData()
. Add a new “interger” parameter to the method. Also, let’s change the service implementation.
Here is the modified Service Contract:
Modified Service implementation: We have added the newly passed parameter with the existing one.
Build the service.
Now run the existing consumer client console application without updating the service reference. We want to call the service using the old stub code and
method signature. You should get the following output:
We can see the existing client of the service remains unaffected on adding new parameters to the service method. Actually, new parameters are initialized
to default values in the service. In our case, since we have introduced a new “integer” type parameter, its default value is “0”. So the value “0” is used as the value
of the new “integer” type parameter at the service end, while the service is called by the old method signature.
Case 2: Removing parameters from an operation signature
Modify the service method GetData()
. Remove both parameters. Also, let’s change the service implementation.
Modified Service Contract:
Modified Service implementation: We have removed both parameters from the service.
Build the service.
Now run the existing consumer client console application without updating the service reference. We want to call the service using the old stub code and
method signature. You should get the following output:
We can see the existing client of the service remains unaffected on removing parameters to the service method. Actually, superfluous parameters passed
by clients are ignored at the service end and this results in data lost at the service.
Case 3: Modifying parameter types of operations
Modify the service method GetData()
. In order to modify the parameter type against the existing client-side stub method signature, let’s add a new
“string” parameter to the method. Also, let’s change the service implementation.
Modified Service Contract:
Modified Service implementation: We have removed both parameters from the service.
Build the service.
Now run the existing consumer client console application without updating the service reference. We want to call the service using the old stub code and
method signature. You should get the following output:
The existing client application runs but it fails to display any value passed by the caller. Actually, in this case, the result is unexpected. An exception
is supposed to be thrown if the incoming type from the client cannot be converted to the parameter data type.
Case 4: Modifying return value types
Modify the service method GetData()
in order to return a “integer” type. Also, change the service implementation.
Modified Service Contract:
Modified Service implementation: We have removed both parameters from the service.
Build the service.
Now run the existing consumer client console application without updating the service reference. We want to call the service using the old stub code and
method signature. You should get the following output:
The existing client application runs and displays the value passed by the caller. Again, in this case, the result is unexpected. An exception is supposed to be
thrown if the return value from the service cannot be converted to the expected data type in the client version of the operation signature. Our existing client
code calls the service method with the value 4. At the service end, an “integer” value 4 is returned. Now, the expected return type at the client end is “string”.
So “integer” 4 has been converted to “string” 4.
Case 5: Adding new operations
Add a new service method GetNewData()
and implement the same at the service end.
New Service method:
Service implementation:
Build the service.
Now run the existing consumer client console application without updating the service reference. We want to call the service using the old stub code and
method signature. You should get the following output:
So the existing client remains unaffected and would not invoke operations which are totally unknown.
Case 6: Removing existing operations
Remove the existing service method GetData()
. Now the service has the only method GetNewData()
.
Commenting the existing Service method:
Commenting the existing implementation:
Build the service.
Now run the existing consumer client console application without updating the service reference. As far as the old stub code at client side is concerned, the GetData()
method
is being called. The following error should occur:
In this case, messages sent by the client to the service are considered to be using an unknown action header. As a result, an exception is thrown.
I have tried to discuss some possible cases of versioning of operations in the Service Contracts. In the next part of the article, I will
explore WCF framework’s behavior in different cases of versioning of Data Contracts.