Not too many of our customers have complained in the past that there is no way to express null values for value types in .NET. Well, this is just the concept of value types, isn’t it? But it is an essential piece that is missing when working with XML schema-based types that allow null values. The .NET Framework 2.0 provides a solution for this. Take a look at the following XML fragment that denotes a valid order:
Again, imagine our fits-it-all Web service to deliver information about order status. Based on the query criteria, the service may return the status of an order that has not been shipped yet. In this case the Web service returns a ShipDate element with the XSD instance attribute nil set to true. The current version of the .NET Framework, or more correctly the proxy class generation and serialization process, already supports this. When you have an XSD or WSDL with a nillable or optional element, the proxy class contains an additional flag. In our example above this would be ShipDateSpecified. This flag indicates whether the value for this element is set or not. People need to be able to differentiate whether the element or attribute was missing from the XML document and whether the attribute was present but had the default value. The support for truly nullable types in the .NET Framework would make things a lot easier. Take a look at the following Web service code:
[WebServiceBinding( ConformanceClaims = WsiClaims.BP10, EmitConformanceClaims = true)] [WebService(Namespace = "http://www.thinktecture.com/demos/Nullable")] public class NullableService { [WebMethod] [return:XmlElement("MyData", IsNullable=true)] public SqlInt32 GetData(bool ReturnNull) { SqlInt32 mydata; mydata=(ReturnNull ? SqlInt32.Null : 1234);
return mydata; } }
This WebMethod returns a type of SqlInt32. After a quick look into the documentation we can see that it implements INullable. This is the essential interface that has to be supported when implementing your own nullable types. If we point wsdl.exe to the service’s interface and message contract it will generate the following code snippet:
As can be seen very clear, the proxy uses a generic type System.Nullable<System.Int32> to indicate that the actual instance of the return type may be null. SqlTypes is also an example of a type that implements IXmlSerializable. The SQL types like SqlInt32 can then emit their own schemas and serialize/deserialize themselves. If we specify a special switch on proxy generation, the wsdl.exe tool can map nillable elements of primitive types (e.g. Int32, Date) to SqlTypes. So if you want to consume the above service, you might run wsdl.exe with the /sqltypes switch to get a proxy class that contains this code:
[return: System.Xml.Serialization.XmlElementAttribute("TheData", IsNullable=true)] public SqlInt32 GetData(bool ReturnNull) { object[] results = this.Invoke("GetData", new object[] {ReturnNull}); return ((System.Data.SqlTypes.SqlInt32)(results[0])); }
Now we have a SqlInt32 data type present as return type of the method. This can come in handy when you are developing database-oriented and a bit more tightly coupled systems than it originally was intended by the Web services credo.