0

Hi I'm hoping you can help.

I'm working on converting Stocks data from a third party API to a c# data type, but the problem is, the JSON objects have multiple values.

For example:

"sharesShortPriorMonth":{"raw":4680878,"fmt":"4.68M","longFmt":"4,680,878"}

the one I want is the fmt value (4.68M), and I'm trying to put it into the C# field public string sharesShortPriorMonth { get; set; }

My question is, when I Deserialize from a JSON string, it's expecting something more like "sharesShortPriorMonth": "4.68M"

How can I tell Json.NET to take that value?

I've already checked the documentation, the JSONProperty Attribute isn't what i want, because that maps different names. not child values.

Thanks in advance.

TechnicalTophat
  • 1,655
  • 1
  • 15
  • 37

3 Answers3

1

You need either change your sharesShortPriorMonth to be of type representing the existing json structure (you can include only needed properties):

public SharesShortPriorMonth sharesShortPriorMonth { get; set; }

public class SharesShortPriorMonth
{
    public string fmt { get; set; }
}

Or create custom converter and mark field with corresponding attribute.

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
1

I would use something like this

public class Stocks
{
    ... another properties

    [JsonProperty("sharesShortPriorMonth")]
    public JObject sharesShortPriorMonthJo { set { sharesShortPriorMonth = (string) value["fmt"]; }}
    [JsonIgnore] 
    public string sharesShortPriorMonth { get; private set;}
}
Serge
  • 40,935
  • 4
  • 18
  • 45
  • Good idea, +1, but as I said in my answer I would make the `sharesShortPriorMonthJo` property `private`. – Marco Luzzara Jan 16 '22 at 17:19
  • @MarcoLuzzara thank you, I appreciate your interest and fixed my code. I didn't know that json will deserialize to private properties. Live and learn. – Serge Jan 16 '22 at 17:33
1

Personally, I would choose the solution of @Serge (but the sharesShortPriorMonthJo property should be private in my opinion because not necessary from the outside, but rather confusing for the client). If you want to keep your class as clean as possible, then you could use a custom JsonConverter, as pointed out by @GuruStron . However, the complexity is just moved in another class, the JsonConverter precisely.


The simplest (?) JsonConverter you could use in your case is:

public class CustomConverter : JsonConverter<string>
{
    public override void WriteJson(JsonWriter writer, string value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
    
    public override string ReadJson(JsonReader reader, Type objectType, string existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        var tokens = new Dictionary<string, object>();
        serializer.Populate(reader, tokens);
        
        return (string) tokens["fmt"] ?? throw new JsonReaderException(@"""fmt"" not found in sharesShortPriorMonth");
    }
}

The Populate method comes in very handy in this case because we can fill in a dictionary containing all the json attributes, eventually we just need to retrieve the fmt property.

The Stocks class becomes:

public class Stocks
{
    [JsonConverter(typeof(CustomConverter))]
    public string sharesShortPriorMonth { get; set; }
}
Marco Luzzara
  • 5,540
  • 3
  • 16
  • 42