使用Newtonsoft JSON的TypeNameHandling反序列化返回默认值问题
问题根源
- 私有setter属性无法被Json.NET赋值:Subscription类的所有属性都是
private set,默认情况下Json.NET没有权限修改这些属性,反序列化后自然会得到默认值。 - 只读集合无法填充私有字段:
Alerts是只读属性,每次返回的都是_alerts的新列表,Json.NET无法直接将JSON中的数据写入私有字段_alerts。 - DateOnly类型可能缺少序列化支持:如果使用的Json.NET版本较旧,可能没有内置的DateOnly转换器,导致日期值反序列化失败。
解决办法
办法1:给私有成员添加[JsonProperty]标记
修改Subscription类,让Json.NET能够访问私有属性和字段:
public class Subscription : AggregateRoot { [JsonProperty("Alerts")] // 让Json.NET直接操作这个私有字段 private readonly List<Alert> _alerts = new(); [JsonProperty] // 标记后Json.NET可设置private setter的属性 public Guid UserId { get; private set; } [JsonProperty] public SubscriptionTier subscriptionTier { get; private set; } [JsonProperty] public SubscriptionPlan subscriptionPlan { get; private set; } [JsonProperty] public DateOnly StartDate { get; private set; } [JsonProperty] public DateOnly EndDate { get; private set; } [JsonProperty] public bool IsVaild { get; private set; } [JsonProperty] public decimal ComulativeTradingVolume24H { get; private set; } [JsonProperty] // 假设AggregateRoot的Id属性也是private set public Guid Id { get; private set; } public IReadOnlyList<Alert> Alerts => _alerts.AsReadOnly(); // 用AsReadOnly避免重复创建列表 }
办法2:使用带[JsonConstructor]的私有构造函数
通过构造函数传参初始化对象,无需修改属性的访问权限:
public class Subscription : AggregateRoot { private readonly List<Alert> _alerts = new(); public Guid UserId { get; private set; } public SubscriptionTier subscriptionTier { get; private set; } public SubscriptionPlan subscriptionPlan { get; private set; } public DateOnly StartDate { get; private set; } public DateOnly EndDate { get; private set; } public bool IsVaild { get; private set; } public decimal ComulativeTradingVolume24H { get; private set; } public Guid Id { get; private set; } public IReadOnlyList<Alert> Alerts => _alerts.AsReadOnly(); // 私有构造函数,添加[JsonConstructor]让Json.NET用它初始化对象 [JsonConstructor] private Subscription( Guid userId, SubscriptionTier subscriptionTier, SubscriptionPlan subscriptionPlan, DateOnly startDate, DateOnly endDate, bool isVaild, decimal comulativeTradingVolume24H, List<Alert> alerts, Guid id) { UserId = userId; this.subscriptionTier = subscriptionTier; this.subscriptionPlan = subscriptionPlan; StartDate = startDate; EndDate = endDate; IsVaild = isVaild; ComulativeTradingVolume24H = comulativeTradingVolume24H; _alerts = alerts ?? new List<Alert>(); Id = id; } // 保留业务逻辑需要的公共构造函数 public Subscription(Guid userId, SubscriptionTier tier, SubscriptionPlan plan, DateOnly startDate, DateOnly endDate) { UserId = userId; subscriptionTier = tier; subscriptionPlan = plan; StartDate = startDate; EndDate = endDate; IsVaild = true; ComulativeTradingVolume24H = 0; Id = Guid.NewGuid(); } }
办法3:添加DateOnly自定义转换器(若需要)
如果你的Json.NET版本不支持DateOnly,自定义转换器并添加到序列化设置中:
public class DateOnlyConverter : JsonConverter<DateOnly> { private const string DateFormat = "yyyy-MM-dd"; public override DateOnly ReadJson(JsonReader reader, Type objectType, DateOnly existingValue, bool hasExistingValue, JsonSerializer serializer) { return DateOnly.ParseExact(reader.Value.ToString(), DateFormat, CultureInfo.InvariantCulture); } public override void WriteJson(JsonWriter writer, DateOnly value, JsonSerializer serializer) { writer.WriteValue(value.ToString(DateFormat, CultureInfo.InvariantCulture)); } }
更新序列化和反序列化代码:
// 序列化 JsonConvert.SerializeObject(domainEvent, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All, Converters = { new DateOnlyConverter() } }); // 反序列化 var domainEvent = JsonConvert.DeserializeObject<IDomainEvent>( serializedDomainEvent, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All, Converters = { new DateOnlyConverter() } });
验证修改
完成修改后重新执行序列化和反序列化流程,检查Subscription对象的属性值是否正常填充,而非默认的空Guid、0等值。
内容的提问来源于stack exchange,提问作者Sulabee
相关产品推荐
相关产品推荐

