Nested json deserialized incompletely - asp.net-mvc-4

I mentioned in title that the json is deserialized incompletely because some of the objects have the right value in the controller (I send the json to an asp.net mvc 4 controller), but the problem occurs with properties of objects stored in arrays (to be exact, the problem appears with Data)
I have the following classes:
public class Node
{
[JsonProperty("id")]
public int? Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
private Data _data = new Data();
[JsonProperty("data")]
public Data Data { get; set; }
private List<Adjacency> _adjacencies = new List<Adjacency>();
[JsonProperty("adjacencies")]
public List<Adjacency> Adjacencies
{
get { return _adjacencies; }
set { _adjacencies = value; }
}
private List<Instance> _dependendStates = new List<Instance>();
public List<Instance> DependentStates
{
get { return _dependendStates; }
set { _dependendStates = value; }
}
}
public class Data
{
[JsonProperty("$posX")]
public decimal PosX { get; set; }
[JsonProperty("$posY")]
public decimal PosY { get; set; }
}
public class Adjacency
{
[JsonProperty(PropertyName = "nodeTo")]
public string NodeTo { get; set; }
[JsonProperty(PropertyName = "data")]
public AdjData Data { get; set; }
//doesn't contain definition for automated transitions
}
public class AdjData
{
[JsonProperty(PropertyName = "$labelid")]
public string LabelId { get; set; }
[JsonProperty(PropertyName = "$labeltext")]
public string Label { get; set; }
[JsonProperty(PropertyName = "$type")]
public string Type { get; set; }
}
I've highlighted fields that don't have the right value.
The null problem http://img19.imageshack.us/img19/530/36976913.png
The json looks like this:
{
"result":[
{
"id":"100",
"name":"Start",
"data":{
"$posX":-100,
"$posY":-100,
"$deployed":true,
"$color":"#000000",
"$selected":"true"
},
"adjacencies":[
{
"nodeTo":"188",
"data":{
"$type":"labeled_arrow",
"$labelid":"Label Name",
"$labeltext":"Label Name"
}
}
]
},
{
"id":"188",
"name":"Second ",
"data":{
"$dim":20,
"$color":"#000000",
"$selected":"true"
},
"adjacencies":[
]
}
],
"smName":"gftrds"
}
I'm having a problem sorting this out as I do not understand or see where the problem is.

Disclaimer: I wasn't able to reproduce this exactly, as in my case Label and LabelId deserialized fine, though Type did not, so my anwser may not address the problem you are having.
In my case, I was only able to deserialize the "$type":"labeled_arrow" property if it was not the first one - if it appeared after "$labelid":"Label Name" or "$labeltext":"Label Name" it worked fine.
Strangely, if the $type property was called type in the Json and referred to as [JsonProperty(PropertyName = "type")] in the C#, it would deserialize fine, regardless of the order.
In your case you can't deserialize Label or LabelId either, so it could be that your problem is caused by something else. To rule out what I have suggested, it might pay to try modifying some of the property names (possibly just take off the $) to see if they are causing the properties to be deserialized incorrectly.

I experienced the same issue, however in my case this was related to how the data was being transmitted from client side. Make sure the AJAX request is using the proper headers and formatting. For example:
dataType: 'json',
contentType: 'application/json; charset=UTF-8',
data: JSON.stringify({
MemberId : '123',
UserName: '456',
Parameters: [
{ Value : 'testing' },
{ Value : 'test2' }
]
}),

Related

Bind property to another input name in nested array property

The data in JSON format is sent to api endpoint.
Data sample:
{
"templateId": "dc15e4d1-ccbd-4581-a819-5b7f90b32cc5",
"name": "abc",
"steps": [
{
"id": "34b4f406-120e-4d80-8018-6c780c80a6c4",
"visible": false,
}
]
}
Api gets data in this format:
public class TemplateRequest {
public Guid TemplateId { get; set; }
public string Name { get; set; }
public StepRequest[] Steps { get; set; }
}
StepRequest class:
public class StepRequest {
[ModelBinder(Name = "id")]
public Guid StepId { get; set; }
public bool? Visible { get; set; }
}
The JSON has id key instead of stepId, but I can't get it in controller.
When I check, the StepId is always an empty Guid.
What is wrong here, why the StepId property is not having the value from id key?
Yes, like #daremachine said, it was NewtonSoft and JsonProperty(PropertyName = "id") helped.

How to use Patch method in minimal api application?

I am trying to use patch method in my minimal api application this is my code :
Car class
public class Car
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "producent")]
public Producent Producent { get; set; }
[JsonProperty(PropertyName = "age")]
public int Age { get; set; }
[JsonProperty(PropertyName = "yearCreated")]
public int YearCreated { get; set; }
[JsonProperty(PropertyName = "engine")]
public Engine Engine { get; set; }
public Car()
{
Id= Guid.NewGuid().ToString();
YearCreated = DateTime.Now.Year - Age;
}
}
ICarService:
public interface ICarService
{
Task<IEnumerable<Car>> GetAll();
Task<Car> GetById(string id,string partitionKey);
Task Create(Car car);
Task<bool> Update(Car car);
Task<Car> UpdatePatchAsync(string id, string partitionKey,List<PatchOperation> patchOperations);
Task<bool> Delete(string id,string partitionKey);
}
patch method in service
public async Task<Car> UpdatePatchAsync(string id, string partitionKey, List<PatchOperation> patchOperations)
{
var result = await _container.PatchItemAsync<Car>(id, new PartitionKey(partitionKey),
patchOperations:patchOperations );
return result;
}
my requests:
[HttpPatch]
public static async Task<IResult> Patch(ICarService service,string id,string partitionKey,
[FromBody]List<PatchOperation> operations)
{
var updatedCar = await service.UpdatePatchAsync(id,partitionKey,operations);
if (updatedCar == null)
{
return Results.NotFound();
}
return Results.Ok(updatedCar);
}
app.MapMethods("/cars/patch/{id}/{partitionKey}", new string[] { "PATCH" }, CarRequests.Patch);
I use cosmosDb database and when i code like this:
{
"op": "replace",
"path": "age",
"value": 22
}
i get the error
System.NotSupportedException: Deserialization of types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with 'JsonConstructorAttribute' is not supported. Type 'Microsoft.Azure.Cosmos.PatchOperation'. Path: $[0] | LineNumber: 3 | BytePositionInLine: 3.
---> System.NotSupportedException: Deserialization of types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with 'JsonConstructorAttribute' is not supported. Type 'Microsoft.Azure.Cosmos.PatchOperation'.
The problem is you are using [FromBody]List<PatchOperation> operations.
This is making ASP.NET attempt to deserialize a JSON raw string into PatchOperation, which when we look at our source code, has no parameterless constructor: https://github.com/Azure/azure-cosmos-dotnet-v3/blob/master/Microsoft.Azure.Cosmos/src/Patch/PatchOperation.cs, it is an abstract class.
The way it is meant to be used is through PatchOperation.XXXX, like PatchOperation.Add, you cannot use it to deserialize into it. You could have your own MyPatchOperation<Car> that has the exposed properties for deserialization, and then simply have a method in that class that based on which properties are populated, calls PatchOperation<Car>.Add (or whatever operation).
Not the full code but:
public class MyPatchOperation
{
[JsonProperty(PropertyName = "op")]
public string Operation { get; set; }
[JsonProperty(PropertyName = "path")]
public string Path { get; set; }
[JsonProperty(PropertyName = "value")]
public string Value { get; set; }
public PatchOperation<Car> ToPatchOperation()
{
switch (this.Operation)
{
case "replace":
return PatchOperation<Car>.Replace(this.Path, this.Value);
/* other operations */
}
}
}

Core WebAPI not returning all values/parameters

I am upgrading a .NET 4.5 solution to .Net 5. In the process of this i have found some code that works in 4.5 but does not seem to work in Core.
It is a rather simple WebAPI call, a simplified example as follows;
Model:
public class UJ
{
public interface IJComponent
{
string Type { get; set; }
}
public class JComponentRte : IJComponent
{
public string? Type { get; set; }
public string Text { get; set; }
}
}
Controller:
private List<IJComponent> GetJComponents(...)
{
var sComponents = new List<IJComponent>();
foreach (var component in components)
{
sComponents.Add(
new JComponentRte {
Type = "My type",
Text = "My text"
});
break;
}
}
The issues is that it always just returns the Type, not the Text. The Text is not just empty, is is not included in the return value at all - like it is only looking at IJComponent as the Model and not the JComponentRte? WHat am I missing?
Am not sure why it would have worked in earlier version but problem appears to be that your interface does not include the Text property, so when the result is being serialised using interface IJComponent, there is no Text property to serialise.
Either add the Text property to the interface:
public interface IJComponent
{
string Type { get; set; }
string Text { get; set; }
}
Or return a list of JComponent:
private List<JComponent> GetJComponents(...)
{
var sComponents = new List<JComponent>();
foreach (var component in components)
{
sComponents.Add(
new JComponentRte {
Type = "My type",
Text = "My text"
});
break;
}
}

Better Way of Dealing With Circular References? - EF Core 3.1 and Web API

I am currently trying to progress with EF Core with a one-to-many (a user has many items). A tutorial or three later I managed to get things working with two very small and simple tables; however, I got a json exception: A possible object cycle was detected which is not supported which indicated that I had circular references.
Here is my code that gets around the issue using DTO objects, but is there a more cleaner way I can get around this issue as typing the, though it works, felt a bit wrong.
User:
namespace TestWebApplication.Database
{
public class User
{
[Key]
public int UserId { get; set; }
public string UserName { get; set; }
public string Dob { get; set; }
public string Location { get; set; }
public ICollection<Items> Items { get; set; }
}
}
Items:
namespace TestWebApplication.Database
{
public class Items
{
[Key]
public int ItemId { get; set; }
public string Item { get; set; }
public string Category { get; set; }
public string Type { get; set; }
public virtual User User { get; set; }
}
}
DtoItems:
namespace TestWebApplication.Database.DTOs
{
public class DtoItems
{
public string Item { get; set; }
public string Category { get; set; }
public string Type { get; set; }
public DtoUser User { get; set; }
}
}
DtoUser:
namespace TestWebApplication.Database.DTOs
{
public class DtoUser
{
public string UserName { get; set; }
public string Dob { get; set; }
public string Location { get; set; }
}
}
TestController:
[HttpGet]
[Route("getitems")]
public ActionResult<List<Items>> GetItems()
{
List<Items> items = _myContext.Items.Include(i => i.User).ToList();
// DTOs
List<DtoItems> dtoItems = new List<DtoItems>();
foreach (var i in items)
{
var dtoItem = new DtoItems
{
Item = i.Item,
Category = i.Category,
Type = i.Type,
User = new DtoUser
{
UserName = i.User.UserName,
Dob = i.User.Dob,
Location = i.User.Location
}
};
dtoItems.Add(dtoItem);
}
return Ok(dtoItems);
}
The output from endpoint:
[
{
"item": "xxx",
"category": "xxx",
"type": "xxx",
"user": {
"userName": "xxx",
"dob": "xxx",
"location": "xx"
}
},
{
"item": "xxx",
"category": "xxx",
"type": "xxx",
"user": {
"userName": "xxx",
"dob": "xxx",
"location": "xxx"
}
}
]
In my opinion, the use of a DTO is the correct way of dealing with this issue. The fact that your datamodel does not serialize well is trying to hint to you that you should not be serializing your datamodel from the API at all.
I think returning a DTO also solves further issues down the road (What if you want to return all properties of the UserModel except one, maybe it's a sensitive property you don't want to just return from your API, what if your UserModel in the DB gets more navigation properties that you don't want to return?).
There is really only two other ways of handling this.
You can switch to Newtonsoft.Json which has support for handling reference loops and you can configure it one single line
Like so :
services.AddControllers().AddNewtonsoftJson(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
System.Text.Json does not have support for doing this (yet). Follow this Github Issue for more info : https://github.com/dotnet/runtime/issues/30820
You use the JsonIgnore attribute to force non serialization of properties which will work but... It looks weird to have an EntityFramework model have JSON Serialization options on it...
So your best bet, stick with the DTO.
More info :
https://dotnetcoretutorials.com/2020/03/15/fixing-json-self-referencing-loop-exceptions/
https://github.com/dotnet/runtime/issues/30820
https://www.newtonsoft.com/json/help/html/ReferenceLoopHandlingIgnore.htm

Accessing data with DAL2: Value cannot be null.Parameter name: con

I'm trying to access data with DAL2 in DotNetNuke. When I use the repository.Get() to get all fields of a certain table I sometimes get this error:
'Value cannot be null. Parameter name: con'
public IEnumerable<SitesProvince> GetAll()
{
using (var ctx = DataContextContent.Instance())
{
var rep = ctx.GetRepository<SitesProvince>();
return rep.Get();
}
}
Model:
[TableName("Sites_Province")]
[PrimaryKey("Sites_Province_No")]
[Cacheable("Sites_Province", CacheItemPriority.Default, 20)]
[Scope("Sites_Province_No")]
public class SitesProvince
{
public int Sites_Province_No { get; set; }
public string BU { get; set; }
public string Province { get; set; }
}
What could be the problem? In some queries it works and some don't and I don't see any difference between the methods.
I found this but I have no contracts:
http://clraddins.codeplex.com/discussions/24568
I solved this problem by adding an empty constructor to my model. Now everything works fine.