315

My problem is that I wish to return camelCased (as opposed to the standard PascalCase) JSON data via ActionResults from ASP.NET MVC controller methods, serialized by JSON.NET.

As an example consider the following C# class:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

By default, when returning an instance of this class from an MVC controller as JSON, it'll be serialized in the following fashion:

{
  "FirstName": "Joe",
  "LastName": "Public"
}

I would like it to be serialized (by JSON.NET) as:

{
  "firstName": "Joe",
  "lastName": "Public"
}

How do I do this?

aknuds1
  • 65,625
  • 67
  • 195
  • 317

14 Answers14

489

or, simply put:

JsonConvert.SerializeObject(
    <YOUR OBJECT>, 
    new JsonSerializerSettings 
    { 
        ContractResolver = new CamelCasePropertyNamesContractResolver() 
    });

For instance:

return new ContentResult
{
    ContentType = "application/json",
    Content = JsonConvert.SerializeObject(new { content = result, rows = dto }, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }),
    ContentEncoding = Encoding.UTF8
};
Brian Rogers
  • 125,747
  • 31
  • 299
  • 300
silvio
  • 5,651
  • 2
  • 17
  • 14
  • 2
    This is more complex to use though, since you must configure a ContentResult for each controller method. – aknuds1 Mar 18 '14 at 15:11
  • 2
    Yeah I understand that your answer was a reusable solution, my point is to make it more clear that it is only a parameter on the Serialize method. – silvio Mar 18 '14 at 21:00
  • No, that's missing out on the big picture, which is to return camelCased data from controller methods. – aknuds1 Mar 18 '14 at 21:50
  • 1
    If you're returning JSON from a `Controller` method, you probably should be using an `ApiController`, in which case this answer works great. – Simon Hartcher Jun 01 '15 at 09:15
  • 1
    @SimonHartcher Consider the scope of the question though, not the general case. – aknuds1 Jun 25 '15 at 06:52
  • 1
    The valid content-type for JSON is `application/json`, not `text/plain`. – Fred Dec 01 '16 at 10:20
  • Just configure the defaults in one of your App_Start classes (i.e. `GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver()`). – BrainSlugs83 May 05 '17 at 15:58
  • Does anybody know why this doesn't apply to exceptions? I've got an `ExceptionDTO` that takes an `Exception`, and the DTO itself is getting camel-cased with this strategy, but the Exception's own fields are `ClassName` (instead of the desired `className`), and similar. – Groostav Jun 15 '17 at 22:09
  • 1
    `CamelCasePropertyNamesContractResolver` is in `Newtonsoft.Json.Serialization` namespace. – heuristican Mar 20 '19 at 16:55
106

I found an excellent solution to this problem on Mats Karlsson's blog. The solution is to write a subclass of ActionResult that serializes data via JSON.NET, configuring the latter to follow the camelCase convention:

public class JsonCamelCaseResult : ActionResult
{
    public JsonCamelCaseResult(object data, JsonRequestBehavior jsonRequestBehavior)
    {
        Data = data;
        JsonRequestBehavior = jsonRequestBehavior;
    }

    public Encoding ContentEncoding { get; set; }

    public string ContentType { get; set; }

    public object Data { get; set; }

    public JsonRequestBehavior JsonRequestBehavior { get; set; }

    public override void ExecuteResult(ControllerContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        if (JsonRequestBehavior == JsonRequestBehavior.DenyGet && String.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException("This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.");
        }

        var response = context.HttpContext.Response;

        response.ContentType = !String.IsNullOrEmpty(ContentType) ? ContentType : "application/json";
        if (ContentEncoding != null)
        {
            response.ContentEncoding = ContentEncoding;
        }
        if (Data == null)
            return;

        var jsonSerializerSettings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        };
        response.Write(JsonConvert.SerializeObject(Data, jsonSerializerSettings));
    }
}

Then use this class as follows in your MVC controller method:

public ActionResult GetPerson()
{
    return new JsonCamelCaseResult(new Person { FirstName = "Joe", LastName = "Public" }, JsonRequestBehavior.AllowGet)};
}
aknuds1
  • 65,625
  • 67
  • 195
  • 317
63

For WebAPI, check out this link: http://odetocode.com/blogs/scott/archive/2013/03/25/asp-net-webapi-tip-3-camelcasing-json.aspx

Basically, add this code to your Application_Start:

var formatters = GlobalConfiguration.Configuration.Formatters;
var jsonFormatter = formatters.JsonFormatter;
var settings = jsonFormatter.SerializerSettings;
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
Assaf S.
  • 4,676
  • 2
  • 22
  • 18
  • 4
    Web API and MVC have been merged in ASP.NET 6 – Alex Aug 14 '15 at 15:40
  • 2
    Linking for convenience; this setup plays really nicely with this answer: http://stackoverflow.com/a/26068063/398630 (different question, but I use them together, and this link might save me and others some googling in the future). – BrainSlugs83 May 05 '17 at 16:00
42

I think this is the simple answer you are looking for. It's from Shawn Wildermuth's blog:

// Add MVC services to the services container.
services.AddMvc()
  .AddJsonOptions(opts =>
  {
    opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
  });
Quantium
  • 1,779
  • 1
  • 14
  • 14
  • This is for Asp.Net 5. – Erik Hellström Jan 17 '16 at 12:50
  • 2
    My apologies, guys. I read through this posting too quickly. It is for ASP.NET 5. – Quantium Jan 24 '16 at 11:18
  • 9
    Ironically, I came here looking for an answer to the question you answered here, so while it wasn't the answer to the OP's question, it helped me anyway. Thanks! :) – porcus Mar 14 '16 at 20:25
  • 5
    fyi For ASP.NET Core 1.0 it's camel case by default OOTB – Chris Marisic Jul 07 '16 at 13:24
  • This is the default behavior in ASP.NET Core – Vahid Amiri Jul 15 '16 at 08:10
  • Yup, it's the default now. I just found that out the hard way. – Quantium Jul 20 '16 at 20:34
  • 3
    It turns out this is not (exactly) the default for .NET Core 1.0 after all. This solution affects dynamic properties and those are not affected by default. http://stackoverflow.com/questions/41329279/net-core-json-serialization-of-properties-on-dynamic-expandoobject/41372895#41372895 – Niels Brinch Dec 29 '16 at 03:52
  • It works well for ASP.NET Core and sets the default for JsonResult class used in your controllers. You need to place it into Startup.ConfigureServices() method. – Mike Eshva Jan 19 '18 at 16:41
25

Add Json NamingStrategy property to your class definition.

[JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))]
public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}
Watson Kaunda
  • 439
  • 5
  • 6
13

An alternative to the custom filter is to create an extension method to serialize any object to JSON.

public static class ObjectExtensions
{
    /// <summary>Serializes the object to a JSON string.</summary>
    /// <returns>A JSON string representation of the object.</returns>
    public static string ToJson(this object value)
    {
        var settings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver(),
            Converters = new List<JsonConverter> { new StringEnumConverter() }
        };

        return JsonConvert.SerializeObject(value, settings);
    }
}

Then call it when returning from the controller action.

return Content(person.ToJson(), "application/json");
Stuart Hallows
  • 8,795
  • 5
  • 45
  • 57
12

Simpler is better IMO!

Why don't you do this?

public class CourseController : JsonController
{
    public ActionResult ManageCoursesModel()
    {
        return JsonContent(<somedata>);
    }
}

The simple base class controller

public class JsonController : BaseController
{
    protected ContentResult JsonContent(Object data)
    {
        return new ContentResult
        {
            ContentType = "application/json",
             Content = JsonConvert.SerializeObject(data, new JsonSerializerSettings { 
              ContractResolver = new CamelCasePropertyNamesContractResolver() }),
            ContentEncoding = Encoding.UTF8
        };
    }
}
jwize
  • 4,230
  • 1
  • 33
  • 51
  • 1
    I believe that controller should have nothing to do with serialization. Now we would have to have `N` controllers for `N` serialization options. It's better to use strategy based on requested serialization – Pawel Aug 27 '21 at 16:35
11

You must set the settings in the file 'Startup.cs'

You also have to define it in the default values of JsonConvert, this is if you later want to directly use the library to serialize an object.

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
            .AddJsonOptions(options => {
                options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
                options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            });
        JsonConvert.DefaultSettings = () => new JsonSerializerSettings
        {
            NullValueHandling = NullValueHandling.Ignore,
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        };
    }
Daniel Sánchez
  • 179
  • 2
  • 5
9

Below is an action method that returns a json string (cameCase) by serializing an array of objects.

public string GetSerializedCourseVms()
    {
        var courses = new[]
        {
            new CourseVm{Number = "CREA101", Name = "Care of Magical Creatures", Instructor ="Rubeus Hagrid"},
            new CourseVm{Number = "DARK502", Name = "Defence against dark arts", Instructor ="Severus Snape"},
            new CourseVm{Number = "TRAN201", Name = "Transfiguration", Instructor ="Minerva McGonal"}
        };
        var camelCaseFormatter = new JsonSerializerSettings();
        camelCaseFormatter.ContractResolver = new CamelCasePropertyNamesContractResolver();
        return JsonConvert.SerializeObject(courses, camelCaseFormatter);
    }

Note the JsonSerializerSettings instance passed as the second parameter. That's what makes the camelCase happen.

DanKodi
  • 3,550
  • 27
  • 26
8

In ASP.NET Core MVC.

    public IActionResult Foo()
    {
        var data = GetData();

        var settings = new JsonSerializerSettings 
        { 
            ContractResolver = new CamelCasePropertyNamesContractResolver() 
        });

        return Json(data, settings);
    }
Fred
  • 12,086
  • 7
  • 60
  • 83
6

I did like this :

public static class JsonExtension
{
    public static string ToJson(this object value)
    {
        var settings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver(),
            NullValueHandling = NullValueHandling.Ignore,
            ReferenceLoopHandling = ReferenceLoopHandling.Serialize
        };
        return JsonConvert.SerializeObject(value, settings);
    }
}

this a simple extension method in MVC core , it's going to give the ToJson() ability to every object in your project , In my opinion in a MVC project most of object should have the ability to become json ,off course it depends :)

Ali Alp
  • 691
  • 7
  • 10
  • 2
    Consider extracting the "settings" variable outside the method (as private static field "camelCaseSettings") so that you don't initialize a new variable every time the ToJson method is called. – Ekus Feb 27 '20 at 01:59
0

If you are returning ActionResult in .net core web api, or IHttpAction result then you can just wrap up your model in an Ok() method which will match the case on your front end and serialise it for you. No need to use JsonConvert. :)

LukePerrin
  • 235
  • 5
  • 17
0

Since .net core and following .net5, .net6, .net7, .net8 ASP .NET Core is using System.Text.Json.JsonSerializer instead library from NewtonSoft, so original answers from @aknuds1 and @silvio are not up to date.

To setup property naming convertion:

////In Program.cs or in submodules, while sonfiguring services on startup:
services
  .AddJsonOptions(options =>
  {
    options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
    ////And other options for example for enum:
    //options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
    ////and for DateOnly we can register custom converter:
    //options.JsonSerializerOptions.Converters.Add(new DateOnlyJsonConverter());
  });

////Then in controller:
[HttpGet]
public async Task<IActionResult> FooMethod(CancellationToken cancellationToken)
{
    var data = await GetData(cancellationToken);

    return Ok(data);
}

To convert to Json string manually:

var jsonSerializerOptions = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
};
jsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
////And other settings like:
//jsonSerializerOptions.Converters.Add(new DateOnlyJsonConverter());

var jsonStr = System.Text.Json.JsonSerializer.Serialize(data, jsonSerializerOptions);

Example of custom converter:

//Actual for .net6 if your DTO contains DateOnly field
public class DateOnlyJsonConverter : JsonConverter<DateOnly>
{
    private const string Format = "yyyy-MM-dd";

    public override DateOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var str = reader.GetString();
        return string.IsNullOrEmpty(str)? default : DateOnly.ParseExact(str, Format, CultureInfo.InvariantCulture);
    }

    public override void Write(Utf8JsonWriter writer, DateOnly value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToString(Format, CultureInfo.InvariantCulture));
    }
}
Evgeny
  • 791
  • 7
  • 15
-3

Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson

this solve my problem

Yanshof
  • 9,659
  • 21
  • 95
  • 195