Reputation: 791
In my current MVC application I perform an AJAX call to the controller. The controller gets an object from the database and returns it in the form of a JSON response. My confusion is between using the Controller.Json method vs JavaScriptSerializer.Serialize(object). My object I am converting is a simple class called PhoneSerializable
with a few public properties of type string
and int
.
I have the following:
var serializedPhone = jsSerializer.Serialize(new PhoneSerializable(phone));
return new ContentResult {Content = serializedPhone, ContentType = "application/json"};
This works correctly and I get a JSON response that my AJAX caller can parse. Yet some online examples I have seen use this instead:
return Json(new PhoneSerializable(phone));
The response of this has mostly null
properties and a DenyGet
header which means it failed parsing or something. The documentation for the Json(object)
method states that it uses the same javascript serializer for the object yet it fails to convert my simple object to JSON.
What am I missing? I would like to use Json(object)
since it is much cleaner but I cannot seem to get it to work.
EDIT WITH ANSWER:
The Json()
method was defaulting to "DenyGet" adding more parameters fixed the issue and it now works:
return Json(new PhoneSerializable(phone),
"application/json",
JsonRequestBehavior.AllowGet);
Upvotes: 2
Views: 3702
Reputation: 149518
Using the Json
method from the Controller
base class simply returns a new object of type JsonResult
, using the following overload:
protected internal JsonResult Json(object data)
{
return this.Json(data, null, null, JsonRequestBehavior.DenyGet);
}
protected internal virtual JsonResult Json(
object data,
string contentType,
Encoding contentEncoding,
JsonRequestBehavior behavior)
{
return new JsonResult
{
Data = data,
ContentType = contentType,
ContentEncoding = contentEncoding,
JsonRequestBehavior = behavior
};
}
After you return Json(new PhoneSerialize(phone));
, the controller eventually invokes a method called ExecuteResult(ControllerContext context)
, which internally does the same serialization with JsonSerializer
:
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet &&
string.Equals(context.HttpContext.Request.HttpMethod,
"GET",
StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException(MvcResources.JsonRequest_GetNotAllowed);
}
HttpResponseBase response = context.HttpContext.Response;
if (!string.IsNullOrEmpty(this.ContentType))
{
response.ContentType = this.ContentType;
}
else
{
response.ContentType = "application/json";
}
if (this.ContentEncoding != null)
{
response.ContentEncoding = this.ContentEncoding;
}
if (this.Data != null)
{
JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
if (this.MaxJsonLength.HasValue)
{
javaScriptSerializer.MaxJsonLength = this.MaxJsonLength.Value;
}
if (this.RecursionLimit.HasValue)
{
javaScriptSerializer.RecursionLimit = this.RecursionLimit.Value;
}
response.Write(javaScriptSerializer.Serialize(this.Data));
}
}
This basically means you're passing both DenyGet
as a default parameter, yet your method is a "GET", which ends up throwing an InvalidOperationException
. You should specify the "AllowGet" explicitly to avoid this:
return Json(new PhoneSerializable(phone),
"application/json",
JsonRequestBehavior.AllowGet);
Upvotes: 2