Click here to Skip to main content
Click here to Skip to main content
Technical Blog

JSON and C# using Generics and Delegates

, 1 Apr 2009 CPOL
Rate this:
Please Sign up or sign in to vote.
JSON is a method for transferring data, similar to XML and other formats. There are many advantages to using this method. It is human readable, and it translates easily to objects on the client side of the browser.

JSON or JavaScript Object Notation, is a method for transferring data, similar to XML and other formats. There are many advantages to using this method. It is human readable, and it translates easily to objects on the client side of the browser.

With JSON, I can declare an array like this:

var myArray = ["this","that","the other"]; 

The object notation is even simpler. Imagine a C# "Person" class:

public class Person 
{
   public int ID { get; set; } 
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public string SSN { get; set; }
}

If I want to express this data to the client, I can do something like this:

var person = { 
   "ID" : "1", 
   "FirstName" : "Jeremy",
   "LastName" : "Likness",
   "SSN" : "111-222-3333" 
};
alert("My name is " + person.FirstName + " " + person.LastName); 

One criticism of the WebForms view engine (the one most of you are using in .NET ... while other view engines such as NVelocity have existed as part of the MonoRail project, Microsoft only recently released the MVC release candidate which introduces the Model-View-Controller view engine) is that it overburdens the client when rendering simple tags. If you have compared <input type="text"> with an <asp:TextBox>, you get the point.

Furthermore, developers tend to get lost in the "ease" of the AJAX framework and often fail to consider the performance implications of wrapping, say, cascading drop downs in an update panel. A much easier method is to serialize the values and bind them using a third-party tool like JQuery instead.

While I was working on this framework, I realized it would be quite simple to serialize my domain objects for JSON. I wanted something generic, that didn't rely on reflection for abstraction, and gave me full control over which attributes to render without having to dirty my domain model with attributes or other declarations for something that is entirely UI-related.

The result? A "JSONObject" with a Serialize() method that emits the JSON code. Here is the class:

namespace MyJSON 
{
    /// <span class="code-SummaryComment"><summary>
</span>    ///     Delegate to determine how a value is pulled from the object
    /// <span class="code-SummaryComment"></summary>
</span>    /// <span class="code-SummaryComment"><param name="instance">The instance to pull the property from</param>
</span>    /// <span class="code-SummaryComment"><param name="property">The value of the instance</param>
</span>    /// <span class="code-SummaryComment"><returns>The string representation of the value for that property</returns>
</span>    public delegate string PropertyValue<t>(T instance, string property);

    /// <span class="code-SummaryComment"><summary>
</span>    ///     Class to help serialize AirWatch objects to the client
    /// <span class="code-SummaryComment"></summary>
</span>    public class JSONObject<T> 
    {        
        /// <span class="code-SummaryComment"><summary>
</span>        ///     The object to serialize
        /// <span class="code-SummaryComment"></summary>
</span>        private readonly T _object;

        /// <span class="code-SummaryComment"><summary>
</span>        ///     A list of properties to serialize
        /// <span class="code-SummaryComment"></summary>
</span>        private readonly List<string> _properties;

        /// <span class="code-SummaryComment"><summary>
</span>        ///     Reference to delegate to parse the value
        /// <span class="code-SummaryComment"></summary>
</span>        private readonly PropertyValue<t> _propValue; 
               
        /// <span class="code-SummaryComment"><summary>
</span>        ///     Constructor for JSON object
        /// <span class="code-SummaryComment"></summary>
</span>        /// <span class="code-SummaryComment"><param name="instance">The entity instance</param>
</span>        /// <span class="code-SummaryComment"><param name="properties">The list of properties to serialize</param>
</span>        /// <span class="code-SummaryComment"><param name="propValue">The method to extract the property value</param>
</span>        public JSONObject(T instance, IEnumerable<string> properties, 
		PropertyValue<T> propValue)
        {
            _object = instance;
            _properties = new List<string>(properties);
            _propValue = propValue; 
        }

        /// <span class="code-SummaryComment"><summary>
</span>        ///     Serialize to the JSON representation
        /// <span class="code-SummaryComment"></summary>
</span>        /// <span class="code-SummaryComment"><returns>The JSON representation</returns>
</span>        public string Serialize()
        {
            StringBuilder json = new StringBuilder();

            json.Append("{");

            bool first = true;

            foreach(string prop in _properties)
            {
                if (first)
                {
                    first = false;
                }
                else
                {
                    json.Append(","); 
                }
                string value = _propValue(_object, prop);
                json.Append(string.Format("\"{0}\":{1}", prop, EncodeJsString(value))); 
            }

            json.Append("}"); 

            return json.ToString(); 
        }
   }
}

The JSON object takes a type of T which can be anything. The constructor takes in "T", along with an array and a delegate. The array is a list of strings describing the properties I am interested in. For example, I may only want to send id and last name because I don't use the other attributes in my client script. Finally, the delegate. The signature is simple: given the attribute and the entity, what is the value as a string? This allows me to inject the logic to map the UI attributes to the domain attributes. The easiest way to send the data is to realize it as a string and then manipulate it appropriately on the client. After all, JavaScript itself doesn't "know" about any of our complex objects.

The simplest use would be simply to send one of my Person objects and show the name. For example:

<b>ID: </b> <span id="personId"> </span>
<b>Name: </b> <span id="personName"> </span>

In my own script, I simply make my JSON object and serialize it out:

JSONObject<Person> jsonPerson = new JSONObject<Person>(
   new Person { ID = 1, LastName="Likness" },
   new[] { "id", "name" }, 
   (entity,property) => property.Equals("id") ? entity.ID : entity.LastName
);
Page.ClientScript.RegisterClientScriptBlock(GetType(),GetType(),
   string.Format("var person={0}",jsonPerson.Serialize()),true);

Finally, I need something to wire it in for me, I'll choose JQuery ...

<script type="text/javascript">
   $(document).ready(function(){
      $("#personId").html(person.id);
      $("#personName").html(person.name); 
   });
</script>

The script block takes a type (I'm just using the type of the page or control I'm in), a key (this should be unique per script block ... I'm using the type again here but could have it strongly typed or set as a const, etc), the JavaScript to emit (from our serialize method on the JSON object), and then the true tells it to wrap my script tags because I haven't done it myself.

These objects can come back as the result of a callback (just assign them to the window.var object so they are globally accessible and use an eval) for dynamic binding, or you might simply render an array of objects and then do something like this:

for (var x = 0; x < window.json_options.length; x++) {
            var option = window.json_options[x];
            $("#selBox").append("<option value=\"" +
                option.id + "\"" + +(first ? " checked=\"checked\"" : "") 
			+ ">" + option.value + "</option>");
        }

which will bind the drop down list. If you are fighting with the urge to cry "hack" because we're wiring in HTML ... remember, this is what ASP.NET does under the covers for you. In the end, controls are complex text rendering engines that emit fragments the browser can manage.

Of course, the next step was to make a JSONList<T> and I purposefully left the encode script out. You can Google some solutions for that.

Jeremy Likness

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Jeremy Likness
Architect Wintellect
United States United States
Jeremy Likness is a principal consultant at Wintellect. Jeremy, an experienced entrepreneur and technology executive, has successfully helped ship commercial enterprise software for 20 years. He specializes in catalyzing growth, developing ideas and creating value through delivering software in technical enterprises. His roles as business owner, technology executive and hands-on developer provided unique opportunities to directly impact the bottom line of multiple businesses by helping them grow and increase their organizational capacity while improving operational efficiency. He has worked with several initially small companies like Manhattan Associates and AirWatch before they grew large and experienced their transition from good to great while helping direct vision and strategy to embrace changing technology and markets. Jeremy is capable of quickly adapting to new paradigms and helps technology teams endure change by providing strong leadership, working with team members “in the trenches” and mentoring them in the soft skills that are key for engineers to bridge the gap between business and technology.
Follow on   Twitter   Google+   LinkedIn

Comments and Discussions

 
GeneralNice atricle PinmemberNajmul Hoda7-Apr-09 10:06 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.141216.1 | Last Updated 1 Apr 2009
Article Copyright 2009 by Jeremy Likness
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid