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
相关产品推荐
相关产品推荐

