Click here to Skip to main content
15,885,244 members
Articles / Programming Languages / JScript .NET

JSON and C# using Generics and Delegates

Rate me:
Please Sign up or sign in to vote.
4.33/5 (2 votes)
1 Apr 2009CPOL3 min read 28.6K   24   1
JSON and C# using Generics and delegates

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:

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

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

C#
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:

JavaScript
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:

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

    /// <summary>
    ///     Class to help serialize AirWatch objects to the client
    /// </summary>
    public class JSONObject<T> 
    {        
        /// <summary>
        ///     The object to serialize
        /// </summary>
        private readonly T _object;

        /// <summary>
        ///     A list of properties to serialize
        /// </summary>
        private readonly List<string> _properties;

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

        /// <summary>
        ///     Serialize to the JSON representation
        /// </summary>
        /// <returns>The JSON representation</returns>
        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:

XML
<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:

C#
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 ...

JavaScript
<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:

JavaScript
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)


Written By
Program Manager Microsoft
United States United States
Note: articles posted here are independently written and do not represent endorsements nor reflect the views of my employer.

I am a Program Manager for .NET Data at Microsoft. I have been building enterprise software with a focus on line of business web applications for more than two decades. I'm the author of several (now historical) technical books including Designing Silverlight Business Applications and Programming the Windows Runtime by Example. I use the Silverlight book everyday! It props up my monitor to the correct ergonomic height. I have delivered hundreds of technical presentations in dozens of countries around the world and love mentoring other developers. I am co-host of the Microsoft Channel 9 "On .NET" show. In my free time, I maintain a 95% plant-based diet, exercise regularly, hike in the Cascades and thrash Beat Saber levels.

I was diagnosed with young onset Parkinson's Disease in February of 2020. I maintain a blog about my personal journey with the disease at https://strengthwithparkinsons.com/.


Comments and Discussions

 
GeneralNice atricle Pin
Najmul Hoda7-Apr-09 9:06
Najmul Hoda7-Apr-09 9:06 

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

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