sandor
sandor

Reputation: 63

Newtonsoft JSON optionally change payload casing WebAPI 2

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?

Upvotes: 1

Views: 1294

Answers (3)

sandor
sandor

Reputation: 63

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);
        }
    }
}

Upvotes: 0

David Peden
David Peden

Reputation: 18444

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.

Upvotes: 1

Moby Disk
Moby Disk

Reputation: 3861

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
}

Upvotes: 0

Related Questions