Simon Fell > Its just code > Nullable and XxxSpecified
Friday, July 23, 2004
Yasser responds to my ealier post on Nullable and XxxSpecified in .NET 2.0.
He's correct in that xsi:nil='true' and a element not sent at all are 2 different things are you need to be able to control both, but this doesn't jive too well with the current implementation in the 2.0 beta. Here's an example.
A sample WSDL doc defines a complexType that has nilable='true' and minOccurs='0' for a string element and a boolean element.
<xsd:complexType name="address">
<xsd:sequence>
<xsd:element name="City" type="xsd:string" nillable='true' minOccurs='0'/>
<xsd:element name="State" type="xsd:string" nillable='true' minOccurs='0'/>
<xsd:element name="IsVerified" type="xsd:boolean" nillable='true' minOccurs='0'/>
</xsd:sequence>
</xsd:complexType>
I'll run this through wsdl.exe, lets see what we get, the generated struct for address has
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://samples.pocketsoap.com/dn2/")]
public class address {
private string cityField;
private string stateField;
private System.Nullable<bool> isVerifiedField;
private bool isVerifiedFieldSpecified;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
public string City {
get {
return this.cityField;
}
set {
this.cityField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
public string State {
get {
return this.stateField;
}
set {
this.stateField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
public System.Nullable<bool> IsVerified {
get {
return this.isVerifiedField;
}
set {
this.isVerifiedField = value;
}
}
/// <remarks/>
[System.Xml.Serialization.XmlIgnoreAttribute()]
public bool IsVerifiedSpecified {
get {
return this.isVerifiedFieldSpecified;
}
set {
this.isVerifiedFieldSpecified = value;
}
}
}
First thing to note is that only the boolean got an additional Specified flag, what about the strings ?. Lets set some different values on the instance and see what it sends over the wire, first the test code, straightforward enough.
class dn2
{
public static void Main(string [] args)
{
dn2PortType svc = new dn2PortType();
svc.Url = "http://coldcut:8081/service.asmx";
Console.WriteLine("no values specified");
address a = new address();
svc.sendAddress(a);
Console.WriteLine("a string value set");
a = new address();
a.City = "San Francisco";
svc.sendAddress(a);
Console.WriteLine("a boolean value set");
a = new address();
a.IsVerified = true;
svc.sendAddress(a);
Console.WriteLine("a boolean value & Specified set");
a = new address();
a.IsVerified = true;
a.IsVerifiedSpecified = true;
svc.sendAddress(a);
Console.WriteLine("a boolean specified set, no value");
a = new address();
a.IsVerifiedSpecified = true;
svc.sendAddress(a);
}
}
And now the generated requests (I'll leave all the envelope/body goo off, and just show how the address was serialized)
<Address><City xsi:nil="true" /><State xsi:nil="true" /></Address>
<Address><City>San Francisco</City><State xsi:nil="true" /></Address>
<Address><City xsi:nil="true" /><State xsi:nil="true" /></Address>
<Address><City xsi:nil="true" /><State xsi:nil="true" /><IsVerified>true</IsVerified></Address>
<Address><City xsi:nil="true" /><State xsi:nil="true" /><IsVerified xsi:nil="true" /></Address>
Someone on the ASMX team needs to take a step back and have a fresh look at this, for the Specified flags to be useful there really need to be 2 things,
- They're needed on all elements that have a minOccurs='0', why do I get it on boolean elements, and not string elements ?
- Look carefully at the 3rd example, I explicitly set a value for the boolean, but it still didn't get serialized, this is totally lame behavior and my major complaint. There's a property setter right there, if I've set a value for the IsVerified property then I want to send it!, have the IsVerified property setter also set the IsVerifiedSpecified flag as well.
- Not shown above, but there's a bug with System.Nullable and xsd:date, looks like the DataType attribute and System.Nullable don't play nicely together.