0

I have an API that accepts a simple class

public class MyPayload
{
 public string Id {get;set;}
 public JsonElement Payload {get;set;}
}

The Id of the payload tells the backend what class to create and the json Payload is the data to pass along. We are in the process of changing over to this API from basically a scripted solution. Sometimes the data coming in would be in the form of this json:

{
 "key":null
}

In the scripted solution we could handle the null pretty simply, and pass back the default value for the provided key. The problem on switching to the API is that "key" has a type, string, or int, or bool but what happens when this is passed into the API I'm getting the following error message:

The JSON value could not be converted to System.Boolean. Path: $.Key | LineNumber: 5 | BytePositionInLine: 38.

One of the things I tried was using [JsonIgnore(Condition = JsonIgnoreCondition.Never)], I actually played with all the ignorecondition options. Basically when "key" == null then "key" was omitted from the output instead of the default value as expected. I've tried several things but as the value is coming in null and not like a type or whatever it's failing.

Ok, I am editing this a little bit as when I originally wrote it I left out I think some vital information, or perhaps wasn't terribly clear. The API references another project that contains the classes that I'm creating via the json payload. These are the classes throwing the error above. For clarity I will post two different versions of said class so you all can see what I've tried.

In the first class below the error is thrown.

public class MyClass
{
  public string? Key {get;set;} = "default value";
  public bool? IsThing {get;set;} = false;
}

In this instance, the null is passed along, but the default is not used, and there are a few versions of JsonIgnoreCondition where the propery is omitted altogether.

public class MyClass
{
  [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
  public string? Key {get;set;} = "default value";
  [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
  public bool? IsThing {get;set;} = false;
}

The following updated class follows the old style getter/setter from @ismail. I shortened this to a single property for brevity.

public class MyClass
{
  private bool? _IsThing; 
  public bool? IsThing
  {
   get
   {
    if (_IsThing == null)
    {
     // Default Value
     return true;
    }
    else
    {
     return _IsThing;
    }
   }
   set
   {
    if (value == null)
    {
     // Default Value
     _IsThing = true;
    }
    else
    {
     _IsThing = value;
    }
   }
  }
}

Thanks for looking!

Jeff Patton
  • 551
  • 4
  • 15
  • Have you tried Nullable? public Nullable variablename ? – Ismail Sep 03 '21 at 22:47
  • 1
    I'm a little confused, you have a `MyPayload` but the you are trying to send it `{ "key":null }` they are not even close? or is the json an example of the payload itself ? – TheGeneral Sep 03 '21 at 22:49
  • It's true; a `{ "key": null }` cannot be converted to `class Whatever{ public bool Key {get;set;} }`; make the `bool` a `bool?` – Caius Jard Sep 04 '21 at 08:25
  • @Ismail I have tried setting public string? Key and iirc it skipped output which is not what I need, if it gets passed in without a value i need to assign the default. – Jeff Patton Sep 04 '21 at 17:31
  • @TheGeneral Sorry if I was not clear, the json was an example of the payload itself. – Jeff Patton Sep 04 '21 at 17:31
  • @CaiusJard I believe that I tried this, but let me set that again and see what happens when i get back to my desk. – Jeff Patton Sep 04 '21 at 17:32
  • 1
    @JeffPatton here is one of my implementation see if you can make something out of it. public Nullable gST { get; set; } public Nullable GST { get { if (gST == null) { return (decimal)7.5; } else { return gST; } } set { if (value == null) { gST = (decimal)7.5; } else { gST = value; } } } – Ismail Sep 04 '21 at 18:57
  • @JeffPatton I just found out that string can not be Nullable so it has to be public string name in case of string. – Ismail Sep 04 '21 at 19:02
  • @ismail please don't advocate using properties that differ by case alone – Caius Jard Sep 04 '21 at 19:02
  • @Ismail string is a reference type; it's intrinsically nullable – Caius Jard Sep 04 '21 at 19:03
  • @CaiusJard alright – Ismail Sep 04 '21 at 19:04
  • @JeffPatton what is "the default" in your opinion? (It seems to differ from what c#'s opinion of `default` is). Also, `string?` might be valid syntax if your c# is 8+ but it's for a slightly different purpose than a nullable value type such as `int?` - in a null aware context the compiler will allow you to make a `string?` null but will verify that you're handling it in a way that avoids NREs, see https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-reference-types – Caius Jard Sep 04 '21 at 19:05
  • @Ismail and Caius I've updated my original post with more details to elaborate on what I tried. – Jeff Patton Sep 07 '21 at 13:45
  • @Ismail I have updated my code with the sample you provided, but I'm getting an error ``` (CA2011) Do not assign the property within its setter. This call might result in an infinite recursion. ``` It appears that is exactly what is happening here. As the API will just sit debugger shows nothing and I assume at some point it will simply timeout. – Jeff Patton Sep 07 '21 at 14:11
  • @ismail what I needed to do is create the private backing field and assign it the values at that point it would appear then I can set the defaults. It appears thought that I'll need to create custom getter/setters for each class that has defaults. This is not a deal killer as much as a soul crusher ;) I was hoping to keep the code simpler like the update this morning. I will add my modification as a third example for clarity on what appears to be currently working in limited testing. – Jeff Patton Sep 07 '21 at 14:28

0 Answers0