0

When returning data to Telerik.UI.for.AspNet.Core 2021.1.224 Html.Kendo().Grid(), from my RoomController.Read() I must set NumberHandling = JsonNumberHandling.Strict to get the data to display in the Html.Kendo().Grid(). In testing, I have found that JsonNumberHandling.Strict not only changes how JSON numbers are formatted but also the capitalization of properties(test results below). When I set jsonResult.SerializerSettings from within the controller function, it works. How can I set the jsonResult.SerializerSettings globally for all calls to JSON()?

Related: Breaking Change ASP.NET Core apps allow deserializing quoted numbers The recommended solution in the article, is my failed Attempt 1 (below). I can't get it to work.

Setting jsonResult.SerializerSettings in controller Read()

public ActionResult Read([DataSourceRequest] DataSourceRequest request)
{
     IEnumerable<ApplicationIdentityUser> users
          = _applicationDbContext.Users.OrderBy(u => u.UserName);
     DataSourceResult dataSourceResult = users.ToDataSourceResult(request);
     JsonResult jsonResult = Json(dataSourceResult);
     jsonResult.SerializerSettings = new JsonSerializerOptions() 
     { 
          NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.Strict
     };
     return jsonResult;
}

JSON Result

{
    "Data": [{
        "RoomId": 1,
        "RoomCreated": "2018-04-25T15:41:12",
        "RoomCreatedBy": "joe",
        "RoomEnabled": true,
        "RoomName": "1001",
        "RoomUpdated": "2021-01-04T16:57:14.6151292",
        "RoomUpdatedBy": "mary",
        "Units": [],
        "Building": {
            "BuildingId": 29,
            "BuildingCreated": "2018-04-25T15:41:12.5955256",
            "BuildingCreatedBy": "joe",
            "BuildingEnabled": true,
            "BuildingName": "Roberts Hall",
            "BuildingUpdated": "2018-04-25T15:41:12.5955256",
            "BuildingUpdatedBy": "mary",
            "Rooms": []
        }}]
}

Attempt 1: Setting jsonResult.SerializerSettings in startup.cs

services.AddControllersWithViews().AddJsonOptions(options => {
     options.JsonSerializerOptions.NumberHandling = JsonNumberHandling.Strict;});

Attempt 1: JSON Result

{
    "data": [{
        "roomId": 1,
        "roomCreated": "2018-04-25T15:41:12",
        "roomCreatedBy": "Joe",
        "roomEnabled": true,
        "roomName": "1001",
        "roomUpdated": "2021-01-04T16:57:14.6151292",
        "roomUpdatedBy": "mary",
        "units": [],
        "building": {
            "buildingId": 29,
            "buildingCreated": "2018-04-25T15:41:12.5955256",
            "buildingCreatedBy": "joe",
            "buildingEnabled": true,
            "buildingName": "Roberts Hall",
            "buildingUpdated": "2018-04-25T15:41:12.5955256",
            "buildingUpdatedBy": "mary",
            "rooms": []
        }
    }]
}

Attempt 2: Setting jsonResult.SerializerSettings in startup.cs

services.AddControllers().AddJsonOptions( options => {
     options.JsonSerializerOptions.NumberHandling = JsonNumberHandling.Strict;});

Attempt 2: JSON Result

{
    "data": [{
        "roomId": 1,
        "roomCreated": "2018-04-25T15:41:12",
        "roomCreatedBy": "joe",
        "roomEnabled": true,
        "roomName": "1001",
        "roomUpdated": "2021-01-04T16:57:14.6151292",
        "roomUpdatedBy": "mary",
        "units": [],
        "building": {
            "buildingId": 29,
            "buildingCreated": "2018-04-25T15:41:12.5955256",
            "buildingCreatedBy": "joe",
            "buildingEnabled": true,
            "buildingName": "Roberts Hall",
            "buildingUpdated": "2018-04-25T15:41:12.5955256",
            "buildingUpdatedBy": "mary",
            "rooms": []
        }
    }]
}
Jackdaw
  • 7,626
  • 5
  • 15
  • 33
Will
  • 426
  • 3
  • 13
  • There is no universal global default for `JsonSerializerOptions`, see [Api proposal: Change JsonSerializerOptions default settings #31094](https://github.com/dotnet/runtime/issues/31094). Individual frameworks may have modifiable defaults though. – dbc Mar 15 '21 at 17:15
  • Also, the web default was changed to `JsonNumberHandling.AllowReadingFromString`. That shouldn't affect **serialization** in any way, so I'm surprised that the breaking change affected the JSON returned by your `JsonResult`. Can you share a [mcve] showing the JSON returned and explaining why it's wrong? – dbc Mar 15 '21 at 17:28
  • All that being said, the reason ***Setting jsonResult.SerializerSettings in controller Read()*** switches to pascal case is that, when you set `JsonResult.SerializerSettings`, that apparently *completely supersedes* the framework's options, rather than just superseding individual option values that were actually set. To confirm see e.g. [`SystemTextJsonResultExecutor.GetSerializerOptions(JsonResult result)`](https://github.com/dotnet/aspnetcore/blob/c925f99cddac0df90ed0bc4a07ecda6b054a0b02/src/Mvc/Mvc.Core/src/Infrastructure/SystemTextJsonResultExecutor.cs#L122)... – dbc Mar 15 '21 at 17:33
  • ... which means that the [`PropertyNamingPolicy`](https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.propertynamingpolicy?view=net-5.0) got reset from `JsonNamingPolicy.CamelCase` to `null`, thereby causing your serialization results to be pascal-cased. If you set your naming policy to `JsonNamingPolicy.CamelCase` you will get your camel casing back. I'm not sure that really answers your question though because I'm not sure what problem is being caused by `JsonNumberHandling.AllowReadingFromString`. – dbc Mar 15 '21 at 17:36
  • The easiest way to go about making the serializers all have the same setup would be to use a serializer factory pattern to create your instances of the serializer instead of "newing" them up directly. – Bradley Uffner Mar 15 '21 at 18:11
  • Thank you all for your responses. dbc I understand that setting JsonResult.SerializerSettings supercedes the framework options. That seems to be good in my case because the framework options seem to break the Telerik control. Now I just need that be set in a global way. In the cited article, "ASP.NET Core apps allow deserializing quoted numbers", the recommended action is "services.AddControllers().AddJsonOptions(options => options.JsonSerializerOptions.NumberHandling = JsonNumberHandling.Strict);". Why won't this solution provide the global solution I am looking for? – Will Mar 15 '21 at 18:29

1 Answers1

0

By setting NumberHandling and PropertyNamingPolicy in startup.cs, the JSON generated was able to be consumed by the Telerik controls in a global way.

services.AddControllers().AddJsonOptions(options => 
{ 
     options.JsonSerializerOptions.NumberHandling = JsonNumberHandling.Strict;      
     options.JsonSerializerOptions.PropertyNamingPolicy = null; 
}); 
Will
  • 426
  • 3
  • 13