ASMX ScriptService mistake – Invalid JSON primitive
AJAX, ASMX Mistakes and Misconceptions, ASP.NET By Dave Ward. Updated June 9, 2010Note: This post is part of a long-running series of posts covering the union of jQuery and ASP.NET: jQuery for the ASP.NET Developer.
Topics in this series range all the way from using jQuery to enhance UpdatePanels to using jQuery up to completely manage rendering and interaction in the browser with ASP.NET only acting as a backend API. If the post you're viewing now is something that interests you, be sure to check out the rest of the posts in this series.
One group of searches that consistently brings traffic here is variations on the error: Invalid JSON primitive. Unfortunately, the post that Google sends that traffic to doesn’t address the issue until somewhere within its 150+ comments.
Today, the topic gets its own post.
If you’ve worked with ASMX ScriptServices or Page Methods without ASP.NET AJAX’s client-side proxy (e.g. using jQuery or pure XMLHttpRequest code), you’ve may have seen this cryptic error yourself. Or, perhaps you’ve just arrived here due to seeing it for the first time.
Either way, you may be surprised to learn that the most common reason for this error is that you’ve lied to ASP.NET during your AJAX request.
It all begins with the Content-Type
HTTP’s Content-Type header is a fundamental aspect of communication between browsers and servers, yet often remains hidden from us in day-to-day development. The Content-Type header allows an HTTP connection to describe the format of its contents, using Internet media types (also known as MIME types). A few common ones that you’ve probably seen before are text/html, image/png, and the more topical application/json.
Without the flexible negotiation process content types provide, your users’ browsers and your version of IIS would have to both be “ASMX Compatible” and “JSON Compatible” in order for ScriptServices to function. What a nightmare that would be! The IE6 difficulties we face today would pale in comparison.
Further, Content-Type negotiation is part of what allows a single URL, such as WebService.asmx, to represent data in more than one format (e.g. XML and JSON in ASMX’s case).
The benefits of Content-Type negotiation are well worth a bit of occasional hassle.
Okay, but why does that matter?
When your browser sends a POST request, the W3C’s recommendation is that it should default to using a Content-Type of application/x-www-form-urlencoded. The HTML 4.01 spec describes that serialization scheme:
This is the default content type. Forms submitted with this content type must be encoded as follows:
- [Omitted for brevity; not relevant to this post.]
- The control names/values are listed in the order they appear in the document. The name is separated from the value by ‘=’ and name/value pairs are separated from each other by ‘&’.
For an example of what that means, consider this simple form:
<form method="post"> <label>First Name</label> <input id="FirstName" value="Dave" name="FirstName" /> <label>Last Name</label> <input id="LastName" value="Ward" name="LastName" /> </form>
When the preceding form is submitted with URL encoded serialization, the request’s POST data will look like this:

That standardized serialization format allows a server-side backend like ASP.NET to decipher a form submission’s contents and give you access to each key/value pair. Regardless of what sort of browser submits a form to the server, the Content-Type facilitates a predictable conversion from POST data to server-side collection.
In other words, the Content-Type corresponds to a serialization scheme.
What does that have to do with JSON Primitives?
Understanding Content-Type negotiation and how it relates to serialization is important due to its role in coaxing JSON out of ASMX ScriptServices. Specifically, the fact that you must set a Content-Type of application/json on the request means you’re instructing ASP.NET to interpret your input parameters as JSON serialized data.
However, the W3C’s mandate of URL encoding by default means that most AJAX libraries default to that serialization scheme. Similarly, AJAX tutorials targeting endpoints other than ASMX ScriptServices (including even ASP.NET MVC examples) will describe sending URL encoded data to the server.
In other words, when you’re working with a client-side object like this:
var Person = { FirstName: 'Dave', LastName: 'Ward' }
The default serialization scheme makes it easy to inadvertently transmit that data to the server as a URL encoded string:
FirstName=Dave&LastName=Ward
Again, remember that a Content-Type of application/json is a requirement when working with ASMX ScriptServices. By setting that Content-Type on the request, you’ve committed to sending JSON serialized parameters, and a URL encoded string is far from valid JSON.
In fact, it’s invalid JSON (primitive?), hence the cryptic error message.
Instead of the URL encoded string above, you must be sure to send a JSON string:
{'FirstName':'Dave','LastName':'Ward'}
Whether you’re using XMLHttpRequest directly or a JavaScript library that abstracts the details, getting your request’s serialization wrong is the root of the invalid JSON primitive error. However, a more specific issue tends to be the leading cause of this happening.
When good JavaScript libraries go bad
The most common source of this error stems from a subtlety of using jQuery’s $.ajax() method to call ASMX ScriptServices. Cobbling together snippets of code from the documentation, platform agnostic tutorials, and even posts here on my site, it’s easy to end up with something like this:
// WRONG! $.ajax({ type: 'POST', contentType: 'application/json', dataType: 'json', url: 'WebService.asmx/Hello', data: { FirstName: "Dave", LastName: "Ward" } });
Notice the JavaScript object literal being supplied to $.ajax()’s data parameter. That appears vaguely correct, but will result in the invalid JSON primitive error.
Why? jQuery serializes $.ajax()’s data parameter using the URL encoded scheme, regardless of what Content-Type is specified. Even though the contentType parameter clearly specifies JSON serialization, this URL encoded string is what jQuery will send to the server:
FirstName=Dave&LastName=Ward
That obviously isn’t valid JSON!
The solution is as simple as two single-quotes:
// RIGHT $.ajax({ type: 'POST', contentType: 'application/json', dataType: 'json', url: 'WebService.asmx/Hello', data: '{ FirstName: "Dave", LastName: "Ward" }' });
Did you spot the difference?
Instead of a JavaScript object literal, the data parameter is a JSON string now. The difference is subtle, but helpful to understand. Since it’s a string, jQuery won’t attempt to perform any further transformation, and the JSON string will be unimpeded as it is passed to the ASMX ScriptService.
It doesn’t have to be this way
The problem is trivial once you’re aware of the underlying issue, but there’s not a great reason I can see why things need to be this way in the first place. Either half of this equation could easily provide a remedy.
jQuery – I believe the most correct solution would be $.ajax() attempting to honor the serialization scheme indicated by its contentType parameter. In the case of application/json, fixing this could be easy as testing for JSON.stringify and using it if available. That would work great, but also avoid adding any complexity/size to jQuery core.
That would leave it our responsibility to reference a copy of json2.js in older browsers, but that convention wouldn’t be much of a burden. We generally do that anyway when the client-side objects get complex.
Microsoft – It’s absolutely correct that the framework throws an error when you lie to it about what you’re sending. However, a bit of leniency could potentially save thousands of hours spent troubleshooting this problem (if my search traffic is any indication of its prevalence).
Is there any reason that the ScriptHandlerFactory can’t intelligently differentiate between between JSON and URL encoded inputs? If the first non-whitespace character of the request isn’t an opening curly brace, why not attempt to deserialize it as URL encoded before throwing an invalid JSON primitive error?
Similar posts
What do you think?
I appreciate all of your comments, but please try to stay on topic. If you have a question unrelated to this post, I recommend posting on the ASP.NET forums or Stack Overflow instead.
If you're replying to another comment, use the threading feature by clicking "Reply to this comment" before submitting your own.



Thanks for the clarification. Can you explain what the difference is between setting jQuery’s dataType to ‘html’ vs ‘text’ when using the .ajax() method?
I’ve used them interchangable and haven’t been able to figure out when it matters to use one over the other. I seem to be able to return html fine either way.
The dataType determines how jQuery will interpret the response.
If your endpoint is returning a JSON object and you want jQuery to deserialize it automatically, you need to specify “json” or use a method for manually deserializing it (like the dataFilter approaches I’ve written about here in the past).
If you are using a dataFilter approach, “json” and “text” are just about interchangeable. The exception there is if you’re using jQuery 1.4+, returning a scalar value, and using the dataFilter deserialization approach. In that case, you should use “text” as the dataType to avoid asking jQuery to deserialize invalid JSON.
Nice article!
I found a similar problem when trying to connect Yahoo Pipes to a WCF JSON service. Even though the Yahoo Pipes Web Service module sends JSON, it incorrectly sets the Content-Type to application/x-www-form-urlencoded. The format of the JSON was also unexpected, so it couldn’t be parsed.
I created ASHX code to clean up the data before sending it to the actual WCF code. You can find my blog article (along with sample code and a pipe) by clicking on my name.
Thank you Dave!
You really explained this very well and helped me out a lot. In my case I was doing an ‘$.ajax POST’ to a generic ASP.NET Handler (ashx), but I wasn’t including the ‘quotes’ as you have described. Although in my case I didn’t receive an error “Invalid JSON primitive”.
Regards,
Anthony.
Thanks !
I have done exactly this and still the the “invalid JSON primitive” error. any other ideas?
Take a look at the request in Firebug and see what data you’re sending in the request. Make sure it’s valid JSON and corresponds to the signature of the method that you’re calling.
Hi Dave,
This article was really helpful, but unfortunately my problem still isn’t solved. Using Fiddler my request header is:
GET /Services/GlobalFilters.asmx/GetTechnologists?{facilityIDs:”25,27″,locationIDs:”",modalityIDs:”8″} HTTP/1.1
My asmx WebMetho header looks like this:
[WebMethod(true)]
[ScriptMethod(UseHttpGet = true)]
public IEnumerable GetTechnologists(string facilityIDs, string locationIDs, string modalityIDs)
Can you tell from that what might be going wrong?
Thanks so much!
I don’t think you can pass parameters to ScriptService methods on the QueryString. If you can POST that request instead, it should work.
Thanks Dave,
I changed it to using a POST and it worked. I wasn’t aware of the limitation of query string parameters for the GET and was hoping to use GET because my situation lends itself more to the idea of a GET rather than POST. But nevertheless it’s working now and I’m done being frustrated about it. :)
Thanks!
I know this is a bit old, but found this post whilst googling the same problem.
I finally managed to resolve it; I think what you need is a query string along the lines of:
GET /Services/GlobalFilters.asmx/GetTechnologists?{facilityIDs:”’25,27′″,locationIDs:”””,modalityIDs:”’8′″} HTTP/1.1
Note that the value inside the double quotes is single quoted. I can’t explain 100% why, but it seems to work for me, at least.
I suspect it’s because .NET is trying to de-serialise the contents of the quotes as a string; so it’s expecting to see ’25,27′ not 25,27.
Great post – You are a great technical writer! Wow – very clear and concise writing. Good Job!
Fanatastic, this is something that could have haunted me for hours but you’ve sorted me out in two minutes! Your explanation is very clear and easy to read and I feel 5% smarter than I was before I got here.
The slightly annoying thing is that I have a previous application using jQuery ajax to interrogate a .NET webservice which was already single-quoting the JSON string and I completely missed that when I was banging my head on the desk screaming, “what’s the difference???”. I must have got there by trial & error or random googling but I didn’t properly understand the issue until now.
Silly jQuery. JSON.stringify() FTW!
Thanks a lot,
Jon.
Dude…you rule.
Thank you very much!
Nice artical thanks a lot. I have been looking for something like that.
This article helped me out a lot. I was wondering why some of my parameter values would go through without the single quote but then other strings that contained arithmetic operators weren’t going through correctly. Thanks.
Hi Dave,
I know that you might be pretty busy.
But can you continue with this series.?
Thanks.
I definitely will. I still have a few more posts in mind for this series.
Dave,
I am new to JQuery and I am finding out very quickly that debugging someone’s code that involves this technology is very difficult. Thanks for the post!
NIce,
I went through this some time ago and this post helped me get a grip on things…
With normal examples set out elsewhere, I won’t get this error since I am aware enough to supply data-value pair into data. But I stumbled when I was trying to get with YUI jsTree. They pass it somehow different leading the above mentioned error. Thanks you.
Thanks! This post saved me a lot of head scratching :)
You *can* use GET and query string parameters with ScriptService. On the server side, it transforms the query string into JSON and so the parameters must be JSON encoded. E.g. /foo.asmx?intParam=1&stringParam=’foo’ — or %22foo%22. An “Invalid JSON primitive” exception is thrown for unquoted strings.
Thanks John,
Your final comment saved me from going mad, I was trying every variation of parameters and thought from previous comments that GET was not allowed even though UseHttpGet=true is there for all to see, I had simply missed enclosing quotes on a given string, for anyone else -
var getparameters = “searchstr=’” + searchtext + “‘&maxresults=” + showmaxresults + “&localservice=” + localcall;
$.ajax({
type: “GET”,
data: getparameters,
url: “http … your.asmx/ABC”,
contentType: “application/json; charset=utf-8″,
dataType: “json”,
… etc
And thanks Dave for original article, great stuff
Thanks a lot, it worked for me. But this is quite different; I was using var parameters = “{ccnum:”+ccnum+”}”; which did not worked; i just replaced double quotes by single and it worked. var parameters = ‘{ccnum:”+ccnum+”}’;
Thank you so much, this error cost me like 6 hours…
you saved my ass!! thank for this most helpful explanation.
Miguel
Great clarification ! Hats off !
This was exactly what I needed, thanks so much!!
Dave,
I think that I understand now, thanks to your post, what’s going on, and I have control over my own data being posted, but is there any way to wrap all data in quotes before sending? I don’t have any control over the many jquery libraries/plugins that I use, and they all seem to send without quotes, causing this Invalid JSON primitive.
I’ve read a number of your posts, including the one where you use ajaxSetup to set defaults for everything, I’m guessing something in there would be able to format the request correctly first.
Yup, this was helpful and I was stuck with same error too.
One more thing I would like to add is –
My webservice had method like AddCustomer(Customer customer).
Assume Customer class has { Name, Address, City } properties, from javascript we need following type of json string.
{“customer”:{“Name”:”A”,”Address”:”123, test drive”,”City”:”Troy”}}
Please note that the parameter-name of the method has to be available in the json string.
From here & a related post elsewhere, I’d expect a wider use of Dave’s ‘simple’ quotes
data: ‘{“Customer”:{“Name”: ”’ + Name + ‘”,”Address”: ” + Address + ‘”,”City”: ”’ + City + ‘”}}’
But I have no way of checking this right now.
Dave,
Thanks for taking the time to explain. It helped me find a simple mistake that was not obvious
I cannot say thank you enough. I had an issue with DataTables (www.datatables.net) and this information is what helped me find my solution which I eventually posted here on their forums:
http://datatables.net/forums/discussion/12601/passing-parameters-to-.ajax-asmx-web-service-using-post#Item_1
You are right on the money, Dave. Thanks.
This solves the problem: JSON.stringify(DTO)
I’m having some trouble with this and wonder if you’ve ever seen it before. I posted a detailed question about the problem here:
http://www.codeproject.com/Messages/4530541/JQuery-JSON-ASP-Net-AJAX-Entity-Framework-trouble.aspx
I’m not sure what is happening here. From what I understand, Kendo is built on JQuery Ajax – at least, I know it still works the same if you do the Ajax yourself and pass in objects to Kendo. So, I’ve gotten a lot of help from your blogs about using it with ASP.NET. If you’re ever in Denver I will be happy to get you a coffee, or bacon, whatever :)
Anyway, this is super interesting – the JQuery Ajax system seems to be taking my string’d JSON object and acting as if it’s a character array, encoding each character as a separate (un-named) parameter. IT’S MADDENING! Do you have any idea what is causing this issue?
I’m not very familiar with the Kendo Grid, but have you tried the “parameter map” approach shown in this demo? http://demos.kendoui.com/web/grid/editing.html
You’d still need to set the POST verb and application/json Content-Type like you currently are, but maybe that approach for stringifying the data would work around what you’re having trouble with there (and you’re right, the behavior you’re seeing does seem pretty bizarre on the surface).
Dave, THANKS! That got part of it to work right. It’s now sending the proper JSON over the wire back to the server. Now I’m having trouble getting it to call my WebMethod properly. I’ll probably eventually figure it out, but if you know anything about this, please let me know…
When the server starts processing the request, it knows that it has a “Person” object, and it rolls up my JSON into a Person object from my Entity Framework definition. But then, it tries to convert that (correct) object into a Dictionary type?! So, I’m getting a 500 back from the server that says “Can’t convert TestWebSite.Person to Dictionary”
And the really funky thing is, if I change my WebMethod parameter to Dictionary (which would work fine if I had to) – it still throws the EXACT same error! I traced it through the .Net Framework code and found that it’s failing in ConvertObjectToTypeInternal and specifically, it seems like that function doesn’t know my Person class exists.
Ever seen that before?