When using AJAX, there are lots of situation we have to transfer some data from one place to another (may be from JavaScript to Code behind and vice-versa). We normally use XML to transfer the data from one place to another. Even thou XML is more powerful and structured way to represent any data, it required a parser to construct the XML and parse it. So we required XML parser both from C# and JavaScript end.
JSON provides convenient way to represent the data in data-interchange. As it is subset of JavaScript, parsing JSON is very easy and there is no parser object required to parse it. It provides an easy way to read and write the data and the amount of data transferring is very less comparing the XML.
Let us take an example of an object and with a collection to understand how JSON notation will look like.
I am taking an example for representing the product entity in Northwind database. I am going to call it as ProductView.
public class ProductView { public int ProductId { get; set; } public string ProductName { get; set; } public string SupplierName { get; set; } public string QuantityPerUnit { get; set; } public double UnitPrice { get; set; } public double UnitsInStock { get; set; } public bool Discontinued { get; set; } }
The XML notation for that object would be
<?xml version="1.0" encoding="utf-8"?> <ProductView xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <ProductId>20</ProductId> <ProductName>Sir Rodney's Marmalade</ProductName> <SupplierName>Specialty Biscuits, Ltd.</SupplierName> <QuantityPerUnit>30 gift boxes</QuantityPerUnit> <UnitPrice>81</UnitPrice> <UnitsInStock>40</UnitsInStock> <Discontinued>false</Discontinued> </ProductView>
The JSON notation would be
{ "ProductId":5, "ProductName":"Chef Anton\u0027s Gumbo Mix", "SupplierName":"New Orleans Cajun Delights", "QuantityPerUnit":"36 boxes", "UnitPrice":21.35, "UnitsInStock":0, "Discontinued":true }
Below is the notation for a collection which hold list of ProductView objects
The XML Notation:
<?xml version="1.0" encoding="utf-8"?> <ArrayOfProductView xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <ProductView> <ProductId>16</ProductId> <ProductName>Pavlova</ProductName> <SupplierName>Pavlova, Ltd.</SupplierName> <QuantityPerUnit>32 - 500 g boxes</QuantityPerUnit> <UnitPrice>17.45</UnitPrice> <UnitsInStock>29</UnitsInStock> <Discontinued>false</Discontinued> </ProductView> <ProductView> <ProductId>19</ProductId> <ProductName>Teatime Chocolate Biscuits</ProductName> <SupplierName>Specialty Biscuits, Ltd.</SupplierName> <QuantityPerUnit>10 boxes x 12 pieces</QuantityPerUnit> <UnitPrice>9.2</UnitPrice> <UnitsInStock>25</UnitsInStock> <Discontinued>false</Discontinued> </ProductView> </ArrayOfProductView>
The JSON notation
[ {"ProductId":3,"ProductName":"Aniseed Syrup","SupplierName":"Exotic Liquids","QuantityPerUnit":"12 - 550 ml bottles","UnitPrice":10,"UnitsInStock":13,"Discontinued":false}, {"ProductId":4,"ProductName":"Chef Anton\u0027s Cajun Seasoning","SupplierName":"New Orleans Cajun Delights","QuantityPerUnit":"48 - 6 oz jars","UnitPrice":22,"UnitsInStock":53,"Discontinued":false}, ]
Here I had given only two ProductView object in the collection for example. If you look at the notations, both are easy to understand. But some of other views are,
- JSON is a lightweight data-interchange format compare to XML (For ex: Counting the no of characters in each format, JSON will be less).
- As it is just a string notation, writing and reading will be very easy. The system will parse it very easily compare to XML.
- JSON objects are types but XML data is type less. JSON support string, number, array, Boolean types, but in XML all data are string only.
- As JSON is a subset of JavaScript, the JSON notation can be easily parsed using eval("(" + JSONString + ")") and parsed object can be used in the same way as in code behind (ObjectName.PropertyName). But to parse the XML, JavaScript require DOM object and APIs.
As JSON provides lots of benefits over XML, it would be better to use it for inter-changing the data.
Here one to note is, as JSON provides lots of flexibility - is JSON will replace XML? The answer is NO. Because XML is more powerful then JSON, it has lots of concepts like XSD, XSLT etc., using XML is equal to using a light weight database. But where to use JSON and XML is the place it differs. If we want to interchange the data between client and server (For Ex: Javascript or JQuery to C#.NET or VB.NET), better to go with JSON. If I required storing the data somewhere and using it sometime after, Required to serialize the heavy data and use it further in code behind etc., better to go with XML.
For more information on what is JSON, how to use JSON in JavaScript, the notation format for different objects - please look at the following urls.
http://www.json.org/
http://www.json.org/js.html
http://www.json.org/fatfree.html
http://msdn.microsoft.com/en-us/library/bb299886.aspx
http://labs.adobe.com/technologies/spry/samples/data_region/JSONDataSetSample.html
In this post, I am going to show an example to understand how to implement JSON with XML HTTP AJAX in ASP.NET pages. I am using Northwind database in this example, so please use the same to test the example source.
The use case scenario for this example would be
- In a Webpage, there should be two dropdown controls. One is to select Categories and another one is for Products.
- When the user select Categories dropdown box, the system should fetch the Products under the selected category and bind to the Product dropdown.
- When a Product selected, the system should fetch the information of selected product form the database and show in the screen (I use Supplier Name, UOM and Unit Price here to show)
- When Process button pressed, the system should bind the list of Orders for the product selected and show in a grid.
The implementation details would be
- To bind list of products for the selected Category (step 1), I am going to use XML HTTP AJAX. Once the Category selected, there will be a call to the server with required parameter. In code behind, the list of products will be fetched and converted (serialized) to JSON and return to JavaScript as a result of AJAX call. In JavaScript, the JSON will be parsed to an array and bind it to the Dropdown. (Here a collection is used to parse and use with JSON)
Note: I am showing Loading... message in the Products dropdown by clearing existing items in the dropdown. So the system avoid selecting any items and the user get to know some data getting populated from server.
- When selecting a Product (step 2), there will be again a call to server using XML HTTP AJAX. The code behind will fetch the information and send back as a JSON to JavaScript. The Javascript will parse and show it to the page. (Here an object is used to parse and use with JSON)
Note: I am showing a Progress image with Working on your request message in the screen by making screen as gray. So the system avoid doing any operations.
- When pressing Process button, I am making server call on the same page and bind to the GridView using code behind. (Here I am using Microsoft provided ASP.NET extension to understand how to use both the concept in a same page)
Note : As I am showing two types of Progress message such as Loading... (on Category selection), Working on your request (on Product selection), you might confuse why two different Progress action in a single page. This is an example to show how to use AJAX, so the reader can use which Progress action like to have in own project. I also use System.Threading.Thread.Sleep(1000) statement to see the Progress message in the screen. So please remove this statement to know actual performance of the program.
The implementation code
Code behind for the page generates JSON response - GetAJAXResponse.aspx
protected void Page_Load(object sender, EventArgs e) { string strResponse = string.Empty; if (Request.QueryString["CallType"] != null) { string strCallType = Request.QueryString["CallType"].ToString(); if (strCallType == "ProductList") { if (Request.QueryString["CategoryId"] != null) strResponse = GetProductViewList(Convert.ToInt32(Request.QueryString["CategoryId"].ToString())); } if (strCallType == "ProductInfo") { if (Request.QueryString["ProductId"] != null) strResponse = GetProductInfo(Convert.ToInt32(Request.QueryString["ProductId"].ToString())); } } Response.Clear(); Response.ContentType = "text/xml"; Response.Write(strResponse); Response.End(); } public string GetProductViewList(int intCategoryId) { using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnection"].ConnectionString)) { SqlCommand command = new SqlCommand( "SELECT ProductId, ProductName, CompanyName, QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued " + "FROM Products JOIN Suppliers ON Suppliers.SupplierId = Products.SupplierId WHERE Products.CategoryId = " + intCategoryId, connection); connection.Open(); SqlDataReader dr = command.ExecuteReader(CommandBehavior.CloseConnection); IList<ProductView> ProductViewList = new List<ProductView>(); while (dr.Read()) { ProductView productView = new ProductView(); productView.ProductId = Convert.ToInt32(dr["ProductId"].ToString()); productView.ProductName = dr["ProductName"].ToString(); productView.SupplierName = dr["CompanyName"].ToString(); productView.QuantityPerUnit = dr["QuantityPerUnit"].ToString(); productView.UnitPrice = Convert.ToDouble(dr["UnitPrice"].ToString()); productView.UnitsInStock = Convert.ToDouble(dr["UnitsInStock"].ToString()); productView.Discontinued = Convert.ToBoolean(dr["Discontinued"].ToString()); ProductViewList.Add(productView); } // I am delaying the response to see the Loading... message on the dropdown System.Threading.Thread.Sleep(1000); System.Web.Script.Serialization.JavaScriptSerializer objSerializer = new System.Web.Script.Serialization.JavaScriptSerializer(); return objSerializer.Serialize(ProductViewList); } } public string GetProductInfo(int intProductId) { using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnection"].ConnectionString)) { SqlCommand command = new SqlCommand( "SELECT ProductId, ProductName, CompanyName, QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued " + "FROM Products JOIN Suppliers ON Suppliers.SupplierId = Products.SupplierId WHERE Products.ProductId = " + intProductId, connection); connection.Open(); SqlDataReader dr = command.ExecuteReader(CommandBehavior.CloseConnection); ProductView productView = new ProductView(); while (dr.Read()) { productView.ProductId = Convert.ToInt32(dr["ProductId"].ToString()); productView.ProductName = dr["ProductName"].ToString(); productView.SupplierName = dr["CompanyName"].ToString(); productView.QuantityPerUnit = dr["QuantityPerUnit"].ToString(); productView.UnitPrice = Convert.ToDouble(dr["UnitPrice"].ToString()); productView.UnitsInStock = Convert.ToDouble(dr["UnitsInStock"].ToString()); productView.Discontinued = Convert.ToBoolean(dr["Discontinued"].ToString()); } // I am delaying the response to see the Progress (Waiting for your response) message on the screen System.Threading.Thread.Sleep(1000); System.Web.Script.Serialization.JavaScriptSerializer objSerializer = new System.Web.Script.Serialization.JavaScriptSerializer(); return objSerializer.Serialize(productView); } }
The aspx script for example Web Page - JSONExample.aspx
<div id="alpha" class="alpha"> <div id="Progress" class="ProgressBox"> <img src="Images/ajaxLoader.gif" alt="" width="200px" height="200px" />Working on your Request </div> </div> <div> <table> <tr> <td><b>Categories</b></td> <td><asp:DropDownList runat="server" ID="DDLCategories" Width="250px" DataTextField="CategoryName" DataValueField="CategoryID" onchange="BindProducts(this.id)"> </asp:DropDownList> </td> <td style="width:5px" rowspan="2"> </td> <td><b>Supplier :</b></td> <td><span id="spanSupplier"></span></td> </tr> <tr> <td><b>Products</b></td> <td><asp:DropDownList runat="server" ID="DDLProducts" Width="250px" onchange="ShowProductInfo(this.id)"> <asp:ListItem Text="Select" Value="0"></asp:ListItem> </asp:DropDownList> <asp:HiddenField ID="hndProductId" runat="server" Value="0" /> </td> <td><b>UOM & Price : </b></td> <td><span id="spanUOMPrice"></span></td> </tr> <tr> <td colspan="2" style="text-align:right"> <asp:Button ID="btnProcess" Text="Process" runat="server" Width="100px" onclick="btnProcess_Click" OnClientClick="AssignHiddenValues()" /> </td> </tr> </table> <asp:UpdatePanel ID="updatePanelOrders" runat="server"> <ContentTemplate> <asp:GridView ID="grdViewOrders" runat="server" AllowPaging="true" AutoGenerateColumns="False" TabIndex="1" DataKeyNames="OrderID" Width="100%" GridLines="None" UseAccessibleHeader="true" CellPadding="3" CellSpacing="1" AllowSorting="True" onpageindexchanging="grdViewOrders_PageIndexChanging"> <Columns> <asp:BoundField DataField="OrderID" HeaderText="Order ID" /> <asp:BoundField DataField="CompanyName" HeaderText="Company Name" /> <asp:BoundField DataField="EmployeeName" HeaderText="Employee Name" /> <asp:BoundField DataField="RequiredDate" HeaderText="Required Date" DataFormatString="{0:dd-MMMM-yyyy}" /> </Columns> <RowStyle BackColor="#F7F6F3" ForeColor="#333333" /> <FooterStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" /> <PagerStyle BackColor="#284775" ForeColor="White" HorizontalAlign="Right" /> <SelectedRowStyle BackColor="#E2DED6" Font-Bold="True" ForeColor="#333333" /> <HeaderStyle BackColor="#5D7B9D" Font-Bold="True" ForeColor="White" /> <EditRowStyle BackColor="#999999" /> <AlternatingRowStyle BackColor="White" ForeColor="#284775" /> </asp:GridView> </ContentTemplate> <Triggers> <asp:AsyncPostBackTrigger ControlID="btnProcess" EventName="Click"></asp:AsyncPostBackTrigger> </Triggers> </asp:UpdatePanel> </div>
The code behind - JSONExample.aspx.cs
protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { BindCategoriesDropdown(); } } protected void btnProcess_Click(object sender, EventArgs e) { BindGrid(); } protected void grdViewOrders_PageIndexChanging(object sender, GridViewPageEventArgs e) { grdViewOrders.PageIndex = e.NewPageIndex; BindGrid(); } private void BindGrid() { if (hndProductId.Value.Trim().Length > 0 && Convert.ToInt32(hndProductId.Value) > 0) { using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnection"].ConnectionString)) { SqlDataAdapter dataAdapter = new SqlDataAdapter( "SELECT Orders.OrderID, Customers.CompanyName, Employees.FirstName + ' ' + Employees.LastName [EmployeeName], OrderDate,RequiredDate FROM Orders " + "JOIN [Order Details] OrderDetails On OrderDetails.OrderID = Orders.OrderID " + "JOIN Customers ON Customers.CustomerID = Orders.CustomerID " + "JOIN Employees ON Employees.EmployeeID = Orders.EmployeeID " + "Where OrderDetails.ProductId = " + hndProductId.Value, connection); DataSet ds = new DataSet(); connection.Open(); dataAdapter.Fill(ds); grdViewOrders.DataSource = ds.Tables[0]; grdViewOrders.DataBind(); } } } public void BindCategoriesDropdown() { using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SQLConnection"].ConnectionString)) { SqlCommand command = new SqlCommand("SELECT CategoryID, CategoryName FROM Categories ", connection); connection.Open(); SqlDataReader dr = command.ExecuteReader(CommandBehavior.CloseConnection); IList<Categories> CategoriesList = new List<Categories>(); while (dr.Read()) { Categories categories = new Categories(); categories.CategoryID = Convert.ToInt32(dr["CategoryID"].ToString()); categories.CategoryName = dr["CategoryName"].ToString(); CategoriesList.Add(categories); } DDLCategories.DataSource = CategoriesList; DDLCategories.DataBind(); DDLCategories.Items.Insert(0, new ListItem("Select", "0")); } }
The JavaScript
var is_ie = (navigator.userAgent.indexOf('MSIE') >= 0) ? 1 : 0; var is_ie5 = (navigator.appVersion.indexOf("MSIE 5.5") != -1) ? 1 : 0; var xmlHttp; var vDDLProductsClientID; var vDDLCategoriesClientID; var vhndProductId; function window.onload() { vDDLProductsClientID = '<%= DDLProducts.ClientID %>'; vDDLCategoriesClientID = '<%= DDLCategories.ClientID %>'; vhndProductId = '<%= hndProductId.ClientID %>'; document.getElementById('alpha').style.display = 'none'; // Get the height and Width of the screen var viewportwidth; var viewportheight; if (typeof window.innerWidth != 'undefined') { viewportwidth = window.innerWidth, viewportheight = window.innerHeight } else if (typeof document.documentElement != 'undefined' && typeof document.documentElement.clientWidth != 'undefined' && document.documentElement.clientWidth != 0 ) { viewportwidth = document.documentElement.clientWidth, viewportheight = document.documentElement.clientHeight } else { viewportwidth = document.getElementsByTagName('body')[0].clientWidth, viewportheight = document.getElementsByTagName('body')[0].clientHeight } document.getElementById('alpha').style.height = viewportheight; document.getElementById('alpha').style.width = viewportwidth; document.getElementById('Progress').style.top = ((viewportheight - 200) / 2) + "px"; document.getElementById('Progress').style.left = ((viewportwidth - 400) / 2) + "px"; } /* This function requests the HTTPRequest, will be used to render the Dynamic content html markup * and it will call HandleBindProductResponse to handle the response */ function BindProducts(id) { var url = 'GetAJAXResponse.aspx?CategoryID=' + document.getElementById(id).value + '&CallType=ProductList'; xmlHttp = createAjaxObject(); if (xmlHttp) { xmlHttp.open('get', url, true); xmlHttp.onreadystatechange = HandleBindProductResponse; xmlHttp.send(null); } } /* This function is used to handler the http response * This Function will bind the Products in the dropdown. * When the request is in Server, the dropdown will be Loading... and once client got the response it will bind the items.*/ function HandleBindProductResponse() { // If Response completed if (xmlHttp.readyState == 4) { // Here is the response var strResponse = xmlHttp.responseText; // Parsing the JSON Response // As I generated JSON from Collection, I am getting it back as Array here var ArrCategories = eval("(" + strResponse + ")"); // Getting the Product Dropdown var DDLProducts = document.getElementById(vDDLProductsClientID); while (DDLProducts.childNodes.length > 0) DDLProducts.removeChild(DDLProducts.childNodes[0]); // Removing every list item var option = document.createElement("option"); option.value = "0"; option.innerHTML = "Select"; DDLProducts.appendChild(option); // Looping the array for (var intIndex = 0; intIndex < ArrCategories.length; intIndex++) { var option = document.createElement("option"); option.value = ArrCategories[intIndex]["ProductId"]; option.innerHTML = ArrCategories[intIndex]["ProductName"]; DDLProducts.appendChild(option); } document.getElementById(vDDLCategoriesClientID).disabled = false; xmlHttp.abort(); } else { document.getElementById(vDDLCategoriesClientID).disabled = true; // Getting the Product Dropdown var DDLProducts = document.getElementById(vDDLProductsClientID); while (DDLProducts.childNodes.length > 0) DDLProducts.removeChild(DDLProducts.childNodes[0]); // Removing every list item var option = document.createElement("option"); option.value = "0"; option.innerHTML = "Loading...."; DDLProducts.appendChild(option); } } /* This function requests the HTTPRequest, will be used to render the Dynamic content html markup * and it will call HandleProductInfoResponse to handle the response */ function ShowProductInfo(id) { if (parseInt(document.getElementById(id).value) > 0) { var url = 'GetAJAXResponse.aspx?ProductId=' + document.getElementById(id).value + '&CallType=ProductInfo'; xmlHttp = createAjaxObject(); if (xmlHttp) { xmlHttp.open('get', url, true); xmlHttp.onreadystatechange = HandleProductInfoResponse; xmlHttp.send(null); } } } /* This function is used to handler the http response * The function will fetch the details of selected item and populate in the respective field. * The the request is on the server, there will be a Waiting for your request message in the screen. */ function HandleProductInfoResponse() { // If Response completed if (xmlHttp.readyState == 4) { // Here is the response var strResponse = xmlHttp.responseText; // Parsing the JSON Response // As I generated JSON from object, I am getting it back as object only var ProductInfo = eval("(" + strResponse + ")"); document.getElementById('spanSupplier').innerText = ProductInfo.SupplierName; document.getElementById('spanUOMPrice').innerText = ProductInfo.UnitPrice + ' (' + ProductInfo.QuantityPerUnit + ')'; ShowProgress('Hide'); document.getElementById(vDDLProductsClientID).disabled = false; xmlHttp.abort(); } else { document.getElementById(vDDLProductsClientID).disabled = true; ShowProgress('Show'); } } /* function to create Ajax object */ function createAjaxObject() { var ro; var browser = navigator.appName; if (browser == "Microsoft Internet Explorer") { if (xmlHttp != null) { xmlHttp.abort(); } ro = new ActiveXObject("Microsoft.XMLHTTP"); } else { if (xmlHttp != null) { xmlHttp.abort(); } ro = new XMLHttpRequest(); } return ro; } /* Get the XML Http Object */ function GetXmlHttpObject(handler) { var objXmlHttp = null; if (is_ie) { var strObjName = (is_ie5) ? 'Microsoft.XMLHTTP' : 'Msxml2.XMLHTTP'; try { objXmlHttp = new ActiveXObject(strObjName); objXmlHttp.onreadystatechange = handler; } catch (e) { alert('Object could not be created'); return; } } return objXmlHttp; } function xmlHttp_Get(xmlhttp, url) { xmlhttp.open('GET', url, true); xmlhttp.send(null); } // function to assign Product Value in the Hidden control // Because as the dropdown items are added in Client side, it wont be accessible in code behind. function AssignHiddenValues() { if (parseInt(document.getElementById(vDDLProductsClientID).value) > 0) { document.getElementById(vhndProductId).value = document.getElementById(vDDLProductsClientID).value; return true; } else { alert('Please select Product and Press Process'); return false; } } // Function to show Progress message function ShowProgress(vShowFlag) { if (vShowFlag == 'Show') { // Show the black image on the screen for protecting inputs document.getElementById('alpha').style.display = 'block'; } if (vShowFlag == 'Hide') { // Hide the black image on the screen document.getElementById('alpha').style.display = 'none'; } }
This code has been tested with IE 6.0/9.0, Firefox 3.6, Opera 11.01
[Update 09-Feb-2012:]
As this example uses ASP.NET extension, this example was not given implementation for retaining the state of the controls created in the client side. So I posted another post which talks about how to retain the control state created in the client side when AJAX calls. The url of the post is below
Implementing XML HTTP AJAX with JSON in ASP.NET (Cascading Dropdown, retain the list and selection)
Here is the output of the example.
Page layout once loaded |
When Categories dropdown selected |
When Products dropdown selected |
When Process button pressed |
download the working example of the source code in C# here and in VB here
hi, I'm Cindy. Thanks for your sharing, it help me in bind the data from XMLHttp Ajax + JSON + XML.
But i faced the problem of the button click which trigger the code behind,
post back the page and the data which i bind with XMLHttp Ajax+ JSON + XML.
I'm using VS2010 - vb.
Would you help me go through which part get wrong? Thank for spending time to provide the solution.
Here is my code :
Product.xml
--------------
1
Business Card
2
Greeting/Invitation Card
3
PostCard
CardType.xml
-------------
1
A
Card A
1
B
Card B
1
C
Card C
1
D
Card D
2
A
Card A
2
B
Card B
3
A
Card A
3
B
Card B
3
C
Card C
Sorry, pls ignore the previous post.
I have posted my problem in
http://www.codeproject.com/Questions/326171/Post-Back-problem-cause-the-data-which-bind-with-X
Regards,
Cindy
Hi, Thanks for your comment.
As the Categories drop down box lists are added at the client side (Jquery/Javascript), the list will not retain when the post back happening. But we can retain the UI content created in client side by saving the HTML script in an hidden control before postback happening and restore when gets back.
I was thinking to change this same post to understand more better way with retaining the dropdown box list after postback. I will update this post in a day or two with source code.
Billion thanks to Thiru...
Wish can see your next post of how to retain the dropdown box list after postback.
:)
Regard Cindy.
Hi Cindy, I have published another post for retaining the dropdown box state when post back happend. Please verify the below url
http://www.dotnettwitter.com/2012/02/implementing-xml-http-ajax-with-json-in.html
Let me know if you have any issues.