You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 06:36:02