1

I have camel casing configured as the default JSON output from Newtonsoft library. The following line is called during Application_Start:

config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

All javascript REST calls to the WebAPIs (using WebAPI 2) work fine and return camel cased JSON strings to the client.

Now, I am using jTable control (http://www.jtable.org) on one of my webpages, and this control requires that JSON payloads be returned in Proper Case. So the question is how can I optionally change the WebAPI to return Proper Case JSON payload even though the default configuration through the Application_Start is set to camel case without changing what the global default setting is? I need Proper Case JSON payload returned just for this one WebAPI call within the application.

I've tried [http://fizzylogic.nl/2014/07/30/changing-the-casing-of-json-properties-in-asp-dot-net-web-api/] this, but I was not able to get the ActionFilterAttribute.OnActionExecuting to fire. So the solution did not work.

I also added the following line of code in the WebAPI method

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new JsonContractResolver(new JsonMediaTypeFormatter());

This works, but Proper Case now becomes the default format for other WebAPI calls.

Here's the WebAPI snippet

public JTableDtoImpl Get(int id, int jtStartIndex = 0, int jtPageSize = 0, string jtSorting = "") {
        List<MobileOrderModel> orders = _svc.GetMobileOrders(id);
        var dto = new JTableDtoMobileOrdersImpl(orders, jtStartIndex, jtPageSize) {
            Message = string.Format("DataSource:{0}", _svc.DataSource)
        };
        GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new JsonContractResolver(new JsonMediaTypeFormatter());
        return dto;
}

Problem here is that I now cannot revert back to default camel case formatting since the method has returned by then.

Any other suggestions?

sandor
  • 63
  • 8
  • possible duplicate of [Return camelCased JSON from Web API](http://stackoverflow.com/questions/26474436/return-camelcased-json-from-web-api) – Hamid Pourjam Feb 25 '15 at 21:29
  • If you have three methods, say A, B, and C, is your need to dynamically change the case across any/all methods, or do you only need to run Pascal case for method C always? – David Peden Feb 25 '15 at 21:39
  • I need to run Pascal case for only method C (always). Other methods should continue to use default setting of camel case. – sandor Feb 25 '15 at 21:47
  • You could probably have your method return a string and in the body use `JsonSerializer` directly passing in whatever settings you want/need. That shouldn't effect the global settings for everything else. – Matt Burland Feb 25 '15 at 22:03
  • Correct. Returning a string can be a valid solution, but I am looking for a more elegant solution that I was hoping Newtonsoft.Json could provide. As of now, Request.CreateResponse() approach is the solution I am going with. Thanks. – sandor Feb 26 '15 at 16:30

3 Answers3

1

You can call Request.CreateResponse with the overload that takes a MediaTypeFormatter and pass in the new JsonMediaTypeFormatter() similarly to how you were setting it globally but specifically for this one method. And, of course, you can specify whatever SerializerSettings you want. It would probably be best to keep a private static instance of it in your controller so you're not newing it up every time.

David Peden
  • 17,596
  • 6
  • 52
  • 72
  • David, thank you for the suggestion. I used it and it **works**. I suppose I was too fixated on trying to accomplish this using the Newtonsoft.Json library. I guess I was hoping it had some type of a MediaTypeFormatter override option that could be used to change how JSON payloads are returned depending which WebAPI is being called. – sandor Feb 26 '15 at 16:09
  • If you want to control which serialization settings are used across many API methods in a centralized location, you should look into writing your own `MediaTypeFormatter`. You could then inspect the request and have a map of serializer to route or something along those lines. – David Peden Feb 26 '15 at 16:28
  • Ha. Finally figured out I need to click on the check mark to have this marked as the accepted solution. Thanks again David for all your suggestions. – sandor Feb 26 '15 at 17:25
0

You need to explicitly serialize your JSON, rather than returning an object and letting WebApi serialize it for you. Try something like:

public JSonResult Get(int id, int jtStartIndex = 0, int jtPageSize = 0, string jtSorting = "")
{
   List<MobileOrderModel> orders = _svc.GetMobileOrders(id);
   var dto = new JTableDtoMobileOrdersImpl(orders, jtStartIndex, jtPageSize) {
      Message = string.Format("DataSource:{0}", _svc.DataSource)
   };
   return Json(dto, JsonRequestBehavior.AllowGet); // This serializes explicitly, before WebApi invokes the default serializer
}
Moby Disk
  • 3,761
  • 1
  • 19
  • 38
  • First, thank you for your response. I attempted your solution with the latest version of Newtonsoft.Json (6.0.0.0). I was not able to find "JsonRequestBehavior". Also, the comment [// This serializes explicitly, **before** WebApi invokes the default serializer] confused me a bit. If the Json() serializer is called before the WebAPI serializer, then what's the point? Won't the WebAPI serializer just trump whatever Json() has done? I was not able to compile code and verify. Please see my response below to David Peden's suggestion. – sandor Feb 26 '15 at 15:48
0

Here is my final WebAPI method that works the way I needed. It's too bad I was not able to get this functionality through the Newtonsoft.Json library so the method would be returning the business object and not a response object. I removed code from the class for clarity. (ie: tracing, comments, etc).

public class MobileOrdersController : ApiController {
    private static readonly MobileOrdersService _svc = new MobileOrdersService();
    private static readonly MediaTypeFormatter _properCaseFormatter = new JsonMediaTypeFormatter{
        SerializerSettings = new JsonSerializerSettings {
            ContractResolver = new DefaultContractResolver()
        }
    };

    [Authorize][HttpGet]
    public HttpResponseMessage GetCustomerMobileOrders(int id, int jtStartIndex = 0, int jtPageSize = 0, string jtSorting = "") {
        try {
            List<MobileOrderModel> orders = _svc.GetMobileOrders(id);
            var dto = new JTableDtoMobileOrdersImpl(orders, jtStartIndex, jtPageSize) {
                Message = string.Format("DataSource:{0}", _svc.DataSource)
            };
            return Request.CreateResponse(HttpStatusCode.OK, dto, _properCaseFormatter);
        } catch (Exception ex) {
            return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
        }
    }
}

The following is my solution with OkNegotiatedContentResult<> as recommended by David since I'm using WebAPI 2.

public class MobileOrdersController : ApiController {
    private static readonly MobileOrdersService _svc = new MobileOrdersService();
    private static readonly IContentNegotiator _conneg = GlobalConfiguration.Configuration.Services.GetContentNegotiator();
    private static readonly IEnumerable<JsonMediaTypeFormatter> _mediaTypeFormatters = new[] {
        new JsonMediaTypeFormatter {
            SerializerSettings = new JsonSerializerSettings {
                ContractResolver = new DefaultContractResolver()
            }
        }
    };

    [Authorize][HttpGet]
    public IHttpActionResult GetCustomerMobileOrders(int id, int jtStartIndex = 0, int jtPageSize = 0, string jtSorting = "") {
        try {
            List<MobileOrderModel> orders = _svc.GetMobileOrders(id);
            var dto = new JTableDtoMobileOrdersImpl(orders, jtStartIndex, jtPageSize) {
                Message = string.Format("DataSource:{0}", _svc.DataSource)
            };
            return new OkNegotiatedContentResult<JTableDtoMobileOrdersImpl>(dto, _conneg, Request, _mediaTypeFormatters);
        } catch (Exception ex) {
            return new ExceptionResult(ex, this);
        }
    }
}
sandor
  • 63
  • 8
  • `JsonMediaTypeFormatter` uses Json.Net under the hood. The serialized response is the same, regardless of what the actual return type is on your API method. Not sure why you don't like this solution... – David Peden Feb 26 '15 at 16:30
  • I'd also recommend explicitly setting the serializer settings to maintain the casing that you want so that a.) your intent is declared and b.) if the default were to ever change, your code would not break. – David Peden Feb 26 '15 at 16:32
  • And one more thing, if you're running Web API 2, you can return an `OkNegotiatedContentResult` (see [here](https://msdn.microsoft.com/en-us/library/dn308866(v=vs.118).aspx)) to get a strongly typed response. – David Peden Feb 26 '15 at 16:36
  • Regarding my comment about declaring intent, I would change your formatters variable to this: `private static readonly IEnumerable _mediaTypeFormatters = new[] { new JsonMediaTypeFormatter { SerializerSettings = new JsonSerializerSettings { ContractResolver = new DefaultContractResolver() } } };` – David Peden Feb 27 '15 at 05:24
  • Thank you. I updated the code snippet with your line. And using it in my project. – sandor Feb 27 '15 at 17:21