If you’re having trouble with getting jQuery to talk to your ASP.NET web service, I may have some tips to ease your pain.

#1: It’s not JSON!

That’s right, even though your WebMethod consumes and returns JSON, you actually have to send a formatted string instead of a pure JSON object:

JavaScript:

var BadArguments = { FirstName: "John", LastName: "Doe" }; // BAD
var GoodArguments = '{ "FirstName": "John", "LastName": "Doe" }'; // GOOD

This means that the JSON used by ASP.NET web services is not portable. To get around this, I created a little JavaScript function that handles one-dimensional associative arrays and converts them to “MS-JSON.” You may want to adapt this function to your needs since it explicitly doesn’t handle “objects” such as arrays or dates:

JavaScript:

function GenerateAspNetJsonString(MyArray) {
	var StrOut = '{';

	for (var key in MyArray) {
		if ('object' != typeof MyArray[key]) {
			// The type is not an object, so we can write it down as a string:
			StrOut += '"' + key + '":"' + escape(MyArray[key]) + '",'
		}
	}

	// Strip the trailing comma and return:
	return StrOut.substr(0, StrOut.length - 1) + '}';
}

#2: Check your Attributes

Chances have that you already marked your web method with the following code:
VB.NET:

<WebMethod(Description:="Does something.")> _
<ScriptMethod(ResponseFormat:=ResponseFormat.Json)> _
Public Function MyMethod(ByVal Something as String) As String ...

C#:

[WebMethod(Description = "Does something.")]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string MyMethod(string Something) ...

But make sure that you have also marked the Web Service’s class with the ScriptService (short for ScriptServiceAttribute) attribute as well. This is not automatically done by Visual Studio when the code is generated, so you’ll have to do it manually:
VB.NET:

<System.Web.Services.WebService(Namespace:="http://tempuri.org/")> _
<System.Web.Services.WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<ScriptService()> _
Public Class MyWebService
	Inherits System.Web.Services.WebService ...

C#:

[WebService(Namespace = "http://www.tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class MyWebService : System.Web.Services.WebService { ...

#3: When all else fails

Check your XmlHttpRequest’s errors, since ASP.NET actually returns quite a bit of useful information in debug mode. Using jQuery, you can add an error handler to your $.ajax function call:

JavaScript:

$.ajax({
	type: 'POST',
	contentType: 'application/json; charset=utf-8',
	url: '/MyWebService.asmx/MyWebMethod',
	// notice the usage of the function provided in #1:
	data: GenerateAspNetJsonString({
		FirstName: 'John',
		LastName: 'Doe'
	}),
	dataType: 'json',
	error: function (jqXHR, textStatus, errorThrown) {
		// responseText contains all of the interesting
		// bits and pieces:
		alert(jqXHR.responseText);
	},
	success: function (msg) {
		// do something with msg.d, eval() to
		// to retrieve the data.
	}
});

Warnings GaloreMy dearest VB.NET programmers (and C# programmers up to a point), I once again have to inform you of one of my pet peeves. This is pretty much a follow-up to one of my previous posts, but more than two years after, I still work in projects from various online sources as well as professionally that are littered with the warnings about undefined variables:

warning BC42104: Variable 'X' is used before it has been assigned a value. A null reference exception could result at runtime.

At runtime, these warnings usually translate into the dreaded NullReferenceException:
NullReferenceException was unhandled, Object Reference not set to an instance of an object.

So, what causes this and how can can we fix this? Let’s take a look at a piece of code that demonstrates something incredibly common, especially in VB circles:

Dim MyString As String

If ThisAndThat Then
    MyString = "Some Value"
End If

...

SomeFunction(MyString)

If the boolean ThisAndThat evaluates to False, MyString will never be defined, and a NullReferenceException will arise when the SomeFunction function tries to do anything with MyString. Remember that The System.String class does not have a default constructor, so no constructor is implicitly called. MyString is NOT String.Empty, but NULL.

To fix this, all you need is an Else statement in your code and some default value that you’d like to assign to MyString:

Dim MyString As String

If ThisAndThat Then
    MyString = "Some Value"
Else
    MyString = String.Empty
End If

...

SomeFunction(MyString)

in fact, the best way to handle default values is to define the variable upon declaration:

Dim MyString As String = String.Empty

If ThisAndThat Then
    MyString = "Some Value"
End If

...

SomeFunction(MyString)

Or you could even eliminate the If statement entirely by using the IIf function:

Dim MyString As String = IIf(ThisAndThat, "Some Value", String.Empty).ToString()

...

SomeFunction(MyString)

And even though I’m using the class System.String as an example, this should be applicable to any variable of any data type. It’s a good practice and will eliminate many of those pesky runtime errors that can be difficult to trace.

Visual Studio 2010 CTP Released

Maybe this news is a bit old but Visual Studio 2010 CTP was released, you can get it at the following location:

Visual Studio 2010 CTP Site

For you who don’t know, CTP means Community Technology Preview and can almost be regarded as a public beta version.

For C/C++ developers, you can find more info on the next version of Visual C++ 2010 on the Visual C++ Team Blog. I’m glad to see that IntelliSense for VC++ is being improved since in 2008/2005 it’s a quite horrible technology. This version also has support for some C++0x functionality.