In .NET 3.5, when a Web service class is decorated with “ScriptService” attribute, the web service returns data in JSON format [MSDN]. I have demonstrated this with a simple example in the article, Passing JSON objects in .NET 3.5.
Let us consider that our “person” class has several properties, of which only few are useful on the client side for data binding. We can filter this object in two ways:
1. On the server side:- Create a dictionary object [System.Collections.Generic.Dictionary(Of TKey, TValue)], add the desired properties to dictionary object and return it.
2. On the client side:- In cases where a quick filter has to be done without touching server side code, we can use jQuery’s each function to create a custom JSON object.
Suppose you want to filter only “country” and “code” out of the below JSON data,
var players =
[{ "country": "India", "code": "Ind", "name": "Sachin" },
{ "country": "Sri Lanka", "code": "SL", "name": "Murali" },
{ "country": "Australia", "code": "Aus", "name": "Shane" },
{ "country": "West Indies", "code": "WI", "name": "Lara"}];
you can simply write the below jQuery code:
var newObject = {}; //Creating a new object
$.each(players, function() { //Looping through our players array using jQuery's each function
newObject[this.country] = this.code; //Creating our custom "name/value" pair
});
So, our newObject will contain new data(having only “country” and “code”). If you want to access country code, you can simply say “newObject.India”, which gives “Ind”.
This tip is particularly useful in cases like filling dropdown lists with JSON data. By default, the server’s JSON data contains several properties which are not required. In such cases, this client side filter comes as a handy tip :)
I was trying to use jqGrid, an excellent jQuery based grid, for building a zero postback page. It's configuration is very simple, similar to flexigrid, but has many additional features like inline editing, subgrids etc.
What jqGrid expects is a JSON response having few objects and arrays, which are mapped to columns in the grid inside the grid.base.js file, like this.
Though the grid's AJAX call is successful, data is not being bound to thegrid. The reason is, .NET 3.5 returns JSON object which is prefixed with a "d" parameter like this.
So, to map the JSON data to the grid, we have to manually parse the AJAX response and separate the "d" parameter in AJAX success callback. This applies not only to jqGrid, but also to all jQuery plugins which expect JSON response.
I was about to write more on why .Net 3.5 prefixes "d" to JSON response, how it enhances security and how to parse it easily., but incidentally, Dave ward explained the concept excellently in his latest article: http://encosia.com/2009/06/29/never-worry-about-asp-net-ajaxs-d-again
So no more worrying about .Net's "d" again :)
In my previous post, I have explained how to pass complex types using jQuery and JayRock in .NET 2.0 framework. I was digging a bit into Dave’s example (using complex types to make calling services less complex) in .NET 3.5 framework, to find how easier JSON serilaization/deserialization can be made.
When a Web service class is decorated with “ScriptService” attribute, which is in the System.Web.Script.Services namespace in .NET 3.5, the web service returns data in JSON format [MSDN]. Whether the returned value is a string or an object, it will be in JSON format. So no need of writing chunks of code for serializing objects explicitly.
Therefore, all that we need to do is to simply decorate our web service class with “ScriptService” attribute and return an object from the server. So, to create a JSON object like this:
{"d":{"FirstName":"Krishna","LastName":"Chaitanya","City":"Hyd","State"
:"Andhra","Country":"India"}}
We can simply return a person object like this:
<WebMethod()> _
Public Function fnFetchDetailsClass() As Person
Dim objPerson As New Person
Try
objPerson.FirstName = "Krishna"
objPerson.LastName = "Chaitanya"
objPerson.City = "Hyd"
objPerson.State = "Andhra"
objPerson.Country = "India"
Catch ex As Exception
End Try
Return objPerson
End Function
In some situations (like in client side templating), we might need to create custom, complex JSON objects on the fly. In such situations, we can make use of .NET’s “ListDictionary” and “ArrayList” classes.
The above example can be re-written using ListDictionary as:
<WebMethod()> _
Public Function fnFetchDetails() As ListDictionary
Dim jsonObj As New ListDictionary
Try
jsonObj.Item("fname") = "Krishna"
jsonObj.Item("lname") = "Chaitanya"
jsonObj.Item("city") = "Hyd"
jsonObj.Item("state") = "Andhra"
jsonObj.Item("country") = "India"
Return jsonObj
Catch ex As Exception
jsonObj.Item("Error") = "Error at server"
Return jsonObj
End Try
End Function
Thus, using JSON is made easier in .NET 3.5.
Here is a simple demo which makes things clear. (I have used jQuery for making AJAX calls.)
(Note: ListDictionary stores values in Name/Value pairs, which is useful in building JSON Object. Similarly, an ArrayList can be used to build JSON Arrays. Therefore, these two can be used instead of JsonObject and JsonArray classes of Jayrock in my post Converting ASP.NET DataTable to JSON using JayRock.)
Scenario: Consider a web form having several fields, whose values are to be submitted to the server through an AJAX call.
This can be easily achieved using jQuery’s $.ajax(), passing all the form elements (like first name, last name, city etc) as parameters to the AJAX call.
However, in reality, most of our web forms contain large number of input fields and hence the $.ajax() method will be overloaded with several parameters both at the client side as well as at the server side. This is cumbersome and is not a good programming practice.
Solution: The best practice in this scenario is to build a Data Transfer Object (DTO) on the client side and pass it to the server. This is what Dave Ward explained in his excellent article - “Using complex types to make calling services less… complex”.
If you are working on NET 3.5 framework, Dave’s article is the solution. In .NET 3.5, the System.Web.Script.Services Namespace can be imported, which makes webservices accessible in JavaScript. Also, it has the ability to accept JSON object from client side code and parse it at the server.
However, in .NET 2.0 framework, JSON object cannot be parsed inherently and hence have to use libraries like JayRock. Here is how you can achieve the same using JayRock. The difference is in the way how you pass your “data” parameter in ajax call.
$('#btnSubmit').click(function() {
//Build JSON object by looping through all text boxes
var objDetails = {};
$('input[type=text]').each(function() {
objDetails[this.name] = this.value;
});
//Stringify the JSON object using the below method from json2.js
var jsObj = JSON.stringify(objDetails);
//jQuery ajax call. Note the data parameter, which is different from normal ajax parameter.
$.ajax({
type: "POST",
url: "CTypesHandler.ashx",
data: "{'id':'1','method':'fnAjaxMethod','params':{'obj':" + jsObj + "}}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: fnSuccess,
error: function(xhr, status, errorThrown) {
alert('Error' + errorThrown);
}
});
function fnSuccess(response) {
var obj = response.result.details;
$('#divMessage').html(obj.FirstName + ' ' + obj.LastName + ' resides at ' + obj.City + ', ' + obj.State + ', ' + obj.Country);
}
});
Here is a simple demo. You can appreciate the demo if you can see how data is being requested and returned, in json format, using firebug. (Few optimizations are yet to be done.)
Thanks to Praveen (my Technical Architect) for helping me with the concept. Thanks to Dave for replying to several of my queries.
Here is a jQuery bug which suck few hours of my time:
- unbind() works only on events attached using jQuery.
- removeAttr() does not work on events added using jQuery
Confusing? Here is the scenario which explains better:
I have a server side asp button(btnTest), for which an “onclick” event is attached on page load (in code behind) like this:
btnTest.Attributes.Add("onclick", "fnTestMethod()")
Without changing server side code, I need to change the functionality of button click (reason: deployment issues). So my initial approach was simple - To unbind the click event from my asp button using jQuery like this:
$('#btnTest').unbind("onclick");
But this
didn’t work!
I was confused! I didn’t understand how page life cycle was impacting DOM. After wasting a couple of hours, I remembered the removeAttr() and tried it:
$('#btnTest').removeAttr("onclick");
and it worked!
On googling, I came to know that this is a bug in jQuery’s tracker and it doesn’t have a fix. You may find a detailed explanation of the bug here.
In short, the explanation says that:
* unbind() works only on events attached using jQuery’s functions like bind(), click() etc. It didn’t work for me as I was binding in my server side code like: btnTest.attributes.add().
* removeAttr() does not work on events added using jQuery.
Hence, if you want to change the click event but not sure if you have added it from code behind or jQuery, write a safer code like this as suggested in the bug tracker:
$("#btnTest").removeAttr("onclick").unbind("click");
Mentioning about the bug here so that readers may not waste their time in similar scenarios. I still love jQuery a lotttt!!! :)
Restructured my site www.novogeek.net. Moved my technical blog from kris.novogeek.net to the root. Created a new subdomain - Labs.NovoGeek.Net for my little experiments. Placed only few important demos as of now. Will slowly move all my silly/stupid code snippets there :)
Update(11th May, 2009): Purchased the domain "NovoGeek.com". It was
parked by someone till recently and I could get it last night :)
Configured Domain Forwarding to novogeek.net. So all existing URL's to novogeek.net will work the same with novogeek.com :)
Update(24th May, 2009): Redirected my .net domain to .com domain. Now my site's actual address is novogeek.com :)
Beginners using jQuery plugins and jQuery AJAX with ASP.NET get stuck with one common problem-converting datatable to JSON. This conversion is necessary since JSON can be easily parsed in JavaScript and also most plugins expect data in JSON format, though that can be altered.
On googling, I found that .Net 3.5 has inbuilt support for this, but learnt from my Tech Arch (Mr.Praveen Reddy) that for .NET 2.0, the simplest solution is to use JayRock. The concept is very simple. Just loop through all rows, all columns of your datatable and add them to JSON arrays, objects.
Download JayRock and add Json.dll to your project’s references and go ahead with the below code (C# lovers may use this utility to convert the below code from VB.NET to C#):
'Import Jayrock.Json namespace, which is defined in json.dll
Imports Jayrock.Json
'Write the below code in your specific events/methods
Dim rowIndex As Integer = 0
Dim jRowArray As New JsonArray
Dim jTable As New JsonObject
If ds.Tables(0).Rows.Count > 0 Then
'Loop through all the rows of datatable.
For Each row As DataRow In ds.Tables(0).Rows
Dim colIndex As Integer = 0
'Create a new JSON array using JayRock
Dim jColArray As New JsonArray
'Create a new JSON object
Dim jRowObj As New JsonObject
'Loop through all the cells of a row
For Each col As DataColumn In ds.Tables(0).Columns
'Add the value of each cell of a row to a JSON Array (jColArray)
jColArray.Add(row.Item(colIndex))
colIndex += 1
Next
'jColArray now contains data from all columns. Add this to a JSON object (jRowObj)
jRowObj("datarow") = jColArray
rowIndex += 1
'Now add this JSON object to another JSON Array (jRowArray).
jRowArray.Add(jRowObj)
Next
End If
jRowArray is the final JSON string, which can now be returned to your JavaScript.
The advantage of using JayRock is, you can customize what JSON data you want to return from the server. E.g., you may require to pass additional data to your JavaScript code such as refresh interval which may not be present in your datatable.
Click here to see the SQL data which will be filled in datatable.
Click here to see the JSON output (in Firebug) of the above data, taken from datatable.
Please share your thoughts. Thanks to Praveen for that! Happy Coding:)
In
ASP.NET, we are used to drag/drop server controls and quickly finish
the task, though we do not concentrate much on how they work. The
problem arises when JavaScript is disabled in the user's browser, as
some of these controls do not work.
Also, if you have rich AJAX features in your site, they will fail
miserably if JavaScript is disabled in the browser. Ideally, your
client expects the site to work even when JS is disabled in the
browser.
Here are some of the ASP.NET server controls which which depend on client script for their functionality:
- The LinkButton and HtmlButton server controls require JavaScript. (However, the Button Web server control, the HtmlInputButton or
HtmlInputImage controls work fine.)
- Any Web server
control whose AutoPostBack property is set to true need client script
so that the control will post the page to the server.
- The
Validation controls require client script to support client-side
validation. If the client does not support script, validation will run
on the server only.
- Gridview pagination, sorting will not work. Custom pagination has to be used
How to detect if JavaScript is enabled in the browser or not? Check this excellent article at Boutell.com.
So, for the site to still work without JavaScript, use
<noscript></noscript> tag, place server side buttons
inside the tags and write your server side code in the button click events. These tags will be visible only when JavaScript is
disabled. So you will not face any issues when JS is enabled.
An irritating scenario: You need a link button to do a server side task, but it doesn't wont work without javascript.
Work around: Apply styles to server side button and make it look like link button :p
Here is the CSS code you have to write (works fine in all major browsers):
.NewLinkButton
{
background-color:Transparent;
border-style: none;
color:Navy;
cursor: pointer;
display:inline-block;
font-style:normal;
text-align: left;
text-decoration:underline;
}
Please check the MSDN article: ASP.NET Web Server Controls that Use Client Script for more valuable info.
I have given a KT (Knowledge Transfer) session on jQuery for my colleagues today. Instead of routine power point stuff, I made a jQuery based web page for presenting the content.
My friend and guru @ office, Mr.Praveen Reddy, guided me and shared really good demos, which are apt for beginners.
Here is the presentation.