ASP.NET Core 中枚举的自定义验证器

Sha*_*ash 3 c# enums asp.net-web-api asp.net-core .net-5

public enum GroupBy
{
    status = 0,
    dueDate = 1,
    requester = 2,
    assignee = 3
}
Run Code Online (Sandbox Code Playgroud)

我在 Web api 的参数中使用这个枚举,如下所示:-

public async Task<IActionResult> Dashboard(GroupBy groupBy)
Run Code Online (Sandbox Code Playgroud)

我的问题是当我传递正确的枚举时它会给出输出。但是如果我传递任何无效的枚举,它将抛出错误,这是ASP.NET Core 的内置错误。我尝试实现,但在调用此 api 时,它不会进入我的自定义验证器。当我传递有效的枚举时,它将进入我的验证器。

所以,我想为其实现自定义验证。请有人帮忙

Orw*_*wel 5

当值不正确时,模型绑定器无法创建 GroupBy 实例,也无法在此实例上调用自定义验证。

解决方案是将输入参数类型更改为字符串并手动执行检查和解析步骤:

public async Task<IActionResult> Dashboard(string groupBy)
{
    if(!Enum.TryParse(groupBy, out GroupBy by))
    {
        ModelState.AddModelError(nameof(groupBy), $"The value is invalid. Valid value : {Enum.GetValues(typeof(GroupBy))}");
        return BadRequest(ModelState);
    }
    return Ok(by);
}
Run Code Online (Sandbox Code Playgroud)

其他解决方案是覆盖模型绑定器行为。为此,您需要创建一个自定义活页夹:

public class GroupByBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
        {
            throw new ArgumentNullException(nameof(bindingContext));
        }

        // Try to fetch the value of the argument by name
        var modelName = "groupBy";
        var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);

        if (valueProviderResult == ValueProviderResult.None)
        {
            return Task.CompletedTask;
        }

        bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);

        var value = valueProviderResult.FirstValue;

        // Check if the argument value is null or empty
        if (string.IsNullOrEmpty(value))
        {
            return Task.CompletedTask;
        }

        // Custom validation
        if (!Enum.TryParse(value, out GroupBy groupBy))
        {
            bindingContext.ModelState.AddModelError(modelName, $"The value is invalid. Valid value : {Enum.GetValues(typeof(GroupBy))}");
            return Task.CompletedTask;
        }

        bindingContext.Result = ModelBindingResult.Success(groupBy);
        return Task.CompletedTask;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在您可以:

public async Task<IActionResult> Dashboard(string groupBy)
{
    if(!Enum.TryParse(groupBy, out GroupBy by))
    {
        ModelState.AddModelError(nameof(groupBy), $"The value is invalid. Valid value : {Enum.GetValues(typeof(GroupBy))}");
        return BadRequest(ModelState);
    }
    return Ok(by);
}
Run Code Online (Sandbox Code Playgroud)

您可以将此行为覆盖到所有 GroupBy 输入参数:

public class GroupByBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
        {
            throw new ArgumentNullException(nameof(bindingContext));
        }

        // Try to fetch the value of the argument by name
        var modelName = "groupBy";
        var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);

        if (valueProviderResult == ValueProviderResult.None)
        {
            return Task.CompletedTask;
        }

        bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);

        var value = valueProviderResult.FirstValue;

        // Check if the argument value is null or empty
        if (string.IsNullOrEmpty(value))
        {
            return Task.CompletedTask;
        }

        // Custom validation
        if (!Enum.TryParse(value, out GroupBy groupBy))
        {
            bindingContext.ModelState.AddModelError(modelName, $"The value is invalid. Valid value : {Enum.GetValues(typeof(GroupBy))}");
            return Task.CompletedTask;
        }

        bindingContext.Result = ModelBindingResult.Success(groupBy);
        return Task.CompletedTask;
    }
}
Run Code Online (Sandbox Code Playgroud)

警告:当数据来自 JSON 或 XML 内容时,不使用模型生成器。更多细节参见官方文档