7

I have a webapi that returns some Json:

{"id":9,"businessName":"dummy","address":"pluto","products":[
{"id":762,"description":"Centralized needs-based website","price":1281.24,"stock":1600,"categories":[],"factory":null},
{"id":1027,"description":"Realigned 6th generation knowledge base","price":2398.16,"stock":19583,"categories":[],"factory":null},
{"id":1392,"description":"User-centric zero administration array","price":998.07,"stock":6124,"categories":[],"factory":null},
{"id":1800,"description":"Team-oriented reciprocal core","price":4422.95,"stock":17372,"categories":[],"factory":null},
{"id":2763,"description":"Sharable needs-based hierarchy","price":4122.98,"stock":17397,"categories":[],"factory":null},
{"id":6189,"description":"Re-engineered hybrid emulation","price":395.09,"stock":532,"categories":[],"factory":null}
]}

I then try to deserialize using:

using var response = await _httpClient.GetAsync($"{GetApiRouteFromEntity(entity)}/{entity.GetId()}");
        response.EnsureSuccessStatusCode();
        var responseContent = await response.Content.ReadAsStringAsync();
        T? item = JsonSerializer.Deserialize<T>(responseContent);

but this gives me an empty Factory with id 0 and all the other attributes to null

Factory.cs

public class Factory : EntityBase
    {
        [DisplayName("ID")]
        public int Id { get; set; }

        [DisplayName("Nome Business")]
        public string? BusinessName { get; set; }

        [DisplayName("Indirizzo")]
        public string? Address { get; set; }

        [DisplayName("Prodotti")] 
        public virtual ICollection<Product> Products { get; set; }
        
        public override string ToString()
        {
            return $"[{Id}] {BusinessName}";
        }
    }

Product.cs

public class Product : EntityBase
    {
        [DisplayName("ID")]
        public int Id { get; set; }

        [DisplayName("Descrizione")]
        public string? Description { get; set; }

        [DisplayName("Prezzo")]
        public float Price { get; set; }

        [DisplayName("Magazzino")]
        public int Stock { get; set; }

        [DisplayName("Categorie")]
        public virtual ICollection<Category> Categories { get; set; }

        [DisplayName("Fabbrica")]
        public virtual Factory Factory { get; set; }

        public override string ToString()
        {
            return $"[{Id}] {Description}";
        }
    }

EntityBase.cs

public abstract class EntityBase
    {
        public virtual object GetId()
        {
            return GetType().GetProperty("Id").GetValue(this);
        }
    }

i guess its because the factory prop in the products is null but idk how to work around that

Ivan Ambla
  • 763
  • 5
  • 24

2 Answers2

10

The JSON keys are all camel case but the props in your classes are written in pascal case. E.g. businessName vs. BusinessName. Hence JsonSerializer can't match them.

You can initialize the serializer like this to ignore the differences in casing:

var options = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true
};
T? item = JsonSerializer.Deserialize<T>(responseContent, options);

See the docs for further info: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-character-casing

Jan Köhler
  • 5,817
  • 5
  • 26
  • 35
6

From the docs:

By default, property names and dictionary keys are unchanged in the JSON output, including case.

You can specify the property naming policy:

T? item = JsonSerializer.Deserialize<T>(responseContent, new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});

to use camel case for all JSON property names, or mark all needed properties with JsonPropertyNameAttibute containing correct name:

public class Factory : EntityBase
{
    [DisplayName("ID")]
    [JsonPropertyName("id")] // and so on
    public int Id { get; set; }
    ....
}

Or set JsonSerializerOptions.PropertyNameCaseInsensitive to true.

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • 1
    oh my god, i spent 5 hoiurs into this, ty so much! – Ivan Ambla Feb 17 '22 at 12:35
  • @IvanAmbla was glad to help! – Guru Stron Feb 17 '22 at 12:40
  • i have a new problem now :-:, if i try to serialize the object it gives me a nice string with PascalCase but if i try and use JsonSerializer.Serialize(lastEntity.Entity,new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }) it just gives me {} – Ivan Ambla Feb 17 '22 at 14:11
  • @IvanAmbla are you using the same settings when serializing and deserialiazing? Or the json is coming from another system? – Guru Stron Feb 17 '22 at 14:25
  • same settings, im just putting instead of getting – Ivan Ambla Feb 17 '22 at 14:26
  • for now i found a workaround using Newtonsoft JsonConvert.SerializeObject but it would be better using the native jsonserializer – Ivan Ambla Feb 17 '22 at 14:27
  • Can you please post full repro somewhere? Cause if you are using the same settings as in answer it should not return pascal case. There is another option - make property names case insensitive - `new JsonSerializerOptions { PropertyNameCaseInsensitive = true };` – Guru Stron Feb 17 '22 at 14:30
  • 1
    using the same options returns {} using no options return Pascal, ill prepare a repo if necessary i will take me some time, ty for the help again! – Ivan Ambla Feb 17 '22 at 14:36
  • 1
    i can open a new discussion, i think its better since even if related is a different problem ill open it this evening – Ivan Ambla Feb 17 '22 at 14:41