How to custom deserialize into an object with json.net
I used http://json2csharp.com/ to generate a csharp class that represents my JSON, which worked wonderfully. However, after working with the third party api for a while, I realized that their responses aren't always sending the same type of data. I'm querying their API for Ticket data, and each ticket has a SellPrice. Sometimes they return that SellPrice as a Money object that has a currency (string) and amount (double), and sometimes they send it back as just a double. So I'm trying to find a way to handle this gracefully, so that I always set the Amount of my SellPrice object. Here's a short version of the code that works when they send a Money object as SellPrice
public class Ticket
{
public string Ticket_Id {get; set;}
//... other fields
public SellPrice SellPrice {get; set;}
}
public class SellPrice
{
public string Currency {get; set;}
public double Amount {get; set;}
}
And then when I get the Json, I deserialize like so, which works great...
for (int i = 0; i < jItems.Count; i++)
{
TUTicket2 item = jItems[i].ToObject<TUTicket2>();
}
...until I run into an API call that returns a double instead of an object.
So just looking at the case where it's Money object, I thought I'd try to create a constructor so that I can set the values depending on the object type, like so:
public class SellPrice
{
public SellPrice(object sellPrice)
{
if (sellPrice.GetType() == typeof(Dictionary<string, object>))
{
Currency = (string)((Dictionary<string, object>)sellPrice)["Currency"];
Amount = (double)((Dictionary<string, object>)sellPrice)["Currency"];
}
}
public string Currency { get; set; }
public double Amount { get; set; }
}
But that doesn't work because the sellPrice object is always null, so I think I'm barking up the wrong tree there. Is there a way to do this easily? I think my problem is the way it auto-deserializes to an object type, but I've been looking through the code/documentation and haven't figured out what I'm missing.
I have a couple goals here: We are doing enough API work that I'd like to be able to utilize a tool like json2csharp to generate the classes. I'd also like to avoid doing manual deserialization for every class/object, although if that's my only option, I can go in that direction, it just feels like overkill when 99% of the values behave normally. I also don't want to end up with X different versions of each of my classes depending on which API call I make. I'm trying to find some solution that just lets me override a small portion instead of everything. Any feedback would be appreciated.
json json.net
add a comment |
I used http://json2csharp.com/ to generate a csharp class that represents my JSON, which worked wonderfully. However, after working with the third party api for a while, I realized that their responses aren't always sending the same type of data. I'm querying their API for Ticket data, and each ticket has a SellPrice. Sometimes they return that SellPrice as a Money object that has a currency (string) and amount (double), and sometimes they send it back as just a double. So I'm trying to find a way to handle this gracefully, so that I always set the Amount of my SellPrice object. Here's a short version of the code that works when they send a Money object as SellPrice
public class Ticket
{
public string Ticket_Id {get; set;}
//... other fields
public SellPrice SellPrice {get; set;}
}
public class SellPrice
{
public string Currency {get; set;}
public double Amount {get; set;}
}
And then when I get the Json, I deserialize like so, which works great...
for (int i = 0; i < jItems.Count; i++)
{
TUTicket2 item = jItems[i].ToObject<TUTicket2>();
}
...until I run into an API call that returns a double instead of an object.
So just looking at the case where it's Money object, I thought I'd try to create a constructor so that I can set the values depending on the object type, like so:
public class SellPrice
{
public SellPrice(object sellPrice)
{
if (sellPrice.GetType() == typeof(Dictionary<string, object>))
{
Currency = (string)((Dictionary<string, object>)sellPrice)["Currency"];
Amount = (double)((Dictionary<string, object>)sellPrice)["Currency"];
}
}
public string Currency { get; set; }
public double Amount { get; set; }
}
But that doesn't work because the sellPrice object is always null, so I think I'm barking up the wrong tree there. Is there a way to do this easily? I think my problem is the way it auto-deserializes to an object type, but I've been looking through the code/documentation and haven't figured out what I'm missing.
I have a couple goals here: We are doing enough API work that I'd like to be able to utilize a tool like json2csharp to generate the classes. I'd also like to avoid doing manual deserialization for every class/object, although if that's my only option, I can go in that direction, it just feels like overkill when 99% of the values behave normally. I also don't want to end up with X different versions of each of my classes depending on which API call I make. I'm trying to find some solution that just lets me override a small portion instead of everything. Any feedback would be appreciated.
json json.net
add a comment |
I used http://json2csharp.com/ to generate a csharp class that represents my JSON, which worked wonderfully. However, after working with the third party api for a while, I realized that their responses aren't always sending the same type of data. I'm querying their API for Ticket data, and each ticket has a SellPrice. Sometimes they return that SellPrice as a Money object that has a currency (string) and amount (double), and sometimes they send it back as just a double. So I'm trying to find a way to handle this gracefully, so that I always set the Amount of my SellPrice object. Here's a short version of the code that works when they send a Money object as SellPrice
public class Ticket
{
public string Ticket_Id {get; set;}
//... other fields
public SellPrice SellPrice {get; set;}
}
public class SellPrice
{
public string Currency {get; set;}
public double Amount {get; set;}
}
And then when I get the Json, I deserialize like so, which works great...
for (int i = 0; i < jItems.Count; i++)
{
TUTicket2 item = jItems[i].ToObject<TUTicket2>();
}
...until I run into an API call that returns a double instead of an object.
So just looking at the case where it's Money object, I thought I'd try to create a constructor so that I can set the values depending on the object type, like so:
public class SellPrice
{
public SellPrice(object sellPrice)
{
if (sellPrice.GetType() == typeof(Dictionary<string, object>))
{
Currency = (string)((Dictionary<string, object>)sellPrice)["Currency"];
Amount = (double)((Dictionary<string, object>)sellPrice)["Currency"];
}
}
public string Currency { get; set; }
public double Amount { get; set; }
}
But that doesn't work because the sellPrice object is always null, so I think I'm barking up the wrong tree there. Is there a way to do this easily? I think my problem is the way it auto-deserializes to an object type, but I've been looking through the code/documentation and haven't figured out what I'm missing.
I have a couple goals here: We are doing enough API work that I'd like to be able to utilize a tool like json2csharp to generate the classes. I'd also like to avoid doing manual deserialization for every class/object, although if that's my only option, I can go in that direction, it just feels like overkill when 99% of the values behave normally. I also don't want to end up with X different versions of each of my classes depending on which API call I make. I'm trying to find some solution that just lets me override a small portion instead of everything. Any feedback would be appreciated.
json json.net
I used http://json2csharp.com/ to generate a csharp class that represents my JSON, which worked wonderfully. However, after working with the third party api for a while, I realized that their responses aren't always sending the same type of data. I'm querying their API for Ticket data, and each ticket has a SellPrice. Sometimes they return that SellPrice as a Money object that has a currency (string) and amount (double), and sometimes they send it back as just a double. So I'm trying to find a way to handle this gracefully, so that I always set the Amount of my SellPrice object. Here's a short version of the code that works when they send a Money object as SellPrice
public class Ticket
{
public string Ticket_Id {get; set;}
//... other fields
public SellPrice SellPrice {get; set;}
}
public class SellPrice
{
public string Currency {get; set;}
public double Amount {get; set;}
}
And then when I get the Json, I deserialize like so, which works great...
for (int i = 0; i < jItems.Count; i++)
{
TUTicket2 item = jItems[i].ToObject<TUTicket2>();
}
...until I run into an API call that returns a double instead of an object.
So just looking at the case where it's Money object, I thought I'd try to create a constructor so that I can set the values depending on the object type, like so:
public class SellPrice
{
public SellPrice(object sellPrice)
{
if (sellPrice.GetType() == typeof(Dictionary<string, object>))
{
Currency = (string)((Dictionary<string, object>)sellPrice)["Currency"];
Amount = (double)((Dictionary<string, object>)sellPrice)["Currency"];
}
}
public string Currency { get; set; }
public double Amount { get; set; }
}
But that doesn't work because the sellPrice object is always null, so I think I'm barking up the wrong tree there. Is there a way to do this easily? I think my problem is the way it auto-deserializes to an object type, but I've been looking through the code/documentation and haven't figured out what I'm missing.
I have a couple goals here: We are doing enough API work that I'd like to be able to utilize a tool like json2csharp to generate the classes. I'd also like to avoid doing manual deserialization for every class/object, although if that's my only option, I can go in that direction, it just feels like overkill when 99% of the values behave normally. I also don't want to end up with X different versions of each of my classes depending on which API call I make. I'm trying to find some solution that just lets me override a small portion instead of everything. Any feedback would be appreciated.
json json.net
json json.net
asked Nov 15 '18 at 18:56
BrendanBrendan
155
155
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
You can handle this by making a custom JsonConverter for your SellPrice class like this:
public class SellPriceConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(SellPrice);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
SellPrice sellPrice = new SellPrice();
if (token.Type == JTokenType.Object)
{
serializer.Populate(token.CreateReader(), sellPrice);
}
else if (token.Type == JTokenType.Float)
{
sellPrice.Amount = (double)token;
// if there is a default currency, set it here, e.g.:
// sellPrice.Currency = "USD";
}
else
{
throw new JsonException("Unexpected token type for SellPrice: " + token.Type.ToString());
}
return sellPrice;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
To use it, all you would need to do is add a [JsonConverter] attribute to the SellPrice class like this:
[JsonConverter(typeof(SellPriceConverter))]
public class SellPrice
{
...
}
Then you can just deserialize as normal and it should handle both situations.
Working demo here: https://dotnetfiddle.net/qZekyp
I was hoping there was something more simple, but I had a feeling this was the direction I would need to go. Thanks a lot for the concrete solution as well.
– Brendan
Nov 15 '18 at 23:11
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53326193%2fhow-to-custom-deserialize-into-an-object-with-json-net%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
You can handle this by making a custom JsonConverter for your SellPrice class like this:
public class SellPriceConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(SellPrice);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
SellPrice sellPrice = new SellPrice();
if (token.Type == JTokenType.Object)
{
serializer.Populate(token.CreateReader(), sellPrice);
}
else if (token.Type == JTokenType.Float)
{
sellPrice.Amount = (double)token;
// if there is a default currency, set it here, e.g.:
// sellPrice.Currency = "USD";
}
else
{
throw new JsonException("Unexpected token type for SellPrice: " + token.Type.ToString());
}
return sellPrice;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
To use it, all you would need to do is add a [JsonConverter] attribute to the SellPrice class like this:
[JsonConverter(typeof(SellPriceConverter))]
public class SellPrice
{
...
}
Then you can just deserialize as normal and it should handle both situations.
Working demo here: https://dotnetfiddle.net/qZekyp
I was hoping there was something more simple, but I had a feeling this was the direction I would need to go. Thanks a lot for the concrete solution as well.
– Brendan
Nov 15 '18 at 23:11
add a comment |
You can handle this by making a custom JsonConverter for your SellPrice class like this:
public class SellPriceConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(SellPrice);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
SellPrice sellPrice = new SellPrice();
if (token.Type == JTokenType.Object)
{
serializer.Populate(token.CreateReader(), sellPrice);
}
else if (token.Type == JTokenType.Float)
{
sellPrice.Amount = (double)token;
// if there is a default currency, set it here, e.g.:
// sellPrice.Currency = "USD";
}
else
{
throw new JsonException("Unexpected token type for SellPrice: " + token.Type.ToString());
}
return sellPrice;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
To use it, all you would need to do is add a [JsonConverter] attribute to the SellPrice class like this:
[JsonConverter(typeof(SellPriceConverter))]
public class SellPrice
{
...
}
Then you can just deserialize as normal and it should handle both situations.
Working demo here: https://dotnetfiddle.net/qZekyp
I was hoping there was something more simple, but I had a feeling this was the direction I would need to go. Thanks a lot for the concrete solution as well.
– Brendan
Nov 15 '18 at 23:11
add a comment |
You can handle this by making a custom JsonConverter for your SellPrice class like this:
public class SellPriceConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(SellPrice);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
SellPrice sellPrice = new SellPrice();
if (token.Type == JTokenType.Object)
{
serializer.Populate(token.CreateReader(), sellPrice);
}
else if (token.Type == JTokenType.Float)
{
sellPrice.Amount = (double)token;
// if there is a default currency, set it here, e.g.:
// sellPrice.Currency = "USD";
}
else
{
throw new JsonException("Unexpected token type for SellPrice: " + token.Type.ToString());
}
return sellPrice;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
To use it, all you would need to do is add a [JsonConverter] attribute to the SellPrice class like this:
[JsonConverter(typeof(SellPriceConverter))]
public class SellPrice
{
...
}
Then you can just deserialize as normal and it should handle both situations.
Working demo here: https://dotnetfiddle.net/qZekyp
You can handle this by making a custom JsonConverter for your SellPrice class like this:
public class SellPriceConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(SellPrice);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
SellPrice sellPrice = new SellPrice();
if (token.Type == JTokenType.Object)
{
serializer.Populate(token.CreateReader(), sellPrice);
}
else if (token.Type == JTokenType.Float)
{
sellPrice.Amount = (double)token;
// if there is a default currency, set it here, e.g.:
// sellPrice.Currency = "USD";
}
else
{
throw new JsonException("Unexpected token type for SellPrice: " + token.Type.ToString());
}
return sellPrice;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
To use it, all you would need to do is add a [JsonConverter] attribute to the SellPrice class like this:
[JsonConverter(typeof(SellPriceConverter))]
public class SellPrice
{
...
}
Then you can just deserialize as normal and it should handle both situations.
Working demo here: https://dotnetfiddle.net/qZekyp
edited Nov 15 '18 at 19:54
answered Nov 15 '18 at 19:40
Brian RogersBrian Rogers
77.5k18195209
77.5k18195209
I was hoping there was something more simple, but I had a feeling this was the direction I would need to go. Thanks a lot for the concrete solution as well.
– Brendan
Nov 15 '18 at 23:11
add a comment |
I was hoping there was something more simple, but I had a feeling this was the direction I would need to go. Thanks a lot for the concrete solution as well.
– Brendan
Nov 15 '18 at 23:11
I was hoping there was something more simple, but I had a feeling this was the direction I would need to go. Thanks a lot for the concrete solution as well.
– Brendan
Nov 15 '18 at 23:11
I was hoping there was something more simple, but I had a feeling this was the direction I would need to go. Thanks a lot for the concrete solution as well.
– Brendan
Nov 15 '18 at 23:11
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53326193%2fhow-to-custom-deserialize-into-an-object-with-json-net%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown