C# REST API接收JSON含null值时类型转换错误问题咨询
问题根因
报错的核心原因是System.Text.Json(或Newtonsoft.Json)反序列化阶段,遇到JSON中明确传入的null值时,会先进行类型匹配校验:如果目标属性为不可空值类型(如bool/int未加?),会直接抛出类型转换错误,根本不会走到属性的赋值、默认值触发逻辑;如果目标为可空类型,会直接将null赋值给属性,覆盖你声明的初始默认值。而JsonIgnore系列配置仅控制序列化输出的忽略规则,对反序列化阶段的null值处理无效。
解决方案
方案1:可修改外部实体类代码
直接给需要处理null值的属性加对应JsonConverter即可,无需修改原有逻辑:
首先实现通用Null转默认值Converter:
using System.Text.Json; using System.Text.Json.Serialization; public class NullToDefaultConverter<T> : JsonConverter<T> { private readonly T _customDefault; // 无参构造用类型默认值 public NullToDefaultConverter() { _customDefault = default; } // 支持传入自定义默认值 public NullToDefaultConverter(T customDefault) { _customDefault = customDefault; } public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.Null) { return _customDefault; } return JsonSerializer.Deserialize<T>(ref reader, options); } public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { JsonSerializer.Serialize(writer, value, options); } }
然后给属性标记Converter即可:
public class MyClass { // null时返回自定义默认值 [JsonConverter(typeof(NullToDefaultConverter<string>), "default value")] public string Key {get;set;} // null时返回false [JsonConverter(typeof(NullToDefaultConverter<bool>), false)] public bool IsThing {get;set;} }
这种方式不需要属性声明为可空,null值会在反序列化转换阶段就被替换为默认值,不会抛出转换错误。
方案2:完全无法修改外部实体类代码
直接在反序列化入口配置全局JsonConverter即可,不需要改动实体类:
先实现Converter工厂,自动适配所有需要处理的类型:
public class NullToDefaultConverterFactory : JsonConverterFactory { // 自定义需要处理null转默认值的类型 private static readonly Type[] HandleTypes = new[] { typeof(string), typeof(bool), typeof(int), typeof(DateTime) }; public override bool CanConvert(Type typeToConvert) { return HandleTypes.Contains(typeToConvert) || (Nullable.GetUnderlyingType(typeToConvert) != null && HandleTypes.Contains(Nullable.GetUnderlyingType(typeToConvert))); } public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) { var actualType = Nullable.GetUnderlyingType(typeToConvert) ?? typeToConvert; var converter = Activator.CreateInstance(typeof(NullToDefaultConverter<>).MakeGenericType(actualType), // 这里可以配置各类型的默认值 actualType == typeof(string) ? "default value" : actualType == typeof(bool) ? false : Activator.CreateInstance(actualType)); return (JsonConverter)converter; } }
然后在你把JsonElement Payload反序列化为目标类型时,传入配置了该工厂的序列化选项:
var deserializeOptions = new JsonSerializerOptions { Converters = { new NullToDefaultConverterFactory() } }; var targetEntity = JsonSerializer.Deserialize(Payload.GetRawText(), targetType, deserializeOptions);
如果是ASP.NET Core项目,也可以全局注册该配置,所有接口反序列化自动生效:
// Program.cs builder.Services.AddControllers() .AddJsonOptions(opt => { opt.JsonSerializerOptions.Converters.Add(new NullToDefaultConverterFactory()); });
原有方案失效原因
- 可空属性加默认值:反序列化时JSON明确传入null,会直接覆盖属性的初始默认值
- JsonIgnore配置:仅控制序列化输出逻辑,不影响反序列化阶段的赋值
- 手写get/set:如果属性为不可空类型,反序列化时类型转换错误先触发,根本走不到set方法;如果是可空类型,你之前的写法理论上可以生效,前提是你没有在其他地方重置了字段值,或者你用的序列化器配置了跳过null值赋值的规则。
内容的提问来源于stack exchange,提问作者Jeff Patton
相关产品推荐
相关产品推荐

