无法在 asp.net core api 3.1 中将 [FromForm] 枚举与 [EnumMember] 映射

Ale*_*lov 2 c# json.net asp.net-core-webapi

我有一个枚举,并为其值指定了 EnumMemberAttribute:

public enum HireStrategy
{
    [EnumMember(Value = "30-days")]
    Days30,
    [EnumMember(Value = "60-days")]
    Days60,
    [EnumMember(Value = "90-days")]
    Days90
}    
Run Code Online (Sandbox Code Playgroud)

我希望能够使用值30-days, 60-days,90-days作为我的 api 的输入参数。这是服务配置:

services
    .AddControllers()
    .AddNewtonsoftJson(config =>
    {
        config.SerializerSettings.Converters.Add(new StringEnumConverter(typeof(CamelCaseNamingStrategy)));
    });

services
    .AddMvc();            
Run Code Online (Sandbox Code Playgroud)

还有我的行动:

[HttpPost("test")]
public async Task<IActionResult> Test(HireStrategy type)
{
    return Ok();
}        
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试使用该请求(通过邮递员)时, https://localhost:44329/api/v1/users/test?type=60-days 我收到验证错误,即它甚至没有执行我的操作:

public enum HireStrategy
{
    [EnumMember(Value = "30-days")]
    Days30,
    [EnumMember(Value = "60-days")]
    Days60,
    [EnumMember(Value = "90-days")]
    Days90
}    
Run Code Online (Sandbox Code Playgroud)

当我传递“days60”作为值时,它工作正常。我有什么遗漏的吗?谢谢!


更新#1:我尝试禁用 ApiController 验证以查看 newtonsoft 是否处理请求:

services.Configure<ApiBehaviorOptions>(options =>
{
    options.SuppressModelStateInvalidFilter = true;
});            
Run Code Online (Sandbox Code Playgroud)

但参数会映射到默认值,即 Days30

Ale*_*lov 5

基于@dbc 在评论中提供的答案。我唯一改变的是用来CamelCaseNamingStrategy确保帕斯卡或驼峰大小写被视为有效值。

public class EnumMemberConverter<T> : EnumConverter
{
    private readonly CamelCaseNamingStrategy _camelCaseNamingStrategy;

    public EnumMemberConverter(Type type) 
        : base(type) 
    {
        _camelCaseNamingStrategy = new CamelCaseNamingStrategy();
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        var type = typeof(T);

        foreach (var field in type.GetFields())
        {
            if (Attribute.GetCustomAttribute(field, typeof(EnumMemberAttribute)) is EnumMemberAttribute attribute
                && value is string enumValue
                && _camelCaseNamingStrategy.GetPropertyName(attribute.Value, false) == _camelCaseNamingStrategy.GetPropertyName(enumValue, false))
            {
                return field.GetValue(null);
            }
        }          

        return base.ConvertFrom(context, culture, value);
    }
}    
Run Code Online (Sandbox Code Playgroud)
[TypeConverter(typeof(EnumMemberConverter<HireStrategy>))]
public enum HireStrategy
{
    [EnumMember(Value = "30-days")]
    Days30,
    [EnumMember(Value = "60-days")]
    Days60,
    [EnumMember(Value = "90-days")]
    Days90
}    
Run Code Online (Sandbox Code Playgroud)