C# .NET5 REST API OData下多态JSON转换器400输入无效问题求解
解决方案
该问题本质是OData默认使用独立的序列化/反序列化管道,且EDM未显式声明继承层级时,会提前校验请求结构并拦截,导致全局配置的自定义JsonConverter不会被触发,可按以下步骤配置:
1. 显式在EDM模型中声明类继承关系
在构建EDM模型时,除了原有QuizQuestionDto的注册外,需要主动声明QuizOptionDto及其子类的继承关系:
private static IEdmModel GetEdmModel() { var builder = new ODataConventionModelBuilder(); // 若QuizOptionDto是独立实体则用EntityType,若是依附于其他类的复杂属性则用ComplexType builder.ComplexType<QuizOptionDto>(); // 显式声明派生类的继承关系 builder.ComplexType<TextOptionDto>().DerivesFrom<QuizOptionDto>(); builder.ComplexType<ImageOptionDto>().DerivesFrom<QuizOptionDto>(); // 保留原有的QuizQuestionDto注册 builder.EntitySet<QuizQuestionDto>("QuizQuestions"); return builder.GetEdmModel(); }
2. 配置OData使用NewtonsoftJson并继承全局序列化设置
OData默认使用System.Text.Json作为序列化组件,你全局配置的NewtonsoftJson参数不会自动传入OData管道,需要手动配置替换:
services.AddControllers() .AddNewtonsoftJson(options => { // 原有全局配置 options.SerializerSettings.TypeNameHandling = TypeNameHandling.All; options.SerializerSettings.Converters.Add(new QuizOptionJsonConverter()); }) .AddOData(options => { // 保留原有OData查询功能配置 options.Select().Filter().OrderBy().Expand().Count().SetMaxTop(100); // 配置OData路由,注入NewtonsoftJson序列化提供器 options.AddRouteComponents("odata", GetEdmModel(), svc => { svc.AddSingleton<IODataSerializerProvider, NewtonsoftJsonODataSerializerProvider>(); svc.AddSingleton<IODataDeserializerProvider, NewtonsoftJsonODataDeserializerProvider>(); // 传入和全局一致的序列化配置 svc.AddSingleton(new ODataNewtonsoftJsonSerializerSettings { SerializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All, Converters = { new QuizOptionJsonConverter() } } }); }); }); // 可选:若仍存在请求提前被校验拦截的问题,可关闭OData内置模型校验 services.Configure<ODataOptions>(opt => { opt.ValidateFeature = null; });
3. 校验自定义JsonConverter的CanConvert逻辑
确保转换器的类型判断逻辑适配OData管道传入的类型:
public override bool CanConvert(Type objectType) { // 支持基类及其所有子类的转换 return typeof(QuizOptionDto).IsAssignableFrom(objectType); }
以上配置适配OData 8.x + .NET 5运行环境,配置完成后即可同时保留OData功能和多态反序列化能力。
内容的提问来源于stack exchange,提问作者Giovanni
相关产品推荐
相关产品推荐

