0

I have a question regarding WCF and deserialisation of XML.

Lets say i have an XSD that specifies a number of attributes as minoccurs='0'.

<xs:element name=TestData>
  <xs:complexType>
    <xs:sequence>
      <xs:element minOccurs=0 name="stoppageHours>
        <xs:simpleType>
          <xs:restriction base="xs:int">
          </xs:restriction>
        </xs:simpleType>
      </xs:element>
      <xs:element minOccurs=0 name="stoppageDate>
        <xs:simpleType>
          <xs:restriction base="xs:dateTime">
          </xs:restriction>
        </xs:simpleType>
      </xs:element>
    <xs:sequence>
  <xs:complexType>
</xs:element>

If i dont have a value for one for the attributes i can omit the element tags in the XML i.e.

<TestData>
  <StoppageHours>26</StoppageHours>
  ...omitted stoppageDate...
</TestData>

But, given that i have generated classes from the XSD to .NET c#, when i post the XML to my web service it complains that deserialisation has failed as it was expecting element ?

How can you force the deserialistion process to ignore the missing XML element and set the class memeber in question to a NULL value? I have tried setting the class members to system nullable types but to get this to work i have to pass the XML element as xsi:nillable? What i really want to be able to do is simply omit the XML tag.

Thanks.

Milesh
  • 101
  • 1
  • 2
  • 6
  • Those aren't attributes - you're defining XML **elements** to have `minOccurs=0` – marc_s Aug 06 '12 at 14:47
  • Similar question: http://stackoverflow.com/questions/8709424/do-xml-parsers-tell-the-difference-between-xsinil-true-and-omitted-elements – JTMon Aug 06 '12 at 15:02

1 Answers1

0

The attribute that allows this functionatlity is called EmitDefaultValue. Your data contract on the service side will probably look something like this:

[DataContract]
public class TestData
{
    [DataMember(EmitDefaultValue = false)]
    public int StoppageHours { get; set; }

    [DataMember(EmitDefaultValue = false)]
    public DateTime StoppageDate { get; set; }
}

When EmitDefaultValue is equal to false, it tells the data contract serializer in WCF to remove the elements from the input if their value is equal to the default value. For value types the serializer will on the server side set the value to it's default value if it's not present. So in this scenario if you pass

<TestData></TestData> 

when it is received by WCF your object will have these values server side:

<TestData>
    <StoppageHours>0</StoppageHours>
    <StoppageDate>1/1/0001 12:00:00 AM</StoppageDate>
</TestData>

Edit: The other thing you may need to do based on your feedback comment is set the IsRequired attribute on the DataMember as well. When I tested this attribute should default to false but you can try and be explicit in the contract definition. The updated contract would now look like this:

[DataContract]
public class TestData
{
    [DataMember(IsRequired = false, EmitDefaultValue = false)]
    public int StoppageHours { get; set; }

    [DataMember(IsRequired = false, EmitDefaultValue = false)]
    public DateTime StoppageDate { get; set; }
}

When the value is set to true and the nodes are missing I get a serialization exception. When IsRequired is set to false I can send an empty request:

<TestData></TestData>

and there is no serialization exception. If this doesn't work then you may need need to clear your temporary asp.net files and restart the service. I had that issue when testing this out. Hope this helps.

Phil Patterson
  • 1,242
  • 15
  • 25
  • Thnaks phil, i did look at this option but couldn't seem to get it working properly. I found including EmitDefaultValue=false had the desired effect for serialisation but not on deserialisation. I still received an error indicating that an element was missing. – Milesh Aug 07 '12 at 08:22
  • In the end i have set the element values an nillable in the xsd and generated the classes from my xsd using xsd.exe. The resulting class attributes are defined as nullable types. The XML is for a null is then passed in to the WCF service as to indicate a null. I need nulls rather than defaults to be passed into the service. If anyone has any ideas on how this can be done without the nillable attribute i'd love to hear. Thanks. – Milesh Aug 07 '12 at 08:26
  • I've updated my answer with a second potential gotcha with WCF serialization. – Phil Patterson Aug 07 '12 at 14:31