Serializing Objects to a .NET DataSet
- Applying XML Attributes
- Serializing Objects to a Stream
- Reading an XML Stream into a DataSet
- Summary
Serializing Objects to a DataSet
Introduction
DataSets are powerful abstractions introduced with ADO.NET that allow you to manage all kinds of data, not just database-originated data. Serializing objects to a DataSet provides me with an opportunity to introduce several technologies found in the .NET Framework. Additionally, you may find it useful to convert existing objects into a DataSet.
This article describes the XmlSerializer, XML attributes in .NET, streams, and the ADO.NET DataSet. The XmlSerializer can be used to persist and reconstitute persisted objects; in addition, it's an essential aspect of XML web services. Streams are used to manage data, including data found in files, and the ADO.NET DataSet is especially useful as a data repository for any data. Individually and combined, these technologies represent powerful .NET programming tools.
Applying XML Attributes
Extensible Markup Language (XML) is ubiquitous in .NET. Interestingly, you don't have to learn how to read XML to use XML capabilities in .NET, because .NET can read and write XML on your behalf. XML is a language that has proven useful as a means of transmitting self-describing data, composed of metacharacters and text, between computers. Due to its self-describing capabilities, XML is an especially useful kind of text to send across the Internet.
Knowing that data is moved around as XML is important. Consider the case where we have a class named Customer, containing a name, phone number, and web address. Well-named properties in C# might include Name, Phone, Website, but these might not represent good display names. We could use XML attributes to provide better display names, or use other XML attributes to indicate that we want a property to be ignored during serialization. Listing 1 demonstrates a sample Customer class that uses two of the standard XML attributes to describe how properties should be treated when serialized.
Listing 1A Customer Class That Demonstrates the XmlElementAttribute and the XmlIgnoreAttribute
1: [Serializable] 2: public class Customer 3: { 4: private string id; 5: private string name; 6: private string website; 7: private string phone; 8: private static int count; 9: 10: public Customer() 11: { 12: id = (count++).ToString(); 13: } 14: 15: public Customer(string name) : this() 16: { 17: this.name = name; 18: } 19: 20: public Customer(string name, string website): this() 21: { 22: this.name = name; 23: this.website = website; 24: } 25: 26: public Customer(string name, 27: string website, string phone): this() 28: { 29: this.name = name; 30: this.website = website; 31: this.phone = phone; 32: } 33: 34: [XmlIgnore] 35: public string Id 36: { 37: get{ return id;} 38: set{ id = value; } 39: } 40: 41: [XmlElement("Customer Name")] 42: public string Name 43: { 44: get{ return name; } 45: set{ name = value; } 46: } 47: 48: [XmlElement("Customer Phone")] 49: public string Phone 50: { 51: get{ return phone; } 52: set{ phone = value; } 53: } 54: 55: [XmlElement("URL")] 56: public string Website 57: { 58: get{ return website; } 59: set{ website = value; } 60: } 61: }
NOTE
By convention, we drop the Attribute suffix when applying an attribute. Thus, XmlIgnoreAttribute becomes XmlIgnore when applied.
Attributes are just classes. They have a unique function in that attributes allow you to convey extra information about an entity, written as metadata, which makes attributes very useful. For example, you can apply code access security declaratively by using security attributes in .NET.
NOTE
Details on .NET security will be covered in my upcoming book, The Visual Basic .NET Developer's Book (Addison-Wesley, ISBN 0-672-32407-5), which is scheduled for publication Fall 2002.
Lines 34, 41, 48, and 55 of Listing 1 demonstrate XmlElementAttribute and XmlIgnoreAttribute from the System.Xml.Serialization namespace.
I said earlier that you don't need to know how to read or write XML to use XML in .NET. This is true. In fact, the Serializable attribute on line 1 tells .NET that Customer objects can be serialized. Using Reflection, the serializer simply reflects the public properties and writes them as XML. (Reflection is a technology in .NET for discovering type information.)
The XmlIgnore and XmlElement attributes simply provide additional instructions to the serializer, indicating how the properties should be serialized. XmlIgnore instructs the serializer not to serialize a property, and the XmlElement attribute enables you to specify an alternate name for the property.
The Customer class uses these elements as you might expect. Notice in Listing 1 that we want to ignore the Id property; for example, we may want to ignore database identity fields when displaying data. The XmlElement attribute is used on the Name, Phone, and Website properties to provide a better name than the property name for display purposes. Listing 2 shows a serialized array of Customer objects after the XML attributes are applied.
Listing 2A Serialized XML Array of Customer Objects
<?xml version="1.0"?> <ArrayOfCustomer xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Customer> <Customer_x0020_Name>Amway</Customer_x0020_Name> <URL>http://www.amway.com/</URL> </Customer> <Customer> <Customer_x0020_Name>Merrill-Lynch</Customer_x0020_Name> <URL>http://www.merrilllynch.com/</URL> </Customer> <Customer> <Customer_x0020_Name>Puerto Rico Ports Authority</Customer_x0020_Name> </Customer> </ArrayOfCustomer>
Note that you don't have to use XML attributes to support serializationjust the Serializable attribute. It's also worth noting that the Id wasn't serialized because we used the XmlIgnore attribute, but the phone number wasn't serialized for the simple reason that there was no data provided for that field. The serializer abbreviates the XML, ignoring null properties by default.