ASP.NET Core Web API基类参数无法获取派生通知属性问题
解决方案
不需要为每种通知类型单独编写控制器。问题根源是ASP.NET Core默认的JSON反序列化逻辑只会按照参数声明的基类类型解析数据,无法自动识别传入数据对应的派生类,只要配置好多态反序列化规则,就能自动识别通知类型、解析全部属性。
方案1:使用System.Text.Json内置多态反序列化(推荐,适用于.NET 7+版本)
ASP.NET Core默认使用System.Text.Json处理JSON序列化/反序列化,.NET 7开始原生支持多态反序列化配置,只需要给基类添加特性标注即可:
- 第一步:给
NotificationSuper基类添加多态配置特性,指定你已经定义的Type字段作为类型判别依据,同时注册所有派生类和对应的判别值:
using System.Text.Json.Serialization; // 指定用JSON中的Type字段作为类型判断依据 [JsonPolymorphic(TypeDiscriminatorPropertyName = nameof(NotificationSuper.Type))] // 注册所有通知类型,第二个参数为和Type字段值对应的标识,和Flutter端约定一致即可 [JsonDerivedType(typeof(NotificationSuper), "base")] [JsonDerivedType(typeof(UnitNotification), "unit")] [JsonDerivedType(typeof(MaintenanceNotification), "maintenance")] public class NotificationSuper { public string Title { get; set; } public string Body { get; set; } public string Token { get; set; } public string Type { get; set; } }
- 第二步:Flutter端传参时,必须给
Type字段传和后端约定好的对应值,比如发送维修类通知时Type字段传"maintenance",发送单元类通知时传"unit"。 - 控制器代码完全不需要修改,接口接收到请求后会自动把JSON反序列化为对应派生类的实例,所有派生类的独有属性都会被正确填充。后续业务逻辑中可以通过模式匹配识别具体类型做对应处理:
bool success = notification switch { MaintenanceNotification maintenanceNotify => await Notify.SendMaintenanceNotify(maintenanceNotify), UnitNotification unitNotify => await Notify.SendUnitNotify(unitNotify), _ => await Notify.SendCommonNotify(notification) };
- 后续新增通知类型时,只需要新建继承自对应基类的通知类,再在
NotificationSuper的JsonDerivedType特性中追加一行类型注册即可,不需要修改控制器、不需要新增接口。
方案2:自定义JSON转换器(适用于.NET 6及更低版本)
如果项目使用.NET 6及更早版本,没有内置多态反序列化特性,可以自定义JSON转换器实现同样的逻辑:
- 第一步:编写自定义转换器,逻辑是先读取JSON中的
Type字段值,根据约定的映射关系找到对应的目标类型,再执行反序列化:
public class NotificationConverter : JsonConverter<NotificationSuper> { public override NotificationSuper Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { using var doc = JsonDocument.ParseValue(ref reader); var root = doc.RootElement; // 读取Type字段值 var type = root.GetProperty("Type").GetString(); return type switch { "maintenance" => root.Deserialize<MaintenanceNotification>(options), "unit" => root.Deserialize<UnitNotification>(options), _ => root.Deserialize<NotificationSuper>(options) }; } public override void Write(Utf8JsonWriter writer, NotificationSuper value, JsonSerializerOptions options) { JsonSerializer.Serialize(writer, value, value.GetType(), options); } }
- 第二步:把转换器注册到全局JSON配置中,在Program.cs里添加配置:
builder.Services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.Converters.Add(new NotificationConverter()); });
该方案效果和方案1完全一致,后续新增通知类型只要在转换器的switch分支中添加对应映射即可。
注意事项
- 不推荐使用Newtonsoft.Json的
TypeNameHandling配置实现自动多态反序列化,该配置存在远程代码执行安全风险。 - 前后端必须严格约定
Type字段的传值规则,传值和后端映射不匹配时会导致反序列化失败。
内容的提问来源于stack exchange,提问作者Abanoub Refaat
相关产品推荐
相关产品推荐

