Versioning Web Service Parameters
Dare
makes a few comments about one of my
previous posts so I thought - in true blogsphere fashion - I'd follow-up in
a new post. First I'll mention a few more things about versioning web services,
then I'll get to Dare's comments.
Versioning web services can be very challenging depending on the results
you're trying to achieve. The primary decisions revolve around compatibility.
First scenario, the easy way out: no compatibility. If you choose this route, it
is highly recommended you implement a breaking change so your intentions are
clear. So, for the next version of your service, you change the namespace,
create a new endpoint address, and (re)deploy the clients for that service. When
I said the easy way out, I was referring to versioning ... obviously not
maintenance and deployments.
As you can imagine, there are a number of forces that can mandate a service
implement a breaking change. The most common of these is driven directly from
the business. The recommendation I make about using a single parameter for Web
Service operations is strictly for the scenarios when we're applying a
non-breaking change. We should always strive for compatible changes when we want
to avoid the maintenance and deployment headaches evidenced above. I think most
of this was understood in my previous posts, but I wanted to state it explicitly
just to be clear.
I think it's also important to make a distinction between different kinds of
Web Services, even if they're broad and sweeping. There is a considerable
difference between a service-oriented Web Service and one that is not
service-oriented. Perhaps my choice of GetTemp(
TempRequest ) was a poor one. Service-oriented operations are very
course-grained because they represent a business process. Because of this, the
service interface is not likely to change (unless the organization is going to
stop offering the service). However, the data pieces that service will require
could very possibly evolve over time. Therefore, it's important to be able to
version the service interface and the parameters of the operations
independently. If you agree at this point, then we need a way to identify what
version of the operation's inputs are being used. The only way to accomplish
this with multiple parameters is for one of the parameters, which has nothing to
do with the business logic of the operation, to contain version information.
With a single parameter, we can maintain a straightforward experience for the
client developer. Consider this message schema:
<s:schema ... targetNamespace="urn:service">
<s:element name="param" type="tns:UberParam" />
<s:complexType name="UberParam">
<s:sequence>
<s:element name="param1" type="s:string"
minOccurs="0" />
<s:element name="param2" type="s:string"
minOccurs="0" />
</s:sequence>
<s:attribute name="version" type="s:string"
use="required" fixed="1.1" />
</s:complexType>
</s:schema>
Just for completeness, the C# version of this parameter will look like
this.
using System.Xml.Serialization;
[XmlType( Namespace="urn:service" )]
public class UberParam
{
public string param1;
public string param2;
[XmlAttribute()]
[System.ComponentModel.DefaultValue( "1.1" )]
public string version = "1.1";
}
By providing a fixed value for the version of the data type, the service
developer has more metadata to work with and the client developer can focus on
only the job at hand.
UberParam uber = new UberParam();
uber.param1 = "value";
uber.param2 = "value";
MyService.Operation( uber );
Depending on the requirements, a Web Service acting more in the role of a
traditional API might not need this level flexibility. In these cases, I still
recommend a single parameter, but without the need of additional metadata, the
recommendation is less founded.
From Dare ...
Also the developer has to know how to manage interdependencies between
properties of the TemperatureRequest that are set if there are any that are
mutually exclusive, know which properties are required and whether to initialize
primitive values in the object to defaults without any help from the
API.
These issues are valid whether we have one parameter or multiple. The
developer is still required to know something about the API and its
requirements.
The other reason I like the former [multiple parameters] is that it
carries the impression that the XML Web Service end point is unchanging while
the latter [single parameter] does not.
As a client developer, I would find more comfort by feeling a
single-parameter service is constructed in a flexible enough way to withstand
the pressures of evolution.
Comments
- Anonymous
December 02, 2004
Great thougths, my friend. Obviously, I am all for the one parameter approach.
The new WSCF WSDL Wizard will exclusively support this model. Period.
Maybe you also like IBM's recent article on versioning:
http://www-106.ibm.com/developerworks/webservices/library/ws-backward.html
...although I am not too sure about some of the ways they are propagating (like restrictions and optional elements)... - Anonymous
December 02, 2004
Newbie Question:
I know that I'm going to need your expertise soon so this discussion is a good one.
I had thought that when you changed the type of the parameters in a web service then that would be a breaking change for the clients as well as the number of parameters (for example changing from one class to a newer class).
Your article (and Dave's) imply that is not the case. Just to clarify this for me could you supply an example like this one but for version 2.0. ie Which bits can you change without affecting older clients? The class name? It's members?
One of the comments to Dave's post questioned whether ASMX could be overloaded, could you clarify that point too as that is surely another useful technique?
Many thanks for a very interesting series of articles.
Best regards
Steve - Anonymous
December 03, 2004
I also am curious as how the above example can be versioned without breaking the client. The only way I see it not breaking is if you were passing the uberParam as a string or maybe XmlDocument, something generic. Otherwise, as soon as you add another parameter to that uberParam class, you've broken the compatibility, no? - Anonymous
December 03, 2004
It turns out that your example will never work in .NET.
As per the bug I reported (see http://weblogs.asp.net/cazzu/archive/2004/09/30/236378.aspx), if you turn on message-level validation on your webservice (against the schema you have), you will never get a single valid message from a .NET client, as the version attribute will never get serialized, courtesy of the DefaultValueAttribute.
So, you have to remove the required use on the attribute, which kind of defeats one interesting purpose of the attribute :( - Anonymous
May 11, 2005
RePost @ http://www.yeyan.cn/Programming/VersioningWebServiceParameters.aspx