小能豆

.net core 模型绑定 类型转换的提示信息怎么本地化?

javascript

我有这样一个接口,现在我想对sex做入参验证,但是类型转换的时候直接返回
Could not convert string to integer: ss. Path ‘sex’, line 8, position 13.
我现在应该怎么拦截类型转换的异常?使得提示信息更加本地化。

[HttpPost]
public async Task AddUser([FromBody] UserAddReq user)
{
await Task.Run(() => { return true; });
}


public class UserAddReq
{

    /// <summary>
    /// 昵称
    /// </summary>
    [Required]
    public string NickName { get; set; } = string.Empty;

    /// <summary>
    /// 生日
    /// </summary>
    [Required]
    [DisplayName("生日")]
    [JsonConverter(typeof(DateTimeJsonConvert), "yyyy-MM-dd")]
    public DateTime Birthday { get; set; }

    /// <summary>
    /// 性别0-女1-男
    /// </summary>
    [DisplayName("性别")]
    [Range(1, 3)]

    public int Sex { get; set; }

    /// <summary>
    /// 职业
    /// </summary>
    public string Occupation { get; set; } = string.Empty;


    /// <summary>
    /// 手机
    /// </summary>
    [Phone]
    public string Mobile { get; set; } = string.Empty;

    /// <summary>
    /// 状态0冻结1正常
    /// </summary>
    [JsonIgnore]
    public int State { get; set; } = 1;
}

public class DateTimeJsonConvert : IsoDateTimeConverter
{
    public DateTimeJsonConvert(string dateTimeFormat)
    {
        this.DateTimeFormat = dateTimeFormat;
    }
}

img

我实际想得到的是我自定义的异常信息,例如:
img

目前做了以下处理:
1.模型绑定错误消息自定义
services.AddControllers(o =>
{
//A value for the ‘{0}’ parameter or property was not provided
o.ModelBindingMessageProvider.SetMissingBindRequiredValueAccessor((x) => $”未 提供’{x}’ 参数或属性的值”);
//A value is required
o.ModelBindingMessageProvider.SetMissingKeyOrValueAccessor(() => $”需要一个值”);
//A non-empty request body is required
o.ModelBindingMessageProvider.SetMissingRequestBodyRequiredValueAccessor(() => $”需要非空的请求正文”);
//The value ‘{0}’ is invalid
o.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor((x) => $”值’{x}’无效,不能为Null”);
//The value ‘{0}’ is not valid for {1}.
o.ModelBindingMessageProvider.SetAttemptedValueIsInvalidAccessor((x, y) => $”值’{x}’对参数’{y}’无效”);
//The value ‘{0}’ is not valid.
o.ModelBindingMessageProvider.SetNonPropertyAttemptedValueIsInvalidAccessor((x) => $”值’{x}’无效”);
//The supplied value is invalid for {0}.
o.ModelBindingMessageProvider.SetUnknownValueIsInvalidAccessor((x) => $”提供的值对参数’{x}’无效”);
//The supplied value is invalid.
o.ModelBindingMessageProvider.SetNonPropertyUnknownValueIsInvalidAccessor(() => $”提供的值无效”);
//The value ‘{0}’ is invalid.
o.ModelBindingMessageProvider.SetValueIsInvalidAccessor((x) => $”值’{x}’无效”);
//The field {0} must be a number
o.ModelBindingMessageProvider.SetValueMustBeANumberAccessor((x) => $”字段’{x}’ 必须是数字”);
//The field must be a number.
o.ModelBindingMessageProvider.SetNonPropertyValueMustBeANumberAccessor(() => $”字段必须是数字”);
})

2.ModeState错误信息统一处理
services.Configure(options =>
{
options.InvalidModelStateResponseFactory = actionContext =>
{
//ModelState验证顺序并不是按参数顺序验证
var param = actionContext.ModelState.Keys;
var errors = actionContext.ModelState
.Where(s => s.Value != null && s.Value.ValidationState == ModelValidationState.Invalid)
.FirstOrDefault().Value!.Errors.ToList().Select(e => e.ErrorMessage).ToList();
//.SelectMany(s => s.Value!.Errors.ToList())
//.Select(e => new { e.ErrorMessage})
//.ToList();
var result = new MessageModel()
{
Status = StatusCodes.Status400BadRequest,
Msg = string.Format(“数据验证不通过!” + “参数{0}输入有误,{1}”, param.FirstOrDefault(), errors[0]),
IsSuccess = false,
};
return new BadRequestObjectResult(result);
};
});


阅读 35

收藏
2024-06-18

共1个答案

小能豆

在 ASP.NET Core 中,如果你希望对模型绑定过程中的类型转换异常进行自定义处理,以便能够给出本地化的错误信息,可以通过以下几个步骤来实现:

1. 使用自定义的 IModelBinder

ASP.NET Core 允许你通过实现自定义的 IModelBinder 来控制模型绑定的过程,包括类型转换。这样可以在绑定阶段捕获并处理异常。

首先,创建一个自定义的 IModelBinder

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

        var modelName = bindingContext.ModelName;
        var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);

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

        bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);

        var valueAsString = valueProviderResult.FirstValue;

        if (string.IsNullOrEmpty(valueAsString))
        {
            return Task.CompletedTask;
        }

        if (!int.TryParse(valueAsString, out int parsedValue))
        {
            bindingContext.ModelState.TryAddModelError(
                modelName,
                $"The value '{valueAsString}' is not a valid integer for {modelName}.");
            return Task.CompletedTask;
        }

        bindingContext.Result = ModelBindingResult.Success(parsedValue);
        return Task.CompletedTask;
    }
}

2. 注册自定义的 IModelBinder

Startup.csConfigureServices 方法中注册自定义的 IModelBinder

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews(options =>
    {
        options.ModelBinderProviders.Insert(0, new BinderTypeModelBinderProvider(typeof(int), new CustomIntModelBinder()));
    });
}

这样,当 ASP.NET Core 在模型绑定时遇到 int 类型的参数时,会使用我们自定义的 CustomIntModelBinder 来进行绑定,从而可以在其中添加自定义的验证逻辑和错误消息。

3. 处理类型转换异常

通过上述方式,你可以在 CustomIntModelBinder 中添加适当的逻辑来处理类型转换异常。在 BindModelAsync 方法中,我们通过 int.TryParse 来尝试将字符串转换为整数。如果转换失败,我们使用 bindingContext.ModelState.TryAddModelError 来添加自定义的错误消息到模型状态中。

4. 控制器中使用自定义的 IModelBinder

最后,你可以在控制器的方法参数中使用自定义的 IModelBinder,例如:

[HttpPost]
public IActionResult AddUser([FromBody] UserAddReq user)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    // 如果 ModelState 验证通过,继续处理逻辑
    // ...

    return Ok();
}

UserAddReq 类中的 Sex 属性上,可以使用 Range 属性来定义范围,并且通过上述自定义的 IModelBinder 来确保输入符合预期的整数范围,同时能够捕获和处理类型转换异常,以便给出本地化的错误消息。

这样,你就能够在 ASP.NET Core 中有效地处理模型绑定过程中的类型转换异常,并且提供自定义的错误信息,以更好地与前端交互和用户沟通。

2024-06-18