Force lowercase property names from Json() in ASP.NET MVC
Changing serializer is simple if you are using Web API, but unfortunately MVC itself uses JavaScriptSerializer
with no option to change this to use JSON.Net.
James' answer and Daniel's answer give you the flexibility of JSON.Net but means that everywhere where you would normally do return Json(obj)
you have to change to return new JsonNetResult(obj)
or similar which if you have a big project could prove a problem, and also isn't very flexible if you change your mind on the serializer you want to use.
I've decided to go down the ActionFilter
route. The below code allows you to take any action using JsonResult
and simply apply an attribute to it to use JSON.Net (with lower case properties):
[JsonNetFilter]
[HttpPost]
public ActionResult SomeJson()
{
return Json(new { Hello = "world" });
}
// outputs: { "hello": "world" }
You can even set this up to automagically apply to all actions (with only the minor performance hit of an is
check):
FilterConfig.cs
// ...
filters.Add(new JsonNetFilterAttribute());
The code
public class JsonNetFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Result is JsonResult == false)
return;
filterContext.Result = new CustomJsonResult((JsonResult)filterContext.Result);
}
private class CustomJsonResult : JsonResult
{
public CustomJsonResult(JsonResult jsonResult)
{
this.ContentEncoding = jsonResult.ContentEncoding;
this.ContentType = jsonResult.ContentType;
this.Data = jsonResult.Data;
this.JsonRequestBehavior = jsonResult.JsonRequestBehavior;
this.MaxJsonLength = jsonResult.MaxJsonLength;
this.RecursionLimit = jsonResult.RecursionLimit;
}
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("GET not allowed! Change JsonRequestBehavior to AllowGet.");
var response = context.HttpContext.Response;
response.ContentType = String.IsNullOrEmpty(this.ContentType) ? "application/json" : this.ContentType;
if (this.ContentEncoding != null)
response.ContentEncoding = this.ContentEncoding;
if (this.Data != null)
{
var json = JsonConvert.SerializeObject(
this.Data,
new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
response.Write(json);
}
}
}
}
The way to achieve this is to implement a custom JsonResult
like here:
Creating a custom ValueType and Serialising with a custom JsonResult (original link dead).
And use an alternative serialiser such as JSON.NET, which supports this sort of behaviour, e.g.:
Product product = new Product
{
ExpiryDate = new DateTime(2010, 12, 20, 18, 1, 0, DateTimeKind.Utc),
Name = "Widget",
Price = 9.99m,
Sizes = new[] {"Small", "Medium", "Large"}
};
string json =
JsonConvert.SerializeObject(
product,
Formatting.Indented,
new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
}
);
Results in
{
"name": "Widget",
"expiryDate": "\/Date(1292868060000)\/",
"price": 9.99,
"sizes": [
"Small",
"Medium",
"Large"
]
}