Serializing A DataSet With DateTime Columns

by Scosby Friday, March 1, 2013

The Database

I was recently working on a legacy web service that returns a DataSet. Sometimes, these DataSets include DateTime columns with values that come from a database (Figure 1). On the client, it was confusing to see time zone offsets that were not in the database values. The clients could be in different time zones than the web server, so this behavior was easily overlooked during development.

Figure 1 –A Date Value Record

The DataSet

I wondered where the offsets were being added (Figure 2). Clearly, they weren't part of the database. I discovered they are created by the DataSet based on the time zone of the computer where it is serialized. This happens automatically when the web service returns a DataSet to the client. It also happens if you call the DataSet.GetXml method. In either case, 2003-04-06T00:00:00 was becoming 2003-04-06T00:00:00-05:00 and creating the confusion (albeit a different instance in time!).

Figure 2 - DataSet XML With An Offset

I needed to find a way to control how the DataSet was serializing its DateTime columns. After visualizing one of the DataSets (Figure 3), I noticed a property on the DataColumn called DateTimeMode. All of the columns had this property, even the columns that were not DateTime columns. I noticed they were all set to UnspecifiedLocal and decided to investigate.

Figure 3 – Visualizing Columns In A DataSet

 

The Server-Side Fix

Usually, it is not possible to change the DateTimeMode of a column once a DataSet has rows. However, it is possible to change the mode between UnspecifiedLocal and Unspecified because that only affects serialization and not the actual value. This is exactly what I needed and so I wrote the following code on the server side:

System.Data.DataSet data = new DataSet();

 

// ...

 

// Iterate the columns and set DataColumn.DateTimeMode

// to DataSetDateTime.Unspecified to remove offset

// when serialized.

foreach (DataTable table in data.Tables)

{

    foreach (DataColumn item in table.Columns)

    {

        // Switching from UnspecifiedLocal to Unspecified

        // is allowed even after the DataSet has rows.

        if (item.DataType == typeof(DateTime) &&

            item.DateTimeMode == DataSetDateTime.UnspecifiedLocal)

        {

            item.DateTimeMode = DataSetDateTime.Unspecified;

        }

    }

}

This code is pretty straight forward. Changing the column’s mode to Unspecified results in a DateTime value with no offset. This value now matches the database record exactly. This leaves the problem of formatting the value for display completely up to the client-side application.

Figure 4 - DataSet XML With No Offset

Summary

This post discussed how to control the formatting of DateTime columns when a DataSet is serialized. I showed an example of the default behavior which includes the time zone information offset. Finally, I showed a code snippet that changes the behavior to exclude the offset.

Tags: , , ,

IT | Programming

Xml Serializing Internal Classes

by Scosby Monday, May 16, 2011

Introduction

The XmlSerializer does not work with internal classes, instead it only works with public classes. There is a helpful class introduced with WCF in .NET Framework 3.5 called the DataContractSerializer, which can be used for any class. The process is similar to using the XmlSerializer. This article will demonstrate a simple scenario for the user, and explain one approach (out of many!) for serializing a .NET class, defined as internal, into XML.

What is Serialization

Serialization is a complex topic and many users find it confusing. In simple terms, serialization can be defined as: “the process of converting an object into a form that can be easily stored or transmitted”.

This process is a two-way street. When the user is turning an object into XML, this is called as serialization. When the user is turning XML into an object, this is called as deserialization. While both terms are similar, the difference is simply in what direction the process operates.

Serialization is a great tool for the user to have in her toolbox. Often times, an application will need to save data so it can be loaded the next time the application starts up. One such example is the options or settings that can be configured by an end user. While more advanced examples cover the transmission of serialized objects, including web services and remoting.

Serializers

For this post, the user will discuss two different classes that can serialize objects into XML. Of course, this can be accomplished in a variety of ways in the .NET Framework but that is a great exercise for the inquisitive user wishing to learn more. The topic of discussion is how to serialize internal classes, which cannot be accomplished with the XmlSerializer so it will only be discussed briefly.

XmlSerializer

The XmlSerializer class is in the System.Xml.Serialization namespace of the System.Xml.dll assembly. It is capable of converting an object's public properties and fields, given a public class. It will not work with a class that is not publically accessible. This provides a simple and easy to use serializer that is great for many classes. The user should always use this class when she can, because it is very simple and straightforward.

DataContractSerializer

The DataContractSerializer class is in the System.Runtime.Serialization namespace of the System.Runtime.Serialization.dll assembly. It is capable of letting the user declare a contract that governs the serialization of an object. A contract, in this case, means the user gets to choose what is serialized based on attributes used by the DataContractSerializer when serializing an object. This approach sounds more complicated, but is simpler than it first appears! Of course, the trade-off is the requirement forcing the user to declare a contract via attributes. This becomes tedious for large classes with lots of members to serialize, but the pattern is easy.

Scenario

Assume the following scenario for a customer service application: a company class exists that needs to be serialized but it should not be publically accessible outside the assembly. Thus, the class is defined as internal. The company class also defines a list of company employees, another class that is internal. The application outputs a list of the company’s employees. This output should be in an XML file format so it can be interoperable with various other Line of Business (LOB) and 3rd party applications.

 

Code Sample – Company class

    [DataContract(Namespace = "")]

    internal class Company

    {

        [DataMember]

        public string CompanyName { get; set; }

 

        [DataMember]

        public List<Employee> CompanyEmployees { get; set; }

    }

 

 

Code Sample – Employee class

    [DataContract(Namespace = "")]

    internal class Employee

    {

        [DataMember]

        public string Name { get; set; }

 

        public string Address { get; set; }

 

        [DataMember]

        public DateTime StartDate { get; set; }

 

        [DataMember]

        internal int Salary { get; set; }

    }

The first thing the user should note is the DataContract and DataMember attributes. These attributes allow the DataContractSerializer to determine which class members belong in the output. The user should ensure the class is marked with the DataContract attribute and all members to be serialized are marked with the DataMember attribute. 

The astute reader will have noticed the Employee.Address property is not decorated with the DataMember attribute. The serialization process will ignore the Employee.Address property, in this case it serves as a demonstration, but it certainly could be marked as a DataMember if the user wished.

 

 

Code Sample – Serializing the Company Class


       
public static string Serialize(Company value)

        {

            if (value == null)

            {

                throw new ArgumentNullException("value");

            }

 

            StringBuilder xmlData = new StringBuilder();

 

            using (XmlWriter xw = XmlWriter.Create(xmlData, new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true }))

            {

                DataContractSerializer dcs = new DataContractSerializer(typeof(Company));

 

                dcs.WriteObject(xw, value);

            }

 

            return xmlData.ToString();

        }

 

The important thing to notice is how the DataContractSerializer writes to a StringBuilder that is returned to the caller. This string is typically saved to a XML config file. In this case, the user will simply keep the string in memory in order to construct another instance of the Company class. However, it is a good exercise to save this string to a file and then load the file later to deserialize its contents!

After serializing the company class, the XML output will look as follows:

  <Company xmlns:i="http://www.w3.org/2001/XMLSchema-instance">

    <CompanyEmployees>

      <Employee>

      <Name>John Doe</Name>

      <Salary>10</Salary>

      <StartDate>2009-12-15T00:00:00</StartDate>

    </Employee>

      <Employee>

      <Name>Steve Curran</Name>

      <Salary>20</Salary>

      <StartDate>1975-05-22T00:00:00</StartDate>

    </Employee>

  </CompanyEmployees>

  <CompanyName>Contoso</CompanyName>

</Company>

 

Code Sample – Deserializing the Company Class


       
public static Company Deserialize(string xmlData)

        {

            if (string.IsNullOrWhiteSpace(xmlData))

            {

                throw new ArgumentNullException("xmlData");

            }

 

            XmlReaderSettings settings = new XmlReaderSettings()

            {

                CloseInput = true,

            };

 

            using (XmlReader xr = XmlReader.Create(new StringReader(xmlData), settings))

            {

                DataContractSerializer dcs = new DataContractSerializer(typeof(Company));

 

                return (Company)dcs.ReadObject(xr);

            }

        }

 

Here, the important thing to notice is how the DataContractSerializer is using a XmlReader to parse the string and deserialize a new instance of the Company class, which is returned to the caller. Besides reading a string, this method is similar to the one described earlier. In simple terms, the expected result of deserialization is an object in the same state as when it was serialized.

 

In some advanced scenarios, administrators or developers could change the XML values in file system (if the serialization saves the values, of course!). This enables customizations and scripts which can ease the deployment & configuration burden for users of an application. Be aware, this kind of behavior opens the door to malicious attacks and is a primary example of why the user should be cautious about what kind of information is serialized and (arguably more important) deserialized.

 

 

Code Sample – Creating Contoso


       
public static void Run()

        {

            Company contoso = new Company();

 

            contoso.CompanyName = "Contoso";

 

            Employee johnDoe = new Employee();

            johnDoe.Address = "12345 street";

            johnDoe.Name = "John Doe";

            johnDoe.Salary = 10;

            johnDoe.StartDate = new DateTime(2009, 12, 15);

 

            Employee steveCurran = new Employee();

            steveCurran.Address = "56789 blvd";

            steveCurran.Name = "Steve Curran";

            steveCurran.Salary = 20;

            steveCurran.StartDate = new DateTime(1975, 5, 22);

 

            contoso.CompanyEmployees = new List<Employee>() { johnDoe, steveCurran };

 

            string xml = Serialize(contoso);

 

            Company newContoso = Deserialize(xml);

 

            //Compare the two Contoso instances to verify serialization

        }

This method utilizes the code samples the user has learned in this post. A Company instance is created and populated with some mock data. This instance is then serialized and stored in a string variable named “xml”. Finally, a new Company instance is deserialized so the user can compare the two instances and see how they differ.

Concerns

While the DataContractSerializer sounds like a great tool, and it certainly is useful, the user must be careful to understand when and why it would be used to serialize a class. If the user has a public class, then the best way to serialize that class is with the XmlSerializer. The DataContractSerializer has many additional benefits, but for the scope of this article it is important to note that it’s used to get around the XmlSerializer’s limitations with an internal class. The user can find many other uses of the DataContractSerializer in the context of WCF, but this is a good, albeit creative, solution for applications that must XML serialize an internal class.

More Information

Serialization – MSDN topic

Serialization Samples - MSDN samples

ASMX Web Services & XML Serialization - MSDN forums

.NET Remoting & Runtime Serialization – MSDN forums

Tags: ,

IT | Programming