Improve Your Model Classes With OOP - Part Three - Serialization

In part 1 of this series, I discussed building model classes properly with Object-Oriented Programming (OOP), specifically encapsulation that must always include data validation. In part 2 I showed you constructors, interfaces and more that you should implement in your model classes. In this article, we will build upon the Person.cs type from part 2 and end up with a new Person type ready for serialization. Serialization is something important to think about for good model class design, even though it’s not really part of OOP. If you implement what I discuss, other developers using these models will really appreciate the little bit of extra work.
 
Wikipedia defines serialization as: In computer science, in the context of data storage, serialization is the process of translating data structures or object state into a format that can be stored (for example, in a file or memory buffer) or transmitted (for example, across a network connection link) and reconstructed later (possibly in a different computer environment). It goes on to add this for OOP: Serialization of object-oriented objects does not include any of their associated methods with which they were previously linked.
 
Since these articles are focusing on model classes, the Wikipedia definition fits since these types of objects that need to be serialized to be sent via web-based API’s, ASP.NET view models and even for databases like Cosmos DB since its internal storage is JavaScript Object Notation (JSON). I even serialize configuration objects to and from disk for apps that I write to store app and user data.
 
Improve Your Model Classes With OOP - Serialization 
 
Let us improve Person.cs to include what it needs to properly serialize to and from JSON and XML.
 

Serializing to JSON

 
I would say that the way most objects these days that get serialized would be using JSON. I would also say, that with over 266 million downloads, the Newtonsoft.JSON NuGet package is the most popular library to do JSON serialization.
 
Using this package, it only takes one line of code like this.
  1. var json = JsonConvert.SerializeObject(people);  
  2. var people = JsonConvert.DeserializeObject<List<Person>>(json);  
If we serialize a List<Person> with two items (with fake data), this is what it looks like in JSON.
  1. [  
  2.   {  
  3.     "Address1""yJuDoux_HGTsXod",  
  4.     "Address2""qAUPPFylqn",  
  5.     "BornOn""2005-12-14T12:55:24.2371442-08:00",  
  6.     "CellPhone""681-064-3138",  
  7.     "City""COgx^xpxdFMhFup",  
  8.     "Country""OjpX\\AXEPDCl[[e",  
  9.     "Email""[email protected]",  
  10.     "FirstName""ukEpbcSWkRPAHka",  
  11.     "HomePhone""072-236-5678",  
  12.     "Id""06ba87e0e0cc4a51a8dc00c827ad401a",  
  13.     "LastName""eKXt\\MU]xJ[dPTNuSFGL",  
  14.     "PostalCode""82268"  
  15.   },  
  16.   {  
  17.     "Address1""Ft^JaGY^vA]W\\df",  
  18.     "Address2""xUqiuNjH[D",  
  19.     "BornOn""2005-12-14T12:55:24.2423257-08:00",  
  20.     "CellPhone""733-337-0770",  
  21.     "City""Q\\Gla`j_M`^sW_s",  
  22.     "Country""bbLaBUmDFlgBF_K",  
  23.     "Email""[email protected]",  
  24.     "FirstName""\\`ecV]OEHU]Ktu`",  
  25.     "HomePhone""807-472-7275",  
  26.     "Id""a34f3777518e49e2acd62775e5503621",  
  27.     "LastName""^YAAt_dyBDxNnJWS]DM^",  
  28.     "PostalCode""17147"  
  29.   }  
  30. ]  

Fixing JSON Formatting

 
One thing we need to do is to fix the property name casing since it’s not compliant with JSON coding standards. In the OOP world, properties start with an uppercase (PascalCasing) and in the JSON world they should start with a lower case (camelCasing). It’s easy enough to do with attributes.
 
First, we need to add the DataContract attribute to the class like this:
  1. [DataContract(Name = "person")]  
  2. public class Person : IEquatable<Person>, IComparable, IComparable<Person>  
Then we need to add the DataMember attribute to all the properties we want to serialize like this:
  1. [DataMember(Name = "address1")]  
  2. public string Address1  
I’d like to point out that you can use these two attributes to change terribly named data properties from API endpoints from companies like Salesforce, to proper OOP naming. Here is an example:
  1. [DataMember(Name = "Total_Units_Sold__c")]  
  2. public double UnitsSold  
Making a property required is easy too:
  1. [DataMember(Name = "email", IsRequired = true)]  
  2. public string Email  
Now, with these attributes, the JSON looks like this:
  1. [  
  2.   {  
  3.     "address1""gVpEAP_pLyRmnYY",  
  4.     "address2""k\\^sqrx\\Dp",  
  5.     "bornOn""2005-12-14T12:52:08.6788613-08:00",  
  6.     "cellPhone""887-720-6030",  
  7.     "city""HCHNugsfZcnknZc",  
  8.     "country""\\slC[htlOFRfCws",  
  9.     "firstName""`hWWQiTQxKxSB[B",  
  10.     "homePhone""113-161-8082",  
  11.     "lastName""NQrHdAqhaDGTWJtHbnr\\",  
  12.     "postalCode""37228",  
  13.     "id""3f1640265c844b908bcc31028ae3f238",  
  14.     "email""[email protected]"  
  15.   },  
  16.   {  
  17.     "address1""mOPddKKZxTyeL\\l",  
  18.     "address2""x^t][sSF\\f",  
  19.     "bornOn""2005-12-14T12:52:08.6852134-08:00",  
  20.     "cellPhone""346-363-7213",  
  21.     "city""ybaCU[AFiYqwrWJ",  
  22.     "country""G`uYv[InxKk\\FNu",  
  23.     "firstName""FREHmWwrHArMWCo",  
  24.     "homePhone""452-157-8818",  
  25.     "lastName""pmcqdytqnT_sjdmJgmYD",  
  26.     "postalCode""26616",  
  27.     "id""81b195b94cb14ee0bf91716cfc3c4b6e",  
  28.     "email""[email protected]"  
  29.   }  
  30. ]  

Serializing to XML

 
So that you don’t leave out applications that still uses XML as their format (which there are a lot), for now, you should make sure that your model-classes support it. Here is the code to serialize and serialize XML (available in my dotNetTips.Utility.Standard NuGet package).
  1. public static string Serialize(object obj)  
  2. {  
  3.     using (var writer = new StringWriter())  
  4.     {  
  5.         using (var xmlWriter = XmlWriter.Create(writer))  
  6.         {  
  7.             var serializer = new XmlSerializer(obj.GetType());  
  8.             serializer.Serialize(xmlWriter, obj);  
  9.    
  10.             return writer.ToString();  
  11.         }  
  12.     }  
  13. }  
  14.   
  15. public static T Deserialize<T>(string xml)  
  16. {  
  17.     using (var sr = new StringReader(xml))  
  18.     {  
  19.         var xs = new XmlSerializer(typeof(T));  
  20.         return (T)xs.Deserialize(sr);  
  21.     }  
  22. }  
If we serialize a List<Person> to XML, it will look like this:
  1. <?xml version="1.0" encoding="utf-16"?>  
  2. <ArrayOfPerson xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">  
  3.   <Person>  
  4.     <Address1>B[adUUt^r]SrhRq</Address1>  
  5.     <Address2>qkbll`gUk[</Address2>  
  6.     <BornOn />  
  7.     <CellPhone>468-244-4428</CellPhone>  
  8.     <City>KIqLScmLgZegq]O</City>  
  9.     <Country>PTsLiTFoJoevOWy</Country>  
  10.     <Email>[email protected]</Email>  
  11.     <FirstName>lWVSgitVYIl\hRo</FirstName>  
  12.     <HomePhone>774-811-5255</HomePhone>  
  13.     <Id>a5938cd190ee4c49a532bbe83644744f</Id>  
  14.     <LastName>EThWhg_nggOQ^o`VwZCv</LastName>  
  15.     <PostalCode>73438</PostalCode>  
  16.   </Person>  
  17.   <Person>  
  18.     <Address1>Qcr`H^pMJJwiaiK</Address1>  
  19.     <Address2>WqlWXqoVbt</Address2>  
  20.     <BornOn />  
  21.     <CellPhone>708-847-5728</CellPhone>  
  22.     <City>EIFZC^YPfP\gwcP</City>  
  23.     <Country>ybC^T[MPfOXuQeS</Country>  
  24.     <Email>[email protected]</Email>  
  25.     <FirstName>VtPlFOlSUtX_jRX</FirstName>  
  26.     <HomePhone>112-642-4284</HomePhone>  
  27.     <Id>16738e0a16e34469bf80f2c43bb527d2</Id>  
  28.     <LastName>rrYKdbIdSsaWL^ANPgcu</LastName>  
  29.     <PostalCode>84820</PostalCode>  
  30.   </Person>  
  31. </ArrayOfPerson>  

Houston, We Have A Problem

 
As you can easily see in the XML, the value for the BornOn property is missing. This is because the serializer in .NET does not support the newer type of DateTimeOffset. I guess the .NET team never went back and fixed this issue, but we can!
 
Before we get to that fix, let's start off with adding the Serializable and XmlRoot attributes to the class.
  1. [Serializable]  
  2. [XmlRoot(ElementName = "People")]  
  3. public class Person : IEquatable<Person>, IComparable, IComparable<Person>  
There are a few ways to fix this missing BornOn value. For this article, we are going to implement it quickly by adding a new property like this:
  1. [EditorBrowsable(EditorBrowsableState.Never)]  
  2. [IgnoreDataMember]  
  3. [XmlElement("BornOn")]  
  4. public string BornOnForXml  
  5. {  
  6.     get  
  7.     {  
  8.         return BornOn.ToString("o");  
  9.     }  
  10.     set  
  11.     {  
  12.         BornOn = DateTimeOffset.Parse(value);  
  13.     }  
  14. }  
I added the EditorBrowsable attribute to hide this property from other assemblies. Then the IgnoreDataMember so the JSON serialization will ignore this property. Then I added the XmlElement attribute to use BornOn as the element name in XML. I also added the XmlElement to the rest of the properties.
 
Then we need to hide the BornOn property from XML serialization like this:
  1. [XmlIgnore]  
  2. public DateTimeOffset BornOn  
You can also use the XmlElement attribute to make the property required.
  1. [XmlElement(IsNullable = false)]  
  2. public string Id  
The final XML looks like this:
  1. <?xml version="1.0" encoding="utf-16"?>  
  2. <ArrayOfPerson xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">  
  3.   <Person>  
  4.     <Address1>fSrGUNBGo`G[xiT</Address1>  
  5.     <Address2>YbTErOSHxE</Address2>  
  6.     <BornOn>2005-12-14T14:42:35.5808138-08:00</BornOn>  
  7.     <CellPhone>257-531-5721</CellPhone>  
  8.     <City>Is^y[yW\Hv[FApm</City>  
  9.     <Country>HETrESKsBEaL_WW</Country>  
  10.     <Email>[email protected]</Email>  
  11.     <FirstName>Zgk^K`EUdsqqACd</FirstName>  
  12.     <HomePhone>158-720-2817</HomePhone>  
  13.     <Id>d3580c8684884098ac1bc656a87190a8</Id>  
  14.     <LastName>xy\utmrEj\nU\eNDijyM</LastName>  
  15.     <PostalCode>41738</PostalCode>  
  16.   </Person>  
  17.   <Person>  
  18.     <Address1>TDloXg\PAsNjsPb</Address1>  
  19.     <Address2>EjsJsx`ngQ</Address2>  
  20.     <BornOn>2005-12-14T14:42:35.5873074-08:00</BornOn>  
  21.     <CellPhone>334-364-7782</CellPhone>  
  22.     <City>lDVuskEaDhfus\u</City>  
  23.     <Country>OgxEXnOF^yPxpPT</Country>  
  24.     <Email>[email protected]</Email>  
  25.     <FirstName>WvxCpBUwPIsxjxe</FirstName>  
  26.     <HomePhone>440-447-7643</HomePhone>  
  27.     <Id>525f843089a740cb8ab15888add465fe</Id>  
  28.     <LastName>]xquclOQiQivqfttjiv^</LastName>  
  29.     <PostalCode>74074</PostalCode>  
  30.   </Person>  
  31. </ArrayOfPerson>  
One more thing, the XML serializer will try to serialize the private fields in our class, so we need to tell it to ignore them like this,
  1. [NonSerialized]  
  2. private string _address1;  

Summary

 
Id like to note that with both JSON and XML, the attributes also allow you to order the properties, but I couldn’t get them to work. In JSON, they didn’t seem to have any affect. With XML, when I set the order, the serialized object would come back blank. If I figure it out, I will update this article.
 
If you prefer videos, here is the video version of this article:
 
 
As you can see, there is much more to building good model classes than just implementing properties. Wouldn't it be a great value add to Visual Studio if it made designing classes like this easier? Maybe that should be the next extension from Mads Kristensen who builds a lot of my favorite Visual Studio extensions. There is a lot more to good OOP design that I will tackle in future articles, so check back here often.
 
The Person class is now over 600 lines of code and documentation, too large to post in this article. You can view it by going to, here.
 
After reading these three articles, do you practice good OOP design? Do have any tips you’d like to share? Please make a comment below.


Similar Articles
McCarter Consulting
Software architecture, code & app performance, code quality, Microsoft .NET & mentoring. Available!