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

.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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 04:58:12