【问题标题】:Avoid bind any number to bool property避免将任何数字绑定到布尔属性
【发布时间】:2020-04-15 15:30:26
【问题描述】:

我有简单的带有模型的 ASP.NET Core WebApi

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

和端点

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

当我使用正文发出 POST 请求时

{
   "Value" : 7676
}

{
   "Value" : 2955454545645645645645645645654534534540    
}

然后model.Value == true

如何避免这种情况?在这种情况下我需要一些错误,因为7676 不是布尔值。

我找到了this questionthis,但解决方案不适合我,因为我在不同的项目中有很多模型(因此,很难将 JsonConverter 属性从答案添加到所有属性)

另外,我正在寻找任何描述这种行为的文档。

【问题讨论】:

  • 编写自定义模型绑定器并使用它
  • 当您尝试发布无效的 Json 属性值时,您应该会收到类似“无法将 JSON 值转换为 System.Nullable`1[System.Boolean]。路径:$.Value”的错误。您使用的是哪个版本的 asp.net core?
  • @vendettamit 是的,我也这么认为,但行为就像我描述的那样。 ASP.NET Core 2.2
  • @Milney 你能帮忙定制模型活页夹吗?我有很多模型,我可以为所有模型中的布尔属性创建活页夹吗?我试过这个docs.microsoft.com/en-us/aspnet/core/mvc/advanced/…,但总是得到ValueProviderResult.None
  • 创建一个从JsonConverter派生的自定义MyBookConverter,然后注册services.AddMvc().AddJsonOptions(options =&gt; { options.SerializerSettings.Converters.Add(new MyBoolConverter());});

标签: c# asp.net-core asp.net-web-api asp.net-core-webapi


【解决方案1】:

您可以通过创建自定义 JsonConverter 来实现。可以找到相同的文档here

这种行为的原因与 JSON.NET 或 System.Text.JSON 反序列化类型的方式有关。由于123可以转换为booleantrue,所以反序列化成功。它根据整数值认为它是真还是假,直到您显式定义如下的 JsonConverter 来检查正在读取的令牌实际上是布尔值。

如果您不使用 Newtonsoft。你用System.Text.Json你可以关注这个页面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();
      }
}

然后将模型装饰为:

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

或在 Startup 中全局注册

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

【讨论】:

  • @Chebur 我已经编辑它以接受“true”“false”1 和 0 作为有效输入。这能回答你的问题吗?
  • 很好的答案。你知道这是否有一个等效的 asp.net 框架吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-21
  • 2011-08-26
  • 2016-09-26
  • 1970-01-01
相关资源
最近更新 更多