I am using jquery to call an ajax wcf method that returns a list of objects as a JSON string. The JSON string looks like this when inspecting it in fiddler2 (in TextView):
I've found a workaround:
The first problem was the circular reference exception on the entity model. To overcome this I use the following code to Detach my entities from the context and then serialize them to strings. I then serialize them on the client using the code below that.
Service
[WebGet(ResponseFormat = WebMessageFormat.Json)]
[OperationContract]
public string[] GetPeople(Guid groupId)
{
using (SchedulerContext context = new SchedulerContext())
{
var people = (from p in context.People
where p.Group_ID == groupId
select p).ToList();
JavaScriptSerializer ser = new JavaScriptSerializer();
string[] result = new string[people.Count];
for (int i = 0; i<people.Count; i++)
{
context.Detach(people[i]);
string json = ser.Serialize(people[i]);
result[i] = json;
}
return result;
}
}
Client
$.ajax(
{
type: "GET",
//dataType: "application/json",
//dataType: "text/plain",
contentType: "json",
data: { groupId: 'ae09a080-5d7c-4e92-9a87-591574b7c4b8' },
//data: { groupId: 'test' },
//data: { groupId: '739526F1-7C58-4E3B-97D8-4870948BFE32' },
url: "WebAPI.svc/GetPeople",
error: function (jqXHR, textStatus, errorThrown) {
alert(jqXHR.resultText);
},
success: function (people) {
//the returned param "people" is of type string[], so each string needs parsed
$(people).each(function (index, value) {
var person = $.parseJSON(value);
//now I can use the Person object
});
}
}
);
Here, "application/json"
is not a valid value for the dataType
property.
I changed it to "json"
in my project and the same problem was solved.
Please check details here (comment #7): http://bugs.jquery.com/ticket/8216
I assume you want to return the value of ser.Serialize(query.ToArray())
to the client (an array). But you're returning it as a string, so WCF will escape that JSON into a string, and what you'll end up is not an array, but a string.
Since you're using anonymous types, which aren't natively supported by WCF, you need to use the JavaScriptSerializer
. So to prevent the double-encoding of the JSON (into the string) you should return the data as a Stream
instead, so that WCF won't touch your data (see sample code below).
One more thing: I see your response has a {"d":...}
wrapper, which suggests that you're using the <enableWebScript/>
/ WebScriptEnablingBehavior
/ WebScriptServiceHostFactory
when defining your service / endpoint. Since you're not using the ASP.NET AJAX library, you don't need that wrapping, so you can use the "simpler" <webHttp/>
/ WebHttpBehavior
/ WebServiceHostFactory
instead, and your response won't be wrapped in that "d" object.
[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
public System.IO.Stream GetPeople(Guid groupId)
{
using (SchedulerContext context = new SchedulerContext())
{
JavaScriptSerializer ser = new JavaScriptSerializer();
var query = from p in context.People
where p.Group_ID == groupId
select new
{
p.ID,
p.Name,
p.Surname
};
string json = ser.Serialize(query.ToArray());
using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json)))
{
WebOperationContext.Current.OutgoingResponse.ContentType = "application/json; charset=utf-8";
return ms;
}
}
With WCF 4.0, you can add an attribute called automaticFormatSelectionEnabled
which allows the service to look at the Accept
header in the HTTP request to determine what format to return. As long as what you are returning is serializable, WCF will handle the correct serialization for you. In your jQuery ajax call, the Accept header is added by including accepts: {json: "application/json"}
.
Try adding the MIME type in your server-side code:
Response.ContentType = "application/json";