Blazor Server(.NET 6)序列化反序列化因循环引用致数据丢失崩溃
解决方案
核心问题分析
你遇到的问题本质是EF Core实体/DTO的循环引用导致序列化逻辑破坏对象结构:直接序列化触发循环引用错误,用ReferenceLoopHandling.Ignore会直接丢弃循环关联的字段,导致反序列化时对象结构不完整,进而引发访问冲突崩溃。
1. 用纯DTO剥离循环引用与EF代理
不要直接使用EF Core实体类作为序列化对象,专门定义只包含业务所需字段的纯DTO,移除反向导航属性(这是循环引用的主要来源):
示例实体类(带循环引用)
// EF实体类(存在循环引用) public class RequestDetail { public int Id { get; set; } public string Title { get; set; } // 反向导航引发循环 public ICollection<RequestAttachment> Attachments { get; set; } } public class RequestAttachment { public int Id { get; set; } public string FileName { get; set; } // 关联父实体,形成循环 public RequestDetail RequestDetail { get; set; } }
对应纯DTO(无循环)
// 纯传输DTO,仅保留必要字段 public class RequestDetailDTO { public int Id { get; set; } public string Title { get; set; } // 仅包含子DTO,移除反向引用 public List<RequestAttachmentDTO> Attachments { get; set; } } public class RequestAttachmentDTO { public int Id { get; set; } public string FileName { get; set; } // 去掉RequestDetail引用,切断循环 }
2. 使用.NET 6+推荐的循环引用处理方式
放弃ReferenceLoopHandling.Ignore,改用ReferenceHandler.IgnoreCycles(.NET 6新增),它会跳过循环引用但不会直接丢弃字段,而是将循环节点设为null,保证对象结构完整:
序列化配置示例
// 序列化时的配置 var serializeOptions = new JsonSerializerOptions { ReferenceHandler = ReferenceHandler.IgnoreCycles, WriteIndented = true }; // 将DTO序列化为JSON并存入Session var json = JsonSerializer.Serialize(myRequestDetailDTO, serializeOptions); await HttpContext.Session.SetStringAsync("request", json);
反序列化配置示例
// 读取Session并反序列化 var json = await HttpContext.Session.GetStringAsync("request"); var dto = JsonSerializer.Deserialize<RequestDetailDTO>(json, serializeOptions);
3. 避免序列化EF代理对象
如果是直接从EF查询获取的实体,需禁用EF动态代理,防止序列化时带入额外的循环引用:
// 查询时禁用代理+追踪 var requestEntity = await _dbContext.RequestDetails .Include(r => r.Attachments) .AsNoTracking() // 禁用追踪,避免代理 .FirstOrDefaultAsync(r => r.Id == requestId); // 手动映射为纯DTO var dto = new RequestDetailDTO { Id = requestEntity.Id, Title = requestEntity.Title, Attachments = requestEntity.Attachments.Select(a => new RequestAttachmentDTO { Id = a.Id, FileName = a.FileName }).ToList() };
4. 检查Session序列化方式(针对Newtonsoft.Json场景)
如果你的项目用Newtonsoft.Json替代默认的System.Text.Json,需调整配置:
// Startup/Program.cs中配置Session的序列化 services.AddSession(options => { options.IdleTimeout = TimeSpan.FromMinutes(30); options.Cookie.HttpOnly = true; }) .AddNewtonsoftJsonSerializer(options => { options.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; // 保留对象引用,避免循环同时不丢失数据 options.PreserveReferencesHandling = PreserveReferencesHandling.Objects; });
内容的提问来源于stack exchange,提问作者USMC6072
相关产品推荐
相关产品推荐

