You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 13:55:03