Web API 2: how to return JSON with camelCased property names, on objects and their sub-objects

C#.Netasp.net Web-Apijson.netasp.net Web-Api2

C# Problem Overview


UPDATE

Thanks for all the answers. I am on a new project and it looks like I've finally got to the bottom of this: It looks like the following code was in fact to blame:

public static HttpResponseMessage GetHttpSuccessResponse(object response, HttpStatusCode code = HttpStatusCode.OK)
{
    return new HttpResponseMessage()
    {
        StatusCode = code,
        Content = response != null ? new JsonContent(response) : null
    };
}

elsewhere...

public JsonContent(object obj)
{
    var encoded = JsonConvert.SerializeObject(obj, Newtonsoft.Json.Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore } );
    _value = JObject.Parse(encoded);
    
    Headers.ContentType = new MediaTypeHeaderValue("application/json");
}

I had overlooked the innocuous looking JsonContent assuming it was WebAPI but no.

This is used everywhere... Can I just be the first to say, wtf? Or perhaps that should be "Why are they doing this?"


original question follows

One would have thought this would be a simple config setting, but it's eluded me for too long now.

I have looked at various solutions and answers:

https://gist.github.com/rdingwall/2012642

doesn't seem to apply to latest WebAPI version...

The following doesn't seem to work - property names are still PascalCased.

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;

json.UseDataContractJsonSerializer = true;
json.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;

json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); 

Mayank's answer here: https://stackoverflow.com/questions/23370619/camelcase-json-webapi-sub-objects-nested-objects-child-objects seemed like an unsatisfactory but workable answer until I realised these attributes would have to be added to generated code as we are using linq2sql...

Any way to do this automatically? This 'nasty' has plagued me for a long time now.

C# Solutions


Solution 1 - C#

Putting it all together you get...

protected void Application_Start()
{
    HttpConfiguration config = GlobalConfiguration.Configuration;
    config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    config.Formatters.JsonFormatter.UseDataContractJsonSerializer = false;
}

Solution 2 - C#

This is what worked for me:

internal static class ViewHelpers
{
    public static JsonSerializerSettings CamelCase
    {
        get
        {
            return new JsonSerializerSettings {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            };
        }
    }
}

And then:

[HttpGet]
[Route("api/campaign/list")]
public IHttpActionResult ListExistingCampaigns()
{
    var domainResults = _campaignService.ListExistingCampaigns();
    return Json(domainResults, ViewHelpers.CamelCase);
}

The class CamelCasePropertyNamesContractResolver comes from Newtonsoft.Json.dll in Json.NET library.

Solution 3 - C#

It turns out that

return Json(result);

was the culprit, causing the serialization process to ignore the camelcase setting. And that

return Request.CreateResponse(HttpStatusCode.OK, result, Request.GetConfiguration());

was the droid I was looking for.

Also

json.UseDataContractJsonSerializer = true;

Was putting a spanner in the works and turned out to be NOT the droid I was looking for.

Solution 4 - C#

All the above answers didn't work for me with Owin Hosting and Ninject. Here's what worked for me:

public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        // Get the ninject kernel from our IoC.
        var kernel = IoC.GetKernel();

        var config = new HttpConfiguration();

        // More config settings and OWIN middleware goes here.

        // Configure camel case json results.
        ConfigureCamelCase(config);

        // Use ninject middleware.
        app.UseNinjectMiddleware(() => kernel);

        // Use ninject web api.
        app.UseNinjectWebApi(config);
    }

    /// <summary>
    /// Configure all JSON responses to have camel case property names.
    /// </summary>
    private void ConfigureCamelCase(HttpConfiguration config)
    {
        var jsonFormatter = config.Formatters.JsonFormatter;
        // This next line is not required for it to work, but here for completeness - ignore data contracts.
        jsonFormatter.UseDataContractJsonSerializer = false;
        var settings = jsonFormatter.SerializerSettings;
#if DEBUG
        // Pretty json for developers.
        settings.Formatting = Formatting.Indented;
#else
        settings.Formatting = Formatting.None;
#endif
        settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    }
}

The key difference is: new HttpConfiguration() rather than GlobalConfiguration.Configuration.

Solution 5 - C#

Code of WebApiConfig:

	public static class WebApiConfig
	{
		public static void Register(HttpConfiguration config)
		{
			// Web API configuration and services
	
			// Web API routes
			config.MapHttpAttributeRoutes();
	
			config.Routes.MapHttpRoute(
				name: "DefaultApi",
				routeTemplate: "api/{controller}/{id}",
				defaults: new { id = RouteParameter.Optional }
			);
	
			//This line sets json serializer's ContractResolver to CamelCasePropertyNamesContractResolver, 
			//	so API will return json using camel case
			config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
	
		}
	}


Make sure your API Action Method returns data in following way and you have installed latest version of Json.Net/Newtonsoft.Json Installed:

	[HttpGet]
    public HttpResponseMessage List()
    {
        try
        {
            var result = /*write code to fetch your result - type can be anything*/;
            return Request.CreateResponse(HttpStatusCode.OK, result);
        }
        catch (Exception ex)
        {
            return Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message);
        }
    }

Solution 6 - C#

In your Owin Startup add this line...

 public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var webApiConfiguration = ConfigureWebApi();            
        app.UseWebApi(webApiConfiguration);
    }

    private HttpConfiguration ConfigureWebApi()
    {
        var config = new HttpConfiguration();

        // ADD THIS LINE HERE AND DONE
        config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); 

        config.MapHttpAttributeRoutes();
        return config;
    }
}

Solution 7 - C#

Here's an obscure one, when the route attribute did not match the GET url but the GET url matched the method name, the jsonserializer camel case directive would be ignored e.g.

> http://website/api/geo/geodata

//uppercase fail cakes
[HttpGet]
[Route("countries")]
public async Task<GeoData> GeoData()
{
    return await geoService.GetGeoData();
}

//lowercase nomnomnom cakes
[HttpGet]
[Route("geodata")]
public async Task<GeoData> GeoData()
{
    return await geoService.GetGeoData();
}

Solution 8 - C#

I have solved it following ways.

[AllowAnonymous]
[HttpGet()]
public HttpResponseMessage GetAllItems(int moduleId)
{
    HttpConfiguration config = new HttpConfiguration();
            config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            config.Formatters.JsonFormatter.UseDataContractJsonSerializer = false;

            try
            {
                List<ItemInfo> itemList = GetItemsFromDatabase(moduleId);
                return Request.CreateResponse(HttpStatusCode.OK, itemList, config);
            }
            catch (System.Exception ex)
            {
                return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.Message);
            }
}

Solution 9 - C#

I'm using WebApi with Breeze and I ran the same issue when trying to execute a non-breeze action into a breeze controller. I tried to use the apprach Request.GetConfiguration but the same result. So, when I access the object returned by Request.GetConfiguration I realize that the serializer used by request is the one that breeze-server use to make it's magic. Any way, I resolved my issue creating a different HttpConfiguration:

public static HttpConfiguration BreezeControllerCamelCase
        {
            get
            {
                var config = new HttpConfiguration();
                var jsonSerializerSettings = config.Formatters.JsonFormatter.SerializerSettings;
                jsonSerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                jsonSerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                config.Formatters.JsonFormatter.UseDataContractJsonSerializer = false;

                return config;
            }
        }

and passing it as parameter at Request.CreateResponse as follow:

return this.Request.CreateResponse(HttpStatusCode.OK, result, WebApiHelper.BreezeControllerCamelCase);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTomView Question on Stackoverflow
Solution 1 - C#AronView Answer on Stackoverflow
Solution 2 - C#felix-bView Answer on Stackoverflow
Solution 3 - C#TomView Answer on Stackoverflow
Solution 4 - C#mkajView Answer on Stackoverflow
Solution 5 - C#Jay ShahView Answer on Stackoverflow
Solution 6 - C#smatthews1999View Answer on Stackoverflow
Solution 7 - C#jenson-button-eventView Answer on Stackoverflow
Solution 8 - C#Khademul BasherView Answer on Stackoverflow
Solution 9 - C#Leonardo NeningerView Answer on Stackoverflow