.NET 7 API如何配置支持大写下划线格式的枚举查询参数?
解决.NET 7 API查询参数中大写下划线枚举值的绑定问题
你配置的JsonStringEnumConverter仅对**请求体(JSON格式)**生效,查询参数的模型绑定逻辑独立于JSON序列化,因此需要单独配置枚举转换规则。以下是两种可行方案:
方案一:自定义枚举模型绑定器(推荐,无需修改枚举定义)
该方案通过自定义模型绑定逻辑,自动将大写下划线格式的查询参数转换为对应的C#枚举值。
1. 实现枚举模型绑定器
using Microsoft.AspNetCore.Mvc.ModelBinding; using System.Text.RegularExpressions; public class SnakeCaseUpperEnumModelBinder : IModelBinder { public Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext == null) throw new ArgumentNullException(nameof(bindingContext)); var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); if (valueProviderResult == ValueProviderResult.None) return Task.CompletedTask; bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult); var inputValue = valueProviderResult.FirstValue; if (string.IsNullOrEmpty(inputValue)) return Task.CompletedTask; var enumType = bindingContext.ModelType; if (!enumType.IsEnum) return Task.CompletedTask; // 将大写下划线转为帕斯卡命名(匹配C#枚举名称) var normalizedValue = Regex.Replace(inputValue.ToLower(), @"_([a-z])", match => match.Groups[1].Value.ToUpper()); normalizedValue = char.ToUpper(normalizedValue[0]) + normalizedValue.Substring(1); if (Enum.TryParse(enumType, normalizedValue, out var enumResult)) { bindingContext.Result = ModelBindingResult.Success(enumResult); } else { bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, $"无效的枚举值:{inputValue}"); } return Task.CompletedTask; } }
2. 实现绑定器提供者
using Microsoft.AspNetCore.Mvc.ModelBinding; public class SnakeCaseUpperEnumModelBinderProvider : IModelBinderProvider { public IModelBinder? GetBinder(ModelBinderProviderContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); if (context.Metadata.ModelType.IsEnum) return new SnakeCaseUpperEnumModelBinder(); return null; } }
3. 注册绑定器到服务
在Program.cs中添加绑定器配置,确保优先级高于默认绑定器:
builder.Services.AddControllers(options => { // 插入自定义枚举绑定器到最前面 options.ModelBinderProviders.Insert(0, new SnakeCaseUpperEnumModelBinderProvider()); }) .AddJsonOptions(options => { // 保留原有的JSON序列化配置 options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicies.SnakeCaseUpper)); });
方案二:使用EnumMember属性标记枚举值
该方案通过给C#枚举添加属性,指定对应的大写下划线字符串值,让模型绑定识别这些值。
1. 标记枚举属性
using System.Runtime.Serialization; using System.ComponentModel; // 添加类型转换器,让模型绑定识别EnumMember的Value [TypeConverter(typeof(EnumMemberTypeConverter<UserStatus>))] public enum UserStatus { [EnumMember(Value = "ACTIVE")] Active, [EnumMember(Value = "AWAITING_ROLE_ASSIGNMENT")] AwaitingRoleAssignment, [EnumMember(Value = "AWAITING_EMAIL_CONFIRMATION")] AwaitingEmailConfirmation }
2. 实现类型转换器
using System.ComponentModel; using System.Globalization; using System.Runtime.Serialization; public class EnumMemberTypeConverter<TEnum> : TypeConverter where TEnum : struct, Enum { public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) { return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); } public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) { if (value is string inputValue) { var enumType = typeof(TEnum); // 构建EnumMember值到枚举的映射 var valueMap = enumType.GetMembers() .Select(m => new { Member = m, Attr = m.GetCustomAttribute<EnumMemberAttribute>() }) .Where(x => x.Attr != null) .ToDictionary(x => x.Attr!.Value, x => Enum.Parse(enumType, x.Member.Name)); if (valueMap.TryGetValue(inputValue, out var enumResult)) return enumResult; } return base.ConvertFrom(context, culture, value); } }
两种方案都能解决查询参数中大写下划线枚举的绑定问题,方案一无需修改现有枚举定义,更适合已有项目;方案二通过属性标记,逻辑更直观,适合新定义的枚举。
内容的提问来源于stack exchange,提问作者MatterOfFact
相关产品推荐
相关产品推荐

