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

ASP.NET Core 6序列化枚举时如何启用EnumMember属性值?

问题描述

我定义了如下枚举:

using System.ComponentModel;
using System.Runtime.Serialization;
using Newtonsoft.Json;
using My.Custom.Namespace.Converters;

[TypeConverter(typeof(CustomEnumConverter<EFoo>))]
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
public enum EFoo
{
    [EnumMember(Value = "VALUE1")]
    Value1Enum = 1,
    
    [EnumMember(Value = "VALUE2")]
    Value2Enum = 2
}

该枚举用于ASP.NET Core MVC控制器返回的DTO中,例如通过return this.Ok(someDto)返回。

我期望序列化后的JSON格式为:

{
    "foo": "VALUE1",
    ...
}

但实际序列化结果为:

{
    "foo": "Value1Enum",
    ...
}

请问是否可以在不修改原枚举定义的前提下,强制ASP.NET在序列化枚举时使用EnumMember属性的值?

补充说明

  • 使用的框架为ASP.NET Core 6.0
  • 在Startup.cs中的JSON序列化相关配置如下:
services.AddControllersWithViews()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
    });

解决方案

问题原因

当前配置使用的是System.Text.Json的JsonStringEnumConverter,而枚举上标记的是Newtonsoft.Json(Json.NET)的特性,两者不兼容。ASP.NET Core 6默认使用System.Text.Json作为序列化器,因此枚举上的Newtonsoft特性不会生效,而是走全局配置的System.Text.Json转换器,导致输出枚举成员名称而非EnumMember指定的值。

可行方案(无需修改枚举定义)

方案1:自定义System.Text.Json枚举转换器,支持EnumMember属性

编写一个支持读取EnumMember值的自定义转换器,替换全局默认的枚举转换器:

using System;
using System.Reflection;
using System.Runtime.Serialization;
using System.Text.Json;
using System.Text.Json.Serialization;

public class EnumMemberStringEnumConverter : JsonStringEnumConverter
{
    public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
    {
        if (!typeToConvert.IsEnum)
            throw new ArgumentException("类型必须是枚举");

        return new EnumMemberConverter(typeToConvert);
    }

    private class EnumMemberConverter : JsonConverter<Enum>
    {
        private readonly Type _enumType;

        public EnumMemberConverter(Type enumType)
        {
            _enumType = enumType;
        }

        public override Enum Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            string value = reader.GetString();
            foreach (FieldInfo field in _enumType.GetFields())
            {
                if (Attribute.GetCustomAttribute(field, typeof(EnumMemberAttribute)) is EnumMemberAttribute attribute && attribute.Value == value)
                {
                    return (Enum)field.GetValue(null);
                }
            }
            // 找不到匹配值时,回退到枚举名称解析
            return (Enum)Enum.Parse(_enumType, value, ignoreCase: true);
        }

        public override void Write(Utf8JsonWriter writer, Enum value, JsonSerializerOptions options)
        {
            FieldInfo field = _enumType.GetField(value.ToString());
            if (Attribute.GetCustomAttribute(field, typeof(EnumMemberAttribute)) is EnumMemberAttribute attribute && !string.IsNullOrEmpty(attribute.Value))
            {
                writer.WriteStringValue(attribute.Value);
            }
            else
            {
                // 无EnumMember标记时,回退到枚举名称
                writer.WriteStringValue(value.ToString());
            }
        }
    }
}

修改Startup.cs中的配置,替换原转换器:

services.AddControllersWithViews()
    .AddJsonOptions(options =>
    {
        // 移除默认的枚举转换器
        var existingConverter = options.JsonSerializerOptions.Converters.FirstOrDefault(c => c is JsonStringEnumConverter);
        if (existingConverter != null)
        {
            options.JsonSerializerOptions.Converters.Remove(existingConverter);
        }
        // 添加自定义转换器
        options.JsonSerializerOptions.Converters.Add(new EnumMemberStringEnumConverter());
    });

方案2:切换为Newtonsoft.Json作为序列化器

如果更习惯使用Newtonsoft.Json,先安装Microsoft.AspNetCore.Mvc.NewtonsoftJson NuGet包,再修改Startup.cs配置:

services.AddControllersWithViews()
    .AddNewtonsoftJson(options =>
    {
        options.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter
        {
            AllowIntegerValues = false,
            CamelCaseText = false // 匹配EnumMember指定的大写格式,无需驼峰转换
        });
    });

此配置会让枚举上的[JsonConverter]特性生效,序列化时自动读取EnumMember的Value值输出。


内容的提问来源于stack exchange,提问作者Zdeněk

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 20:03:09