DennyDotNet

Awesome ASP.NET C# and other cool coding stuff

About the author

Denny Ferrassoli
Developer at Casting Networks. MCP / .NET
E-mail me Send mail
Add to Technorati Favorites

Recent posts

Recent comments

Authors

Categories

None


Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010

jQuery returns only 1 element even though there are many

I was so frustrated by this issue today. I simply could not figure out why jQuery would return only 1 element for $("a") when I clearly had multiple anchor tags!

No matter what I did the length would always return 1.

I nearly missed the answer to the issue in a StackOverflow post. But it helped me find that jquery.validator was causing the issue. After going to the plug-in's website and downloading the latest version all was back to normal.

It's just unfortunate when you KNOW something is supposed to work right and you waste an hour trying to figure out why :(

Hopefully this post will help anyone with the same problem in the future and help them avoid any wasted time.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by Denny on Monday, September 07, 2009 6:25 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Passing a JSON object to a WCF service with jQuery

[Updated: 04/25/08] 

This example uses WCF to create a service endpoint that will be accessible via an ASP.NET page with jQuery/AJAX. We will use AJAX to pass a JSON object from the client-side to the webservice. We will only use jQuery to connect to the web service, there will be no ASP.NET AJAX library used. Why no ASP.NET AJAX library? jQuery is already included in the project and it can handle all the necessary AJAX calls and functionality that we would want if we were using the ASP.NET AJAX script library. We're also going to save  about 80kb of overhead (much more if in debug mode) by excluding the ASP.NET AJAX library. This is in no way saying that the ASP.NET AJAX library isn't useful... As a matter of fact if we were to do the same example with the library we could save ourselves from writing extra code. However the point of this example is to show that we can access the web service even if we don't have a nicely generated client-side proxy a la ASP.NET AJAX.

The WCF Service:

I'm going to start by adding an AJAX-enabled WCF Service to a Website. (Make sure you're running the correct version of .NET - I am using 3.5 here)

After adding the service it opens up to the service's code-behind file. Go ahead and browse around the file for a second.

The first thing I'm going to point out is to make sure that the "AspNetCompatibilityRequirements" is set to "Allowed":


[AspNetCompatibilityRequirements( RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed )]

This attribute indicates that our service should run in ASP.NET compatibility mode. If it were not "Allowed" we would not be able to access the service from ASP.NET. This attribute is automatically generated when you add the "AJAX-enabled WCF Service." For a detailed explanation of the attribute go to MSDN.

Looking at the generated code-behind file we can see it has placed a "DoWork()" method with the "OperationContract" attribute. This is created by default but lets keep it since we will be using this method to run this example. One thing we want to add is a "WebGet" attribute and set the "RequestFormat" to "Json." WebGet associates the operation with a UriTemplate (not discussed in this example) as well as the GET verb. Setting the RequestFormat allows us to define that the Request should be in JSON format. For the sake of this example I will be using the GET method to post data to the web service, however it is recommended to use POST for data like this. Our "DoWork()" method should now look like this:


[OperationContract]
[WebGet( RequestFormat=WebMessageFormat.Json )]
public void DoWork()
{
 // Add your operation implementation here
 return;
}



The Data/Object Structure:

We want to pass in a "Person" object to the "DoWork()" method so lets quickly create a Person object with properties for a Name, Age and the types of Shoes they own (first thing that popped into my head). This class will also serve as the structure for our JSON object.


[Serializable]
[DataContract( Namespace = "http://www.dennydotnet.com/", Name = "Person" )]
public class Person
{
 private string _name = string.Empty;
 private int _age = 0;

 [DataMember( IsRequired = true, Name = "Name" )]
 public string Name
 {
  get { return _name; }
  set { _name = value; }
 }

 [DataMember( IsRequired = true, Name = "Age" )]
 public int Age
 {
  get { return _age; }
  set { _age = value; }
 }

 [DataMember( IsRequired = true, Name = "Shoes" )]
 public List<String> Shoes;

}

We've decorated our Person class as a DataContract specifying the Namespace and Name. We've also decorated our properties with a DataMember attribute. We've set "IsRequired" for each one to true and specified the Name. You really only need to specify the "Name" if it's going to be different than the property name. For example you could have a property named "Level" and the DataMember attribute's Name set to "Rank." We can now go back and modify our "DoWork()" method to receive a Person object as a param. It should now look like the following:


[OperationContract]
[WebGet( RequestFormat=WebMessageFormat.Json )]
public void DoWork(Person p)
{
 // Add your operation implementation here
 return;
}

The Web.Config File:

You'll need to make a few changes to your web.config file before you can access your service. You'll need to add a serviceBehavior to allow httpGet and we'll also add some helpful debugging options too. Add the following to your web.config:

Below </endpointBehaviors>


<serviceBehaviors>
 <behavior name="ServiceAspNetAjaxBehavior">
  <serviceMetadata httpGetEnabled="true" httpGetUrl="" />
  <serviceDebug httpHelpPageEnabled="true" includeExceptionDetailInFaults="true" />
 </behavior>
</serviceBehaviors>


Between <services>[here]</services> your service node should look like this:

<service name="Service" behaviorConfiguration="ServiceAspNetAjaxBehavior">
 <endpoint address="" behaviorConfiguration="ServiceAspNetAjaxBehavior"
  binding="webHttpBinding" contract="Service" />
 <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>

A security note about the following line:


<serviceDebug httpHelpPageEnabled="true" includeExceptionDetailInFaults="true" />


Allowing exception details can expose internal application information including personally identifiable or otherwise sensitive information. Setting the option to true is only recommended as a way to temporarily debug your service!!

Your Web.Config should look like the following: (pardon the colors)

The Front-End:

Now that the service is created and configured we can move to the front-end (make sure jQuery.js is included in your ASP.NET page). First let's create a sample JSON object that we will pass to the service. We'll create the JSON object based on the structure of the Person class.


var mydata = { "Name":"Denny", "Age":23, "Shoes":["Nike","Osiris","Etnies"] };


If you're not too familiar with JSON this is what our JSON object looks like as an object (JsonViewer):

We need to somehow communicate with the WCF service and since we're using jQuery we can use the library's built-in AJAX methods. The code below creates an AJAX call. the headers are set to GET and the contentType is application/json. We set the url to the path to our WCF service's svc file with a trailing / and then the name of the method we want to execute. In this case we're calling the "DoWork()" method. "data" will be passed in to our function and processData should be set to false so that jquery does not try to auto-process our data. We've also added a success and error function to let us know what happens after executing the AJAX.

Once again, for the sake of this example I am using the GET method to post data to the web service, however it is recommended to use POST.


function sendAJAX(data) {
 $.ajax({
  type: "GET",
  contentType: "application/json",
  url: "Service.svc/DoWork",
  data: data,
  processData: false,
  success:
   function(msg){
     alert( "Data Saved!" );
   },
  error:
   function(XMLHttpRequest, textStatus, errorThrown){
       alert( "Error Occured!" );
   }
 });
}

Now unfortunately there is a small issue here. We must send the actual JSON string as the value for DoWork's Person p param and there's no easy way of turning your JSON object into a string. If you try "data.toString()" you'll just get an "[object Object]" value (remind you of anything?), which is not what we want. So here's a slightly modified function that will take your JSON and turn it into a string.

Note* The JSON de/serialization handles Date/Time in a specific way. The json2string function below does not take this into account. I'm sure there are some implementations out there which will work with ASP.NET AJAX but this one does not. For more information on this you can go here.

Update [4/11/08]: The javascript below has a few issues so it's been suggested that you should use the JSON.org version to "stringify" your object. You can download the script from here.

Update [4/25/08]: Rick Strahl has modified the JSON.org script so that it will properly create the dates to work with ASP.NET AJAX (read his post)


function json2string(strObject) {
 var c, i, l, s = '', v, p;

 switch (typeof strObject) {
 case 'object':
  if (strObject) {
   if (strObject.length && typeof strObject.length == 'number') {
    for (i = 0; i < strObject.length; ++i) {
     v = json2string(strObject[i]);
     if (s) {
      s += ',';
     }
     s += v;
    }
    return '[' + s + ']';
   } else if (typeof strObject.toString != 'undefined') {
    for (i in strObject) {
     v = strObject[i];
     if (typeof v != 'undefined' && typeof v != 'function') {
      v = json2string(v);
      if (s) {
       s += ',';
      }
      s += json2string(i) + ':' + v;
     }
    }
    return '{' + s + '}';
   }
  }
  return 'null';
 case 'number':
  return isFinite(strObject) ? String(strObject) : 'null';
 case 'string':
  l = strObject.length;
  s = '"';
  for (i = 0; i < l; i += 1) {
   c = strObject.charAt(i);
   if (c >= ' ') {
    if (c == '\\' || c == '"') {
     s += '\\';
    }
    s += c;
   } else {
    switch (c) {
     case '\b':
      s += '\\b';
      break;
     case '\f':
      s += '\\f';
      break;
     case '\n':
      s += '\\n';
      break;
     case '\r':
      s += '\\r';
      break;
     case '\t':
      s += '\\t';
      break;
     default:
      c = c.charCodeAt();
      s += '\\u00' + Math.floor(c / 16).toString(16) +
       (c % 16).toString(16);
    }
   }
  }
  return s + '"
';
 case '
boolean':
  return String(strObject);
 default:
  return '
null';
 }
}

Now that we have a function to turn our JSON object into a string we need to go back and update the "mydata" variable that we defined above. After applying the json2string function we should have the following: 


var mydata = { "Name":"Denny", "Age":23, "Shoes":["Nike","Osiris","Etnies"] };
var jsonStr = "p=" + json2string(mydata);

Notice that I prepended the "p=" string to our json string. "p" matches the parameter name in our "DoWork()" method. So if our parameter name was "Dude" ( i.e. DoWork(Person Dude) ) then we would use "Dude=" instead.

Now that we've built the querystring to the web service we can see what our call is going to look like (if using GET method):

http://www.dennydotnet.com/Service.svc/DoWork/?p={ "Name":"Denny", "Age":23, "Shoes":["Nike","Osiris","Etnies"] }

You may get a URL Encoded value too, which would look like:

http://www.dennydotnet.com/Service.svc/DoWork/?p=%7b+%22Name%22%3a%22Denny%22%2c+%22Age%22%3a23%2c+%22Shoes%22%3a%5b%22Nike%22%2c%22Osiris%22%2c%22Etnies%22%5d+%7d%3b

Go ahead and link "jsonStr" to the "SendAjax()" javascript method so we can debug our service and verify that the data was passed through to the service... check it out:

And now you just need to implement your logic in the DoWork() method. Notice how you don't have to do any de/serialization on the WCF service side either, it's already done for you. Now you should certainly implement some exception management so that you don't get any invalid data, or even add some authentication, but I'll leave that up to you...

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Tags: , , ,
Posted by Denny on Monday, March 03, 2008 9:40 AM
Permalink | Comments (11) | Post RSSRSS comment feed

ScreenCast: MVC, jQuery and REST

So I recently picked up a copy of Camtasia Studio (www.techsmith.com) and wanted to give it a shot by creating my first screen cast.

This screen cast is going to show you how to create an MVC application that uses jQuery (http://www.jquery.com/) to do some AJAX calls against a REST url. You should be familiar with jQuery and the MVC framework but I tried to keep it as simple as possible. The screen cast runs for about 25 minutes - Click the image below to start watching.

Comments, questions and suggestions are welcome...

You can download the sample project here: MVCjQueryREST.zip (41.41 kb)

kick it on DotNetKicks.com

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Tags: ,
Posted by Denny on Sunday, December 16, 2007 3:41 PM
Permalink | Comments (9) | Post RSSRSS comment feed

Animating ASP.NET AJAX Update Panel Updates

Do you dislike the way that ASP.NET AJAX Update Panels update (or replace the content within the update panel)? Is it not flashy and Web 2.0 enough for you? Well fear no more! I've devised a straight-forward script to help you animate your update panel updates. This script uses jQuery (www.jquery.com) to animate the content when an update panel updates. It can easily be modified to use another library such as Scriptaculous. It uses javaScript to override ASP.NET AJAX's _updatePanel method within the PageRequestManager (the method which does the actual replacing of the content).

I've commented the script so you can understand what it's doing:


$(document).ready(
  function() {
      // SAVE the original _updatePanel function for later use.
      var old_prm_updatePanel = Sys.WebForms.PageRequestManager.getInstance()._updatePanel; 

      // Overwrite the original method with our code which will apply animation.
      // (Note: The method signature remains the same)
      Sys.WebForms.PageRequestManager.getInstance()._updatePanel = 
          function(updatePanelElement, rendering) {
              // Using jQuery to hide (animate) the element. Then use the callback function 
              // to load and show the new data. You don't want to update the
              // data beforehand otherwise you'll see your update panel flicker.
              $(updatePanelElement).hide('slow',
                  function() {
                      // Pass the old function and the args
                      loadShowUpdatePanel(old_prm_updatePanel, updatePanelElement, rendering);
                  });
          }
   });
 
function loadShowUpdatePanel(old_prm_updatePanel, updatePanelElement, rendering) {
    // Call the original (old) function with context of Page Request Manager instance.
    // We call the original method so ASP.NET AJAX can do all the necessary actions.
    old_prm_updatePanel.apply(Sys.WebForms.PageRequestManager.getInstance(),
                                                               new Array(updatePanelElement, rendering));

    // using jQuery again to show (animate) the update panel.
    $(updatePanelElement).show('slow');
}

And that's all you need. This script isn't just limited to animating the update panel update either... You can extend this script to do anything you want immediately before and after the new content is displayed. The main difference between this method and using the add_BeginRequest or add_EndRequest methods is the timing. This script will fire exactly before and after the update takes place - This would not be a good place to show a loading screen because the AJAX call has already been made, there's nothing to wait for. Whereas the BeginRequest executes before the AJAX call and EndRequest fires after the update has completed - This would be good to apply a loading screen.

kick it on DotNetKicks.com

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by Denny on Thursday, November 08, 2007 6:08 PM
Permalink | Comments (3) | Post RSSRSS comment feed

TypeWatch: jQuery Plugin

Earlier this week I created a jQuery plug-in that allows you to potentially determine when a user has finished typing in a textbox. I created it for a search textbox on one of my websites so that I could return results by firing some AJAX after they're done typing. It could help with an AJAX auto-complete implementation too.

[UPDATED 05/16/08]

There are 4 settings you can set:

1. callback: The function to callback after the user has "finished" typing. Default void.
2. wait: The number of milliseconds to wait before the plugin considers that typing has finished. Default 750.
3. highlight: Aesthetics, determines if the text should be highlighted when the textbox receives focus. Default true.
4. captureLength: The minimum amount of characters necessary before allowing the event to fire. Default 2.

How it works:

For each textbox or textarea matched through jQuery it creates a timer which gets reset upon every [KeyDown] event. If the timer's [wait] is reached then the user has finished typing, or stopped typing long enough for the timer to reach its [wait] interval.

The callback will not execute if the length of text is less than captureLength. Also, if the timer's [wait] interval is reached and the text has not changed it will not execute the callback. So if you change "some text" to "SOME TEXT" the callback will not execute. The callback will be executed when the ENTER key is pressed on single-line INPUT elements.

You can get the debug and packed version at: http://jquery.com/plugins/project/TypeWatch

The latest version 2.0.0 is a complete refactor of code and includes a few issue fixes. Code has been refactored thanks to Charles Christolini - BinaryPie.com

DEMO:

Click here for the Live Demo

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by Denny on Friday, August 17, 2007 5:23 AM
Permalink | Comments (115) | Post RSSRSS comment feed