As I was recently serializing objects into XML, I had the need to suppress a few of the elements in the ouput. After looking around, I finally found “XMLElement” and some examples which I reworked in VB .NET.
To start with, I have a base class with a method called GenerateXML which each inheriting class overloads. In the method, I use an XmlSerializer to generate the XML and everything was working quite well, until the day before yesterday.
The main problem was in a particular subclass that has a property with type DateTime. As all of you know (as do I now,) anytime you try to serialize such an object, you get this in the XML for the property:
<MyDateProperty>0001-01-01T00:00:00.0000000+01:00</MyDateProperty>
When SQL Server tried to update the appropriate table column with the value, I got:
The conversion of a char data type to a datetime data type resulted
in an out-of-range datetime value.
The statement has been terminated.
I thought the DateTime datatype would be consistently nullable between the .NET framework and SQL Server. Guess I was wrong.
The trick became to figure out how to supress the MyDateProperty element in the serialized XML. What to do:
- Develop a stylesheet to transform the xml before passing it to the stored procedure?
- Create a new property with type string in the class and then use hidden inputs on the web form to set and get values?
- Set the data type of the property to string and then marshal the string into a date and vice-verse where necessary?
So many ways to skin a cat. Then I started thinking “there has to be a way to control serialization of the class in the XMLSerializer.” I found the XMLElement attribute along with a really good thread applicable to my case here. There were only two differences in my case:
- I’m using VB .NET
- I needed to figure a way out of how to do it design-time in the class and not when the class gets serialized by the XMLSerializer
After a good deal of tweaking, I finally got the xxxxSpecified idea (see above) to work inside my subclass. Here’s the (VB .NET):
<XmlElement(ElementName:=”MyDateProperty”, DataType:=”date”)> _
Property MyDateProperty() As DateTime
Get
Return _MyDateProperty
End Get
Set(ByVal Value As DateTime)
_MyDateProperty = Value
End Set
End Property
<XmlIgnore()> Property MyDatePropertySpecified() As Boolean
Get
Return _ShowIgnoredElement
End Get
Set(ByVal Value As Boolean)
_ShowIgnoredElement = Value
End Set
End Property
All that’s left is to set the MyDatePropertySpecified property in a constructor of the subclass. Here’s an example:
‘ Author: Anthony Jay Bull
‘ Date: 2006-11-21
‘ In: All the params off of the query string as provided
‘ by a NameValueCollection object
‘ Notes: The MyDateWebControl is providing the date in this case
‘ in the format of “YYYY-DD-MM”
Public Sub New(ByVal formParams As System.Collections.Specialized.NameValueCollection)
Dim arrPickedDate() As String
arrPickedDate =_
HttpUtility.HtmlEncode(formParams.Item(”MyDateWebControl”)).Split(”-”)
If arrPickedDate.Length = 3 Then
Me.MyDateProperty = New DateTime(arrPickedDate(0), _
arrPickedDate(2), arrPickedDate(1))
Me.MyDatePropertySpecified = True
Else
Me.MyDatePropertySpecified = False
End If
End Sub
Now, instead of this:
<SomeRootElement>
<SomeSiblingOfMyDate>Some string value</SomeSiblingOfMyDate>
<MyDateProperty>0001-01-01T00:00:00.0000000+01:00</MyDateProperty>
</SomeRootElement>
…or even this:
<SomeRootElement>
<SomeSiblingOfMyDate>Some string value</SomeSiblingOfMyDate>
<MyDateProperty/>
</SomeRootElement>
I now get this…
<SomeRootElement>
<SomeSiblingOfMyDate>Some string value</SomeSiblingOfMyDate>
</SomeRootElement>