文章目录
- 一、前言
- 二、对象递归引用Json序列化异常案例
-
- 1、领域层对象关系:
- 2、应用层对象关系:
- 3.1、关联查询方式:AbpVnext
- 3.2、关联查询方式:Abp
- 4、查询结果Json序列化异常:
- 5、解决方案:
- 三、总结
一、前言
应用层涉及到从数据库提取数据记录,转换成对应的DTO,然后框架自动Json序列化,返回前端;
在Domain领域层创建的领域对象DO通常带有关系绑定,1:1 或者1:N , 自然Application应用层的数据传输对象 DTO也会带有与之对应关系的DTO;
当查询A记录 想要把A记录关联的B记录也一并查询并返回的时候,记录查询虽然成功,但是在进行Json序列化的时候会提示要转换的对象出现循环递归引用,且超过最大32层循环嵌套深度,直接报JsonException异常。
二、对象递归引用Json序列化异常案例
1、领域层对象关系:
//巡航类 Cruise.cs
public class Cruise : Entity<int>, IHasCreationTime, IHasModificationTime
{
/// <summary>
/// 区域巡检点列表:1条路径多个巡检点
/// </summary>
public virtual List<Cruise_Points> Cruise_Points { get; set; }
}
//巡检点:Cruise_Points.cs
public class Cruise_Points : Entity<int>, IHasModificationTime, IHasCreationTime
{
/// <summary>
/// 预置巡航ID
/// </summary>
public virtual int Cruise_Id { get; set; }
[ForeignKey("Cruise_Id")]
public virtual Cruise Cruise { get; set; }
}
//巡检日志:Device_Warns.cs
public class Device_Warns : Entity<int>, IHasCreationTime, IHasModificationTime
{
/// <summary>
/// 巡检路径id:预置巡航/区域巡航
/// </summary>
public int? CruiseId { get; set; }
[ForeignKey("CruiseId")]
public Cruise Cruise { get; set; }
/// <summary>
/// 巡检点位id:预置巡检点位/区域巡检点位
/// </summary>
public int? CruisePointId { get; set; }
[ForeignKey("CruisePointId")]
public Cruise_Points Cruise_Point { get; set; }
}
2、应用层对象关系:
//CruiseDto.cs:巡检路径
public class CruiseDto : EntityDto<int>
{
/// <summary>
/// 区域巡检点列表 区域巡检点列表:1条路径多个巡检点
/// </summary>
public List<CruisePointDto> Cruise_Points { get; set; }
}
//CruisePointDto.cs:巡检点位
public class CruisePointDto : EntityDto<int>
{
/// <summary>
/// 巡航路径ID
/// </summary>
public virtual int Cruise_Id { get; set; }
public CruiseDto Cruise { get; set; }
}
//WarnsDto.cs:告警记录中包含 巡检路径 和巡检点位
public class WarnsDto : EntityDto<int>
{
/// <summary>
/// 巡检路径id:预置巡航/区域巡航
/// </summary>
public int CruiseId { get; set; }
/// <summary>
/// 预置巡航记录
/// </summary>
public virtual CruiseDto Cruise { get; set; }
/// <summary>
/// 巡检点位id:预置巡检点位/区域巡检点位
/// </summary>
public int CruisePointId { get; set; }
/// <summary>
/// 区域巡航 巡检点
/// </summary>
public CruisePointDto Cruise_Point { get; set; }
}
3.1、关联查询方式:AbpVnext
public class WarnsAppService : CrudAppService<Device_Warns, WarnsDto, int, WarnsPagedResultRequestDto, CreateWarnsDto, WarnsDto>, IWarnsAppService
{
public WarnsAppService(IRepository<Device_Warns, int> repository) : base(repository)
{
}
/// <summary>
/// 重新翻页查询
/// </summary>
protected override IQueryable<Device_Warns> CreateFilteredQuery(WarnsPagedResultRequestDto input)
{
return this.ReadOnlyRepository.WithDetails(p=>p.Device,p => p.Cruise,prop=>prop.Cruise_Point)
.WhereIf(input.Device_Id != null, p => p.Device_Id == input.Device_Id);
}
}
}
//注意代码中的 this.ReadOnlyRepository.WithDetails
3.2、关联查询方式:Abp
//类似这种写法
return await _context.Device_Warns.Include(p => p.Cruise,P.Cruise_Point).FirstOrDefaultAsync(p=>p.id=2);
4、查询结果Json序列化异常:
提示递归应用嵌套,超过Json序列化最大嵌套深度;
System.Text.Json.JsonException: A possible object cycle was detected which is not supported. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32.
at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_SerializerCycleDetected(Int32 maxDepth)
at System.Text.Json.JsonSerializer.Write(Utf8JsonWriter writer, Int32 originalWriterDepth, Int32 flushThreshold, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.JsonSerializer.WriteAsyncCore(Stream utf8Json, Object value, Type inputType, JsonSerializerOptions options, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
— End of stack trace from previous location where exception was thrown —
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
5、解决方案:
在应用层 GasMonitoringApplicationAutoMapperProfile.cs 文件中添加实体类转换配置
public class GasMonitoringApplicationAutoMapperProfile : Profile
{
public GasMonitoringApplicationAutoMapperProfile()
{
CreateMap<Cruise, CruiseDto>()
.ForMember(x=>x.Cruise_Points,opt=>opt.Ignore());
CreateMap<CruiseDto, Cruise>(MemberList.Source); //以Dto数据为准进行转换
CreateMap<CreateCruiseDto, Cruise>(MemberList.Source); //只检测Dto中属性 Validate
}
}
}
.ForMember(x=>x.Cruise_Points,opt=>opt.Ignore()); 可有效解决循环递归引用问题
但是也会存在问题 在Cruise查询的时候 就无法关联查询出对应的 Cruise_Points 列表了:不过这种查询需求一般不会有
三、总结
网上还有其他若干方法,比如在某个关联属性上面添加 [JsonIgnore]属性以忽略Json序列化;
又或者引入Microsoft.AspNetCore.Mvc.NewtonsoftJson 包,然后Startup中添加 Json序列化忽略递归引用;
参考文章:https://www.mmbyte.com/article/142486.html