Keywords: jQuery | AJAX | ASP.NET | Web Services | JSON Serialization | Cross-Domain Requests
Abstract: This article provides an in-depth analysis of the common "Invalid JSON primitive" error when sending JSON data to ASP.NET ASMX web services via jQuery AJAX. By examining the root causes and comparing incorrect versus correct implementations, it thoroughly explains key technical aspects including client-side data serialization, server-side parameter matching, and CORS cross-domain handling. The article offers complete code examples and best practice recommendations to help developers avoid common pitfalls and achieve stable, reliable AJAX communication.
Problem Background and Error Analysis
In web development, using jQuery AJAX to communicate with ASP.NET ASMX web services is a common scenario. However, many developers encounter the "Invalid JSON primitive" error when sending JSON data. The root cause of this issue lies in the mismatch between data serialization and transmission formats.
From the error case, we can observe that when developers directly pass JavaScript objects to jQuery's data parameter, jQuery defaults to converting them into URL-encoded format. Examining the actual transmitted data in Firebug:
markers%5B0%5D%5Bposition%5D=128.3657142857143&markers%5B0%5D%5BmarkerPosition%5D=7&markers%5B1%5D%5Bposition%5D=235.1944023323615&markers%5B1%5D%5BmarkerPosition%5D=19&markers%5B2%5D%5Bposition%5D=42.5978231292517&markers%5B2%5D%5BmarkerPosition%5D=-3
This URL-encoded format does not match the JSON format expected by the server, causing ASP.NET's JSON deserializer to fail parsing and throw the "Invalid JSON primitive" exception.
Correct Client-Side Implementation
The key to solving this problem is ensuring that the data parameter passed to jQuery is a complete JSON string, not a JavaScript object. This prevents jQuery from performing URL encoding on the data.
First, define the correct data structure:
var markers = [
{ "position": "128.3657142857143", "markerPosition": "7" },
{ "position": "235.1944023323615", "markerPosition": "19" },
{ "position": "42.5978231292517", "markerPosition": "-3" }
];
Then, use the JSON.stringify() method to serialize the data into a JSON string:
$.ajax({
type: "POST",
url: "/webservices/PodcastService.asmx/CreateMarkers",
data: JSON.stringify({ Markers: markers }),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data) {
alert(data);
},
error: function(errMsg) {
alert(errMsg);
}
});
Key points include:
- Using
JSON.stringify()to serialize the entire data object into a JSON string - Parameter name "Markers" must exactly match the server-side method parameter name (case-sensitive)
- Setting correct
contentTypeas "application/json; charset=utf-8" - Using
errorcallback instead offailurefor more detailed error information
Server-Side Implementation
To properly receive and process JSON data, the server side needs to define corresponding data models and method signatures.
First, define the data model class:
public class Marker
{
public decimal position { get; set; }
public int markerPosition { get; set; }
}
Then update the web service method:
[WebMethod]
[ScriptService]
public string CreateMarkers(List<Marker> Markers)
{
return "Received " + Markers.Count + " markers.";
}
Important configuration notes:
- The
[ScriptService]attribute allows the web service to be called by JavaScript clients - Method parameter type exactly matches the data structure sent from the client
- Parameter name "Markers" matches the key name in the client's JSON
- ASP.NET automatically uses
JavaScriptSerializerfor JSON deserialization
Cross-Domain Request Handling
When the client and server are on different domains, CORS (Cross-Origin Resource Sharing) issues need to be addressed. In ASP.NET, cross-domain requests can be supported by adding the following code to Global.asax:
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.End();
}
}
This code handles CORS preflight requests, allowing POST requests from any domain and setting appropriate response headers.
Data Size Limits and Configuration
ASP.NET ASMX services have default limits on JSON data size (approximately 2MB). For scenarios requiring large data transfers, the limit can be adjusted in web.config:
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="10485760"></jsonSerialization>
</webServices>
</scripting>
</system.web.extensions>
This sets the maximum JSON length to 10MB, which can be adjusted according to actual requirements.
Response Data Processing
When processing server responses in success callbacks, note that ASP.NET ASMX services wrap response data in a "d" property:
success: function(data) {
// Correct way to access returned data
var result = data.d;
alert(result);
}
This wrapping mechanism is a characteristic of ASP.NET ASMX services, designed to provide an additional security layer.
Best Practices Summary
Based on the above analysis, here are the best practices for interacting with ASP.NET ASMX services using jQuery AJAX:
- Always use
JSON.stringify()to serialize data into JSON strings - Ensure client parameter names exactly match server-side method parameter names
- Set correct
contentTypeas "application/json; charset=utf-8" - Use strongly typed parameters on the server side to receive data
- Add the
[ScriptService]attribute to web services - Configure appropriate CORS headers when handling cross-domain requests
- Adjust JSON serialization limits based on data volume requirements
- Properly handle the "d" wrapping in response data
Following these practices helps avoid common "Invalid JSON primitive" errors and ensures stable, reliable data interaction between client and server.