I'm pulling my hair out trying to figure out how to make a JSONP call to an ASMX web service using jQuery. These are just some of the pages that I've already read and haven't found any solution:
How to call external webservice using jquery "jsonp"?
Posting cross-domain JSON to ASP.NET with jQuery
Error while accessing ASP.net webservice using JQuery - JSONP
Set Headers with jQuery.ajax and JSONP?
http://www.codeproject.com/Articles/43038/Accessing-Remote-ASP-NET-Web-Services-Using-JSONP
http://encosia.com/using-jquery-to-consume-aspnet-json-web-services/
etc...
Here is my sample .NET web method:
[WebMethod]
[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public void GetEmployee(string employeeId, string callback)
{
// Get the employee object from the Factory.
Employee requestedEmployee = EmployeeFactory.GetEmployee(employeeId);
if(requestedEmployee != null)
{
// Return the padded JSON to the caller.
CrossDomainUtility.SendJsonP(callback, requestedEmployee.ToJson());
}
}
Here is SendJsonP():
public static void SendJsonP(string callback, string json)
{
// Clear any response that has already been prepared.
HttpContext.Current.Response.Clear();
// Set the content type to javascript, since we are technically returning Javascript code.
HttpContext.Current.Response.ContentType = "application/javascript";
// Create a function call by wrapping the JSON with the callback function name.
HttpContext.Current.Response.Write(String.Format("{0}({1})", callback, json));
// Complete this request, to prevent the ASMX web service from doing anything else.
HttpContext.Current.ApplicationInstance.CompleteRequest();
}
And here is some sample jquery code:
$.ajax({
url: 'http://devserver/service/service.asmx/GetEmployee',
dataType: 'jsonp',
contentType: 'application/json',
data: { employeeId: '123456789' }
});
I have the web service decorated with [ScriptService] and I have my web.config configured to handle *.asmx using the ScriptHandlerFactory.
I've tried using the built-in JSON serialization that ASMX uses when Content-Type is 'application/json', but there are a couple problems: it can't work for JSONP due to the padding that's required to be wrapped around the JSON which .NET doesn't support. It also doesn't work because in order to serialize JSON, ASMX expects a 'ContentType: application/json' header, but jQuery ignores ContentType headers when sending GET requests (presumably because it isn't sending any content). I've tried setting Request.ContentType = "application/json" in Global.asax Application_BeginRequest() but that didn't do anything. I've also tried setting the request header in jQuery using beforeSend() with no luck.
So since I couldn't get it to work easily using the built-in .NET pipeline, I rolled-my own technique that performs raw writes to the Response body (hence the SendJsonP() method). I'm still having problems though, because even though the GetEmployee() web method is not returning a value, .NET is throwing serialization errors because it is trying to serialize the object to XML since I can't pass a ContentType of 'application/json' with GET requests.
So, since I can't get jQuery to add the ContentType no matter what I do, I wanted to test my web service by just creating manual requests using Fiddler2:
GET http://devserver/service/service.asmx/GetEmployee?callback=createMember&memberId=123456789
User-Agent: Fiddler
Content-Type: application/json
Host: devserver
... and it gives the following error because my parameters are not JSON:
{"Message":"Invalid JSON primitive: createMember [....] }
So after all that, I'm left with a few questions:
Is there a way to use built-in .NET serialization to apply padding to JSON and return it to the client?
Since it appears that I have to roll my own, how should my query string look when sending a JSONP query with parameters to an ASMX page? It has to be in JSON format but I've tried the following and received "Invalid JSON primitive" errors:
GetEmployee?{callback:"createMember", memberId:"99999999"}
GetEmployee?callback={callback:"createMember"}&memberId={memberId:"123456789"}
Is there any way to have jQuery send a ContentType header with JSONP GET requests?