System.DateTime字段出现嵌套日期导致栈溢出该如何解决
问题原因
System.DateTime本身不存在原生嵌套结构,出现该问题的常见诱因如下:
- 序列化组件配置冲突:同时启用了
System.Text.Json和Newtonsoft.Json(Json.NET)的序列化适配,两者对DateTime的序列化规则不一致,反复触发类型转换逻辑导致递归嵌套 - 实体类存在循环引用:DateTime字段所在的实体和其他实体存在双向导航属性,序列化时未禁用循环引用处理,递归序列化过程中错误生成了嵌套的日期结构
- 自定义JsonConverter逻辑错误:自行实现的DateTime类型自定义转换器存在逻辑漏洞,比如转换器内部又调用了
JsonSerializer.Serialize处理DateTime类型,触发无限递归
解决方案
1. 统一序列化组件配置
如果使用.NET Core 3.0+默认的System.Text.Json,在Program.cs(旧版本为Startup.cs的ConfigureServices方法)中明确配置序列化规则,避免多组件冲突:
// .NET 6+ 顶层语句配置示例 builder.Services.AddControllers() .AddJsonOptions(options => { // 忽略循环引用 options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles; // 明确指定DateTime序列化格式 options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; });
如果使用Newtonsoft.Json,需移除System.Text.Json的默认配置,仅保留Newtonsoft相关配置:
builder.Services.AddControllers() .AddNewtonsoftJson(options => { // 忽略循环引用 options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; // 明确DateTime序列化格式 options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; });
2. 处理实体类循环引用
如果实体类存在双向关联,给不需要序列化的关联属性添加[JsonIgnore]特性,避免序列化时递归遍历:
public class Order { public int Id { get; set; } public DateTime CreateTime { get; set; } // 双向导航属性加JsonIgnore避免循环序列化 [JsonIgnore] public ICollection<OrderItem> Items { get; set; } }
3. 修复自定义DateTime转换器逻辑
如果自定义了DateTime的JsonConverter,检查是否存在递归调用,直接处理字符串和DateTime的转换即可,不要再次调用序列化方法:
错误写法示例(会触发递归):
public class BadDateTimeConverter : JsonConverter<DateTime> { public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 内部又调用默认序列化处理DateTime,重复触发当前转换器 return JsonSerializer.Deserialize<DateTime>(ref reader, options); } }
正确写法示例:
public class CorrectDateTimeConverter : JsonConverter<DateTime> { private const string Format = "yyyy-MM-dd HH:mm:ss"; public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.String && DateTime.TryParseExact(reader.GetString(), Format, CultureInfo.InvariantCulture, DateTimeStyles.None, out var date)) { return date; } return reader.GetDateTime(); } public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) { writer.WriteStringValue(value.ToString(Format, CultureInfo.InvariantCulture)); } }
4. 快速排查方案
暂时给出现嵌套问题的DateTime字段添加[JsonIgnore]特性,验证栈溢出是否由该字段序列化导致,再逐步缩小排查范围。
内容的提问来源于stack exchange,提问作者BeniaminoBaggins
相关产品推荐
相关产品推荐

