How to custom deserialize into an object with json.net












1















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.










share|improve this question



























    1















    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.










    share|improve this question

























      1












      1








      1








      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.










      share|improve this question














      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






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 15 '18 at 18:56









      BrendanBrendan

      155




      155
























          1 Answer
          1






          active

          oldest

          votes


















          1














          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






          share|improve this answer


























          • 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











          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
          });


          }
          });














          draft saved

          draft discarded


















          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









          1














          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






          share|improve this answer


























          • 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
















          1














          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






          share|improve this answer


























          • 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














          1












          1








          1







          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






          share|improve this answer















          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







          share|improve this answer














          share|improve this answer



          share|improve this answer








          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



















          • 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




















          draft saved

          draft discarded




















































          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.




          draft saved


          draft discarded














          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





















































          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







          Popular posts from this blog

          The Sandy Post

          Danny Elfman

          Pages that link to "Head v. Amoskeag Manufacturing Co."