.NET5/.NET Core 如何自定义OData序列化器实现枚举标志转数组
OData 8.0.2 枚举标志位转数组输出实现方案
问题原因
Microsoft.AspNetCore.OData 8.x 版本使用独立的隔离容器管理自身服务,直接向ASP.NET Core根服务集合注册ODataPayloadValueConverter或自定义序列化提供器不会被OData组件读取,这是你之前的代码无法触发执行的核心原因。
完整实现步骤
1. 实现自定义枚举序列化器
针对带[Flags]特性的枚举,将其拆分为数组格式输出:
public class EnumFlagODataSerializer : ODataEdmTypeSerializer { public EnumFlagODataSerializer(IODataSerializerProvider serializerProvider) : base(ODataPayloadKind.Property) { } public override void WriteObject(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext) { if (graph is Enum flagEnum) { var enumType = graph.GetType(); // 仅处理带Flags特性的枚举,普通枚举走默认逻辑 if (!enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any()) { base.WriteObject(graph, type, messageWriter, writeContext); return; } // 拆分所有匹配的标志位,过滤None值(值为0的项) var enumValues = Enum.GetValues(enumType).Cast<Enum>(); var result = enumValues.Where(v => flagEnum.HasFlag(v) && Convert.ToInt64(v) != 0).ToList(); // 写入数组格式结果 messageWriter.WritePrimitiveValue(result); return; } base.WriteObject(graph, type, messageWriter, writeContext); } }
2. 实现自定义序列化提供器
替换默认的枚举类型序列化器为自定义实现:
public class CustomODataSerializerProvider : ODataSerializerProvider { private readonly EnumFlagODataSerializer _enumFlagSerializer; public CustomODataSerializerProvider(IServiceProvider rootContainer) : base(rootContainer) { _enumFlagSerializer = new EnumFlagODataSerializer(this); } public override IODataEdmTypeSerializer GetEdmTypeSerializer(IEdmTypeReference edmType) { // 匹配所有枚举类型,返回自定义序列化器 if (edmType.IsEnum()) { return _enumFlagSerializer; } return base.GetEdmTypeSerializer(edmType); } }
3. 正确注册自定义服务
必须在OData路由组件的配置内注册自定义服务,替换默认实现:
builder.Services.AddControllers() .AddOData(options => { // 保留你原有OData配置,比如查询能力、EDM模型配置等 options.Select().Filter().OrderBy().Expand().Count().SetMaxTop(100); // 注册路由组件时注入自定义服务 options.AddRouteComponents("odata", GetEdmModel(), odataServices => { // 替换默认序列化提供器 odataServices.AddSingleton<IODataSerializerProvider, CustomODataSerializerProvider>(); }); });
可选:添加反序列化支持
如果需要支持前端传入枚举数组自动合并为标志位,补充以下实现:
自定义枚举反序列化器
public class EnumFlagODataDeserializer : ODataEdmTypeDeserializer { public EnumFlagODataDeserializer(IODataDeserializerProvider deserializerProvider) : base(ODataPayloadKind.Property) { } public override object ReadInline(object value, IEdmTypeReference edmType, ODataDeserializerContext readContext) { if (value is Newtonsoft.Json.Linq.JArray arr) { var enumType = edmType.AsEnum().GetClrType(); long resultValue = 0; foreach (var item in arr) { var enumVal = Enum.Parse(enumType, item.ToString()); resultValue |= Convert.ToInt64(enumVal); } return Enum.ToObject(enumType, resultValue); } return base.ReadInline(value, edmType, readContext); } }
自定义反序列化提供器
public class CustomODataDeserializerProvider : ODataDeserializerProvider { private readonly EnumFlagODataDeserializer _enumDeserializer; public CustomODataDeserializerProvider(IServiceProvider rootContainer) : base(rootContainer) { _enumDeserializer = new EnumFlagODataDeserializer(this); } public override IODataEdmTypeDeserializer GetEdmTypeDeserializer(IEdmTypeReference edmType) { if (edmType.IsEnum()) { return _enumDeserializer; } return base.GetEdmTypeDeserializer(edmType); } }
注册反序列化服务
在AddRouteComponents的odataServices配置块中添加以下注册代码:
odataServices.AddSingleton<IODataDeserializerProvider, CustomODataDeserializerProvider>();
内容的提问来源于stack exchange,提问作者Driftya
相关产品推荐
相关产品推荐

