Why does C# Web Service code look weird?
Today I read a posting at VMware community forum about the weird code required by C# Web Service. If the following line is missing, then the vSphere API call to get properties doesn’t work:
VimApi.VimService.PropertySpec.allSpecified = True
Lost VMs or Containers? Too Many Consoles? Too Slow GUI? Time to learn how to "Google" and manage your VMware and clouds in a fast and secure HTML5 App.
So, where does the allSpecified come from? and why is it needed?
Having created a new Web Service engine for VI Java API 2.0, I know why the weird code is needed. Let me explain in details here.
For any primitive data type, it does not have a value representing the case that no value is specified. When serialized to an XML SOAP message, it can be a problem. If the value is for a required property, no problem. But if it’s for an optional property, then a big problem. The serialization engine has no way to decide whether to include the value by evaluating the value itself.
Let’s take a close look at the above example, there is a property called all in the PropertySpec. Since the property all is a boolean type, it has to be either true or false. There is no way to represent a value for not specified. The property all happens to be an optional field.
There are two solutions to this problem. One is to have an additional field for every optional field of primitive data type in the data objects, just indicating whether the value should be serialized to the SOAP XML request or not. This is exactly what is used in Microsoft Web Service tool. The naming pattern for the additonal property is like *Specified, all boolean type. These additional properties will be used by WS engine but never serialized to SOAP message. By default, they are false. So if you want a primitive property X to be serialized, you have to explicitly set up the xSpecified = True; otherwise it’s ignored. In the above example, the property all is not, although should, serialized if the line of code is missing.
The other solution is to use wrapping object types for the optional fields of primitive types. For example, for the primitive boolean type, use Boolean type. Then you can use null as the “not specified”. The down side of this is that a new object may be created. The good thing is that it’s much straightforward and no mistake can be made. Java 5.0 and later supports auto-boxing, meaning you can assign a boolean to a Boolean type and the compiler handles the conversion for you. So you don’t even notice that you actually assign a boolean to a Boolean in Java.
With these two approaches, I prefer the second one just because it’s so easy for a developer to forget the *Specified and get a problem sometimes with no clue on what’s going on. For API design, ease of use is way more important than anything else. In the VI Java API 2.0 Web Services engine, I chose the second apprach and the users have no chance to make a mistake as in C#.
The problem is found with vSphere API in C#, but goes beyond that. Any Web Services stub created by Microsoft has this problem. You got to watch out and pay extra attention while coding Web Services in C#.