Blazor Web App使用Syncfusion ComboBox遭遇JSON循环引用问题
解决Blazor中Syncfusion ComboBox循环引用JSON序列化错误
问题场景
我基于EF Core开发Blazor Web App,在页面使用Syncfusion ComboBox展示数据时,触发了循环引用导致的JSON序列化错误。
ComboBox代码:
<SfComboBox TValue="Contact" TItem="Contact" @bind-Value="item.Owner" DataSource="Contacts" Placeholder="Besitzer"> <ComboBoxFieldSettings Value="@nameof(Contact.FullName)"></ComboBoxFieldSettings> </SfComboBox>
错误追踪
Error: System.Text.Json.JsonException: 检测到可能的对象循环。这可能是由于循环引用,或者对象深度超过了允许的最大深度64。请考虑在JsonSerializerOptions上使用ReferenceHandler.Preserve来支持循环引用。路径: $.Items.Owner.Items.Owner.Items.Owner.Items.Owner.Items.Owner.Items ... ... JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.JsonConverter`1.WriteCore(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.Serialize(Utf8JsonWriter writer, T& rootValue, Object rootValueBoxed) at System.Text.Json.JsonSerializer.WriteString[TValue](TValue& value, JsonTypeInfo`1 jsonTypeInfo) at System.Text.Json.JsonSerializer.Serialize[TValue](TValue value, JsonSerializerOptions options) at Syncfusion.Blazor.DropDowns.SfDropDownList`2.GetDataByValue(TValue ddlValue) at Syncfusion.Blazor.DropDowns.SfDropDownList`2.InitValueAsync() at Syncfusion.Blazor.DropDowns.SfDropDownList`2.OnAfterRenderAsync(Boolean firstRender) at Syncfusion.Blazor.DropDowns.SfComboBox`2.OnAfterRenderAsync(Boolean firstRender) at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)
已尝试的无效配置
我曾配置JSON引用处理,但未生效:
builder.Services.Configure<Microsoft.AspNetCore.Http.Json.JsonOptions>(options => options.SerializerOptions.ReferenceHandler = ReferenceHandler.Preserve); builder.Services.ConfigureHttpJsonOptions(jsonOptions => { jsonOptions.SerializerOptions.ReferenceHandler = ReferenceHandler.Preserve; });
实体类定义
public class Item { public Contact Owner { get; set; } } public class Contact { public List<Item> Items { get; set; } = new List<Item>(); }
解决方案
方案1:禁用EF Core延迟加载(推荐)
循环引用的根源是EF Core默认的延迟加载机制——加载Contact时会自动拉取关联的Items,每个Item又关联回Contact,形成无限循环。可以通过两种方式解决:
- 全局禁用延迟加载:
builder.Services.AddDbContext<YourDbContext>(options => options.UseSqlServer("你的连接字符串") .UseLazyLoadingProxies(false)); // 关闭延迟加载代理
- 单个查询层面禁用:
// 不加载关联的Items集合 var contacts = await _dbContext.Contacts.AsNoTracking().ToListAsync(); // 或者仅选择ComboBox需要的字段 var contacts = await _dbContext.Contacts.Select(c => new Contact { Id = c.Id, FullName = c.FullName // 不包含Items属性,切断循环 }).ToListAsync();
方案2:为Syncfusion组件单独配置序列化选项
你之前配置的是HTTP请求的JSON序列化选项,但Syncfusion组件内部使用独立的配置。需要通过SyncfusionBlazorOptions设置:
builder.Services.AddSyncfusionBlazor(options => { options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve; });
方案3:使用DTO(数据传输对象)
创建仅包含ComboBox所需字段的DTO类,彻底切断循环引用:
public class ContactDto { public int Id { get; set; } public string FullName { get; set; } }
查询时转换为DTO:
var contactDtos = await _dbContext.Contacts.Select(c => new ContactDto { Id = c.Id, FullName = c.FullName }).ToListAsync();
修改ComboBox的类型适配DTO:
<SfComboBox TValue="ContactDto" TItem="ContactDto" @bind-Value="selectedOwner" DataSource="contactDtos" Placeholder="Besitzer"> <ComboBoxFieldSettings Value="@nameof(ContactDto.FullName)"></ComboBoxFieldSettings> </SfComboBox>
内容的提问来源于stack exchange,提问作者Steini
相关产品推荐
相关产品推荐

