Reputation:
I've seen this other question with no answer.
I need to deserialize with newtonsoft because I have circular references loop handling when sending the data to the client:
services.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
options.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
});
This produces JSON objects with $id
and $ref
that are making the model binder fail on POST requests when the modified data comes back.
Note that I have a pretty complex object model as you can se below:
{
"$id": "1",
"vehiculeId": 359586015016459,
"companyId": 1,
"phoneNumber": "0614407055",
"hardwareId": 866857042994208,
"gpsBoxType": 29,
"name": "Redmi Note 6 Pro Olivier M",
"iconId": 33554432,
"gpsBoxTrackingDelay": 1,
"rowEnabled": true,
"dbInsertTime": 1549527854940,
"device": {
"$id": "2",
"imei": 866857042994208,
"brand": "Xiaomi",
"model": "Redmi Note 6 Pro",
"name": "Redmi Olivier",
"registration": {
"$id": "3",
"imei": 866857042994208,
"companyId": 1,
"latestRegistrationStatusChangeDate": 1556168520000,
"registrationStatus": 3,
"imeiNavigation": {
"$ref": "2"
}
}
},
"vehiculeGpsBoxInfo": {
"$id": "4",
"vehiculeId": 359586015016459,
"currentDelay": 0,
"normalTrackingMode": 2,
"timeModeDelay": 60000,
"smartModeDelay": 5000,
"smartModeDistance": 100,
"connected": false,
"heartBeatPeriod": 1200,
"insureCoherence": false,
"killHedgehog": true,
"lastCommunicationTime": 1563519489853,
"vehiculeConfiguration": 111,
"updateStatus": 0,
"vehicule": {
"$ref": "1"
},
"vehiculeConfigurationNavigation": {
"$id": "5",
"configurationId": 111,
"configName": "PTIMobileTest",
"masterName": "PTIMobileTest",
"master": "1.0.32",
"firmware": "",
"system": "",
"gpsBoxType": 29,
"vehiculeGpsBoxInfoBoardConfigurationNavigation": [],
"vehiculeGpsBoxInfoVehiculeConfigurationNavigation": [
{
"$ref": "4"
}
]
}
},
"fleetDetail": [
{
"$id": "6",
"fleetDetailId": 27494,
"fleetId": 3216,
"vehiculeId": 359586015016459,
"rowEnabled": true,
"fleet": {
"$id": "7",
"fleetId": 3216,
"companyId": 1,
"name": "RTEProtect",
"rowEnabled": true,
"fleetDetailFleet": [
{
"$id": "8",
"fleetDetailId": 25988,
"fleetId": 3216,
"vehiculeId": 359586014995819,
"rowEnabled": true,
"fleet": {
"$ref": "7"
},
"vehicule": {
"$id": "9",
"vehiculeId": 359586014995819,
"companyId": 1,
"phoneNumber": " ",
"hardwareId": 358240051111110,
"gpsBoxType": 29,
"category": "PTI",
"name": "PTI Emulateur Fred",
"iconId": 33571442,
"gpsBoxTrackingDelay": 1,
"addressProtocol": 0,
"rowEnabled": true,
"dbInsertTime": 1448607218600,
"device": {
"$id": "10",
"imei": 358240051111110,
"brand": "Unknown",
"model": "PTI Emulateur",
"name": "PTI Emulateur Fred",
"registration": {
"$id": "11",
"imei": 358240051111110,
"companyId": 1,
"latestRegistrationStatusChangeDate": 1556169720000,
"registrationStatus": 3,
"imeiNavigation": {
"$ref": "10"
}
}
},
"vehiculeGpsBoxInfo": {
"$id": "12",
"vehiculeId": 359586014995819,
"currentDelay": 0,
"normalTrackingMode": 2,
"timeModeDelay": 60000,
"smartModeDelay": 5000,
"smartModeDistance": 100,
"connected": false,
"heartBeatPeriod": 1200,
"insureCoherence": false,
"killHedgehog": true,
"boardConnected": false,
"lastCommunicationTime": 1558078487030,
"boardLastCommunicationTime": 1485957716897,
"vehiculeConfiguration": 169,
"updateStatus": 0,
"vehicule": {
"$ref": "9"
},
"vehiculeConfigurationNavigation": {
"$id": "13",
"configurationId": 169,
"configName": "SafeProtectSamsungS6",
"masterName": "SafeProtectSamsungS6",
"master": "1.0.2",
"firmware": "",
"system": "",
"gpsBoxType": 29,
"vehiculeGpsBoxInfoBoardConfigurationNavigation": [],
"vehiculeGpsBoxInfoVehiculeConfigurationNavigation": [
{
"$ref": "12"
},
{
"$id": "14",
"vehiculeId": 359586015014836,
"currentDelay": 0,
"normalTrackingMode": 2,
"timeModeDelay": 60000,
"smartModeDelay": 5000,
"smartModeDistance": 100,
"connected": true,
"heartBeatPeriod": 1200,
"insureCoherence": false,
"killHedgehog": true,
"lastCommunicationTime": 1568202416063,
"vehiculeConfiguration": 169,
"updateStatus": 0,
"lastConnexionTime": 1545057192063,
"vehicule": {
"$id": "15",
"vehiculeId": 359586015014836,
"companyId": 1,
"phoneNumber": "+351927853883",
"hardwareId": 356437083709729,
"gpsBoxType": 29,
"name": "Samsung J5 test",
"iconId": 33569462,
"gpsBoxTrackingDelay": 1,
"addressProtocol": 0,
"rowEnabled": true,
"dbInsertTime": 1513945397863,
"device": {
"$id": "16",
"imei": 356437083709729,
"brand": "Samsung",
"model": "J5",
"name": "Test"
},
"vehiculeGpsBoxInfo": {
"$ref": "14"
},
"fleetDetail": [
{
"$id": "17",
"fleetDetailId": 26445,
"fleetId": 3486,
"vehiculeId": 359586015014836,
"rowEnabled": true,
"fleet": {
"$id": "18",
"fleetId": 3486,
"companyId": 1,
"name": "RTE Protect",
"rowEnabled": true,
"fleetDetailFleet": [
{
"$id": "19",
"fleetDetailId": 13251,
"fleetId": 3486,
"vehiculeId": 359586014995819,
"rowEnabled": true,
"fleet": {
"$ref": "18"
},
"vehicule": {
"$ref": "9"
}
},
{
"$id": "20",
"fleetDetailId": 13477,
"fleetId": 3486,
"vehiculeId": 359586014995819,
"rowEnabled": false,
"fleet": {
"$ref": "18"
},
"vehicule": {
"$ref": "9"
}
},
{
"$ref": "17"
}
],
"fleetDetailFleetChildNavigation": []
},
"vehicule": {
"$ref": "15"
}
},
{
"$id": "21",
"fleetDetailId": 27485,
"fleetId": 5536,
"vehiculeId": 359586015014836,
"rowEnabled": true,
"fleet": {
"$id": "22",
"fleetId": 5536,
"companyId": 1,
"name": "SafeProtect",
"rowEnabled": true,
"fleetDetailFleet": [
{
"$ref": "21"
}
],
"fleetDetailFleetChildNavigation": []
},
"vehicule": {
"$ref": "15"
}
}
]
},
"vehiculeConfigurationNavigation": {
"$ref": "13"
}
},
{
"$id": "23",
"vehiculeId": 359586015014947,
"currentDelay": 0,
"normalTrackingMode": 2,
"timeModeDelay": 60000,
"smartModeDelay": 5000,
"smartModeDistance": 100,
"connected": false,
"heartBeatPeriod": 1200,
"insureCoherence": false,
"killHedgehog": true,
"lastCommunicationTime": 1558006034977,
"vehiculeConfiguration": 169,
"updateStatus": 0,
"vehicule": {
"$id": "24",
"vehiculeId": 359586015014947,
"companyId": 1,
"phoneNumber": " ",
"hardwareId": 357011072523992,
"gpsBoxType": 29,
"name": "SafeProtect Céline Pro",
"iconId": 33554432,
"gpsBoxTrackingDelay": 1,
"addressProtocol": 0,
"rowEnabled": true,
"dbInsertTime": 1538134175170,
"device": {
"$id": "25",
"imei": 357011072523992,
"brand": "Samsung",
"model": "S6",
"name": "S6 Céline",
"registration": {
"$id": "26",
"imei": 357011072523992,
"companyId": 1,
"latestRegistrationStatusChangeDate": 1556103600000,
"registrationStatus": 3,
"imeiNavigation": {
"$ref": "25"
}
}
},
"vehiculeGpsBoxInfo": {
"$ref": "23"
},
"fleetDetail": []
},
"vehiculeConfigurationNavigation": {
"$ref": "13"
}
}
]
}
},
"fleetDetail": [
{
"$id": "27",
"fleetDetailId": 26334,
"fleetId": 659,
"vehiculeId": 359586014995819,
"rowEnabled": false,
"fleet": {
"$id": "28",
"fleetId": 659,
"companyId": 1,
"name": "Parc",
"rowEnabled": true,
"fleetDetailFleet": [
{
"$ref": "27"
}
],
"fleetDetailFleetChildNavigation": []
},
"vehicule": {
"$ref": "9"
}
},
{
"$ref": "8"
},
{
"$id": "29",
"fleetDetailId": 25993,
"fleetId": 3216,
"vehiculeId": 359586014995819,
"rowEnabled": false,
"fleet": {
"$ref": "7"
},
"vehicule": {
"$ref": "9"
}
},
{
"$ref": "19"
},
{
"$ref": "20"
}
]
}
},
{
"$ref": "29"
},
{
"$ref": "6"
}
],
"fleetDetailFleetChildNavigation": []
},
"vehicule": {
"$ref": "1"
}
},
{
"$id": "30",
"fleetDetailId": 27476,
"fleetId": 5534,
"vehiculeId": 359586015016459,
"rowEnabled": true,
"fleet": {
"$id": "31",
"fleetId": 5534,
"companyId": 1,
"name": "Ol",
"rowEnabled": true,
"fleetDetailFleet": [
{
"$ref": "30"
}
],
"fleetDetailFleetChildNavigation": []
},
"vehicule": {
"$ref": "1"
}
}
]
}
Currently my controller method is the following:
[HttpPost]
public async Task<IActionResult> UpdateDati([FromBody] Vehicule model)
{...}
I'm surprised there is no simple way to sepcify this kind of behavior for model binding. What am I missing here?
Upvotes: 2
Views: 3038
Reputation:
The solution is to write a custom model binder to use JSON.Net to deserialize the request body:
/// <summary>
/// Custom model binder to be used when TrackableEntities coming in HttpPost Methods.
/// </summary>
public class TrackableEntityModelBinder : IModelBinder
{
/// <inheritdoc/>
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
using (var reader = new StreamReader(bindingContext.HttpContext.Request.Body))
{
var body = await reader.ReadToEndAsync().ConfigureAwait(continueOnCapturedContext: false);
// Do something
var value = JsonConvert.DeserializeObject(body, bindingContext.ModelType, new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = new CamelCasePropertyNamesContractResolver(),
ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
});
bindingContext.Result = ModelBindingResult.Success(value);
}
}
}
Then, just anotate your HttpPost method parameter to use the model binder:
[HttpPost]
public async Task<IActionResult> UpdateDati([ModelBinder(typeof(TrackableEntityModelBinder))] [FromBody] Vehicule model)
{
}
Upvotes: 5
Reputation: 673
Can you try removing them:
.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.None;
does your Vehicule object match (I just used paste special in VS)
public class Rootobject
{
public string id { get; set; }
public long vehiculeId { get; set; }
public int companyId { get; set; }
public string phoneNumber { get; set; }
public long hardwareId { get; set; }
public int gpsBoxType { get; set; }
public string name { get; set; }
public int iconId { get; set; }
public int gpsBoxTrackingDelay { get; set; }
public bool rowEnabled { get; set; }
public long dbInsertTime { get; set; }
public Device device { get; set; }
public Vehiculegpsboxinfo vehiculeGpsBoxInfo { get; set; }
public Fleetdetail[] fleetDetail { get; set; }
}
public class Device
{
public string id { get; set; }
public long imei { get; set; }
public string brand { get; set; }
public string model { get; set; }
public string name { get; set; }
public Registration registration { get; set; }
}
public class Registration
{
public string id { get; set; }
public long imei { get; set; }
public int companyId { get; set; }
public long latestRegistrationStatusChangeDate { get; set; }
public int registrationStatus { get; set; }
public Imeinavigation imeiNavigation { get; set; }
}
public class Imeinavigation
{
public string _ref { get; set; }
}
public class Vehiculegpsboxinfo
{
public string id { get; set; }
public long vehiculeId { get; set; }
public int currentDelay { get; set; }
public int normalTrackingMode { get; set; }
public int timeModeDelay { get; set; }
public int smartModeDelay { get; set; }
public int smartModeDistance { get; set; }
public bool connected { get; set; }
public int heartBeatPeriod { get; set; }
public bool insureCoherence { get; set; }
public bool killHedgehog { get; set; }
public long lastCommunicationTime { get; set; }
public int vehiculeConfiguration { get; set; }
public int updateStatus { get; set; }
public Vehicule vehicule { get; set; }
public Vehiculeconfigurationnavigation vehiculeConfigurationNavigation { get; set; }
}
public class Vehicule
{
public string _ref { get; set; }
}
public class Vehiculeconfigurationnavigation
{
public string id { get; set; }
public int configurationId { get; set; }
public string configName { get; set; }
public string masterName { get; set; }
public string master { get; set; }
public string firmware { get; set; }
public string system { get; set; }
public int gpsBoxType { get; set; }
public object[] vehiculeGpsBoxInfoBoardConfigurationNavigation { get; set; }
public Vehiculegpsboxinfovehiculeconfigurationnavigation[] vehiculeGpsBoxInfoVehiculeConfigurationNavigation { get; set; }
}
public class Vehiculegpsboxinfovehiculeconfigurationnavigation
{
public string _ref { get; set; }
}
public class Fleetdetail
{
public string id { get; set; }
public int fleetDetailId { get; set; }
public int fleetId { get; set; }
public long vehiculeId { get; set; }
public bool rowEnabled { get; set; }
public Fleet fleet { get; set; }
public Vehicule7 vehicule { get; set; }
}
public class Fleet
{
public string id { get; set; }
public int fleetId { get; set; }
public int companyId { get; set; }
public string name { get; set; }
public bool rowEnabled { get; set; }
public Fleetdetailfleet[] fleetDetailFleet { get; set; }
public object[] fleetDetailFleetChildNavigation { get; set; }
}
public class Fleetdetailfleet
{
public string id { get; set; }
public int fleetDetailId { get; set; }
public int fleetId { get; set; }
public long vehiculeId { get; set; }
public bool rowEnabled { get; set; }
public Fleet1 fleet { get; set; }
public Vehicule1 vehicule { get; set; }
public string _ref { get; set; }
}
public class Fleet1
{
public string _ref { get; set; }
}
public class Vehicule1
{
public string id { get; set; }
public long vehiculeId { get; set; }
public int companyId { get; set; }
public string phoneNumber { get; set; }
public long hardwareId { get; set; }
public int gpsBoxType { get; set; }
public string category { get; set; }
public string name { get; set; }
public int iconId { get; set; }
public int gpsBoxTrackingDelay { get; set; }
public int addressProtocol { get; set; }
public bool rowEnabled { get; set; }
public long dbInsertTime { get; set; }
public Device1 device { get; set; }
public Vehiculegpsboxinfo1 vehiculeGpsBoxInfo { get; set; }
public Fleetdetail2[] fleetDetail { get; set; }
}
public class Device1
{
public string id { get; set; }
public long imei { get; set; }
public string brand { get; set; }
public string model { get; set; }
public string name { get; set; }
public Registration1 registration { get; set; }
}
public class Registration1
{
public string id { get; set; }
public long imei { get; set; }
public int companyId { get; set; }
public long latestRegistrationStatusChangeDate { get; set; }
public int registrationStatus { get; set; }
public Imeinavigation1 imeiNavigation { get; set; }
}
public class Imeinavigation1
{
public string _ref { get; set; }
}
public class Vehiculegpsboxinfo1
{
public string id { get; set; }
public long vehiculeId { get; set; }
public int currentDelay { get; set; }
public int normalTrackingMode { get; set; }
public int timeModeDelay { get; set; }
public int smartModeDelay { get; set; }
public int smartModeDistance { get; set; }
public bool connected { get; set; }
public int heartBeatPeriod { get; set; }
public bool insureCoherence { get; set; }
public bool killHedgehog { get; set; }
public bool boardConnected { get; set; }
public long lastCommunicationTime { get; set; }
public long boardLastCommunicationTime { get; set; }
public int vehiculeConfiguration { get; set; }
public int updateStatus { get; set; }
public Vehicule2 vehicule { get; set; }
public Vehiculeconfigurationnavigation1 vehiculeConfigurationNavigation { get; set; }
}
public class Vehicule2
{
public string _ref { get; set; }
}
public class Vehiculeconfigurationnavigation1
{
public string id { get; set; }
public int configurationId { get; set; }
public string configName { get; set; }
public string masterName { get; set; }
public string master { get; set; }
public string firmware { get; set; }
public string system { get; set; }
public int gpsBoxType { get; set; }
public object[] vehiculeGpsBoxInfoBoardConfigurationNavigation { get; set; }
public Vehiculegpsboxinfovehiculeconfigurationnavigation1[] vehiculeGpsBoxInfoVehiculeConfigurationNavigation { get; set; }
}
public class Vehiculegpsboxinfovehiculeconfigurationnavigation1
{
public string _ref { get; set; }
public string id { get; set; }
public long vehiculeId { get; set; }
public int currentDelay { get; set; }
public int normalTrackingMode { get; set; }
public int timeModeDelay { get; set; }
public int smartModeDelay { get; set; }
public int smartModeDistance { get; set; }
public bool connected { get; set; }
public int heartBeatPeriod { get; set; }
public bool insureCoherence { get; set; }
public bool killHedgehog { get; set; }
public long lastCommunicationTime { get; set; }
public int vehiculeConfiguration { get; set; }
public int updateStatus { get; set; }
public long lastConnexionTime { get; set; }
public Vehicule3 vehicule { get; set; }
public Vehiculeconfigurationnavigation2 vehiculeConfigurationNavigation { get; set; }
}
public class Vehicule3
{
public string id { get; set; }
public long vehiculeId { get; set; }
public int companyId { get; set; }
public string phoneNumber { get; set; }
public long hardwareId { get; set; }
public int gpsBoxType { get; set; }
public string name { get; set; }
public int iconId { get; set; }
public int gpsBoxTrackingDelay { get; set; }
public int addressProtocol { get; set; }
public bool rowEnabled { get; set; }
public long dbInsertTime { get; set; }
public Device2 device { get; set; }
public Vehiculegpsboxinfo2 vehiculeGpsBoxInfo { get; set; }
public Fleetdetail1[] fleetDetail { get; set; }
}
public class Device2
{
public string id { get; set; }
public long imei { get; set; }
public string brand { get; set; }
public string model { get; set; }
public string name { get; set; }
public Registration2 registration { get; set; }
}
public class Registration2
{
public string id { get; set; }
public long imei { get; set; }
public int companyId { get; set; }
public long latestRegistrationStatusChangeDate { get; set; }
public int registrationStatus { get; set; }
public Imeinavigation2 imeiNavigation { get; set; }
}
public class Imeinavigation2
{
public string _ref { get; set; }
}
public class Vehiculegpsboxinfo2
{
public string _ref { get; set; }
}
public class Fleetdetail1
{
public string id { get; set; }
public int fleetDetailId { get; set; }
public int fleetId { get; set; }
public long vehiculeId { get; set; }
public bool rowEnabled { get; set; }
public Fleet2 fleet { get; set; }
public Vehicule5 vehicule { get; set; }
}
public class Fleet2
{
public string id { get; set; }
public int fleetId { get; set; }
public int companyId { get; set; }
public string name { get; set; }
public bool rowEnabled { get; set; }
public Fleetdetailfleet1[] fleetDetailFleet { get; set; }
public object[] fleetDetailFleetChildNavigation { get; set; }
}
public class Fleetdetailfleet1
{
public string id { get; set; }
public int fleetDetailId { get; set; }
public int fleetId { get; set; }
public long vehiculeId { get; set; }
public bool rowEnabled { get; set; }
public Fleet3 fleet { get; set; }
public Vehicule4 vehicule { get; set; }
public string _ref { get; set; }
}
public class Fleet3
{
public string _ref { get; set; }
}
public class Vehicule4
{
public string _ref { get; set; }
}
public class Vehicule5
{
public string _ref { get; set; }
}
public class Vehiculeconfigurationnavigation2
{
public string _ref { get; set; }
}
public class Fleetdetail2
{
public string id { get; set; }
public int fleetDetailId { get; set; }
public int fleetId { get; set; }
public long vehiculeId { get; set; }
public bool rowEnabled { get; set; }
public Fleet4 fleet { get; set; }
public Vehicule6 vehicule { get; set; }
public string _ref { get; set; }
}
public class Fleet4
{
public string id { get; set; }
public int fleetId { get; set; }
public int companyId { get; set; }
public string name { get; set; }
public bool rowEnabled { get; set; }
public Fleetdetailfleet2[] fleetDetailFleet { get; set; }
public object[] fleetDetailFleetChildNavigation { get; set; }
public string _ref { get; set; }
}
public class Fleetdetailfleet2
{
public string _ref { get; set; }
}
public class Vehicule6
{
public string _ref { get; set; }
}
public class Vehicule7
{
public string _ref { get; set; }
}
Upvotes: 0