Avoid bind any number to bool property

試著忘記壹切 提交于 2021-01-27 06:03:40

问题


I have simple ASP.NET Core WebApi with model

public class Model
{
    public bool? Value {get; set;}
}

and endpoint

[HttpPost]
public async Task<IActionResult> Create([FromBody] Model model)

When I make a POST request with body

{
   "Value" : 7676
}

or

{
   "Value" : 2955454545645645645645645645654534534540    
}

then model.Value == true

How to avoid this? I need some error in this case, because 7676 is not the Boolean value.

I found this question and this, but solution is not fit for me, because I have a many models in different projects (so, it will hard to add JsonConverter attribute, from answer, to all properties)

Also, I'm looking for any docs that describes this behavior.


回答1:


You can achieve it by creating a custom JsonConverter. The documenation for the same can be found here

The reason for this behavior has got to do with the way JSON.NET or System.Text.JSON deserializes types. Since 123 can be converted to boolean true, deserialization is successful. It considers it to be true or false depending upon the integer value until you explicitly define a JsonConverter as below that checks the token being read is actually boolean.

If you aren't using Newtonsoft. You make use of System.Text.Json You can follow this page to create a custom JSON converter

public class OnlyBoolean : JsonConverter
{
     readonly JsonSerializer defaultSerializer = new JsonSerializer();

     public override bool CanConvert(Type objectType)
     {
         return objectType == typeof(bool);
     }

     public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
     {
         switch (reader.TokenType)
         {

             case JsonToken.Boolean:
             {
                 return defaultSerializer.Deserialize(reader, objectType);
             }
             case JsonToken.String:
             {
                 if (reader.Value?.ToString() == "true" || reader.Value?.ToString() == "false")
                      return defaultSerializer.Deserialize(reader, objectType);
                 else
                      throw new JsonSerializationException(string.Format("Token \"{0}\" of type {1} is not a boolean type", reader.Value, reader.TokenType));
            }
            case JsonToken.Integer:
            {
                if (Convert.ToInt32(reader.Value) == 1 || Convert.ToInt32(reader.Value) == 0)
                    return defaultSerializer.Deserialize(reader, objectType);
                else
                    throw new JsonSerializationException(string.Format("Token \"{0}\" of type {1} is not a boolean type", reader.Value, reader.TokenType));
            }
            default:
                      throw new JsonSerializationException(string.Format("Value\"{0}\" of type {1} is not a boolean type", reader.Value, reader.TokenType));
          }
      }

      public override bool CanWrite { get { return false; } }

      public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
      {
          throw new NotImplementedException();
      }
}

and then decorate your model as:

public class Model
{
    [JsonConverter(typeof(OnlyBoolean))]
    public bool? Value {get; set;}
}

or register it globally in Startup

services.AddMvc().AddJsonOptions(options => { options.SerializerSettings.Converters.Add(new OnlyBoolean());});


来源:https://stackoverflow.com/questions/59470631/avoid-bind-any-number-to-bool-property

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!