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

ASP.NET Core MVC:前端格式化货币字符串绑定转Decimal至控制器

解决方案

可以通过自定义模型绑定器或者类型转换器实现格式字符串到decimal?的转换,且确保转换在验证前执行,以下是两种可行方案:

方案一:自定义模型绑定器

自定义绑定器可直接处理表单提交的字符串,先清理格式再转换为decimal?,步骤如下:

  1. 创建自定义模型绑定器类:
public class FormattedDecimalBinder : 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 rawValue = valueProviderResult.FirstValue;
        if (string.IsNullOrWhiteSpace(rawValue))
        {
            bindingContext.Result = ModelBindingResult.Success(null);
            return Task.CompletedTask;
        }

        // 清理格式:移除$符号和千分位逗号
        var cleanedValue = rawValue.Replace("$", "").Replace(",", "");
        if (decimal.TryParse(cleanedValue, NumberStyles.Currency | NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, CultureInfo.InvariantCulture, out var result))
        {
            bindingContext.Result = ModelBindingResult.Success(result);
        }
        else
        {
            bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, "金额格式无效");
            bindingContext.Result = ModelBindingResult.Failed();
        }

        return Task.CompletedTask;
    }
}
  1. 创建绑定器提供者:
public class FormattedDecimalBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        if (context == null)
            throw new ArgumentNullException(nameof(context));

        // 针对decimal?类型应用绑定器
        if (context.Metadata.ModelType == typeof(decimal?))
            return new BinderTypeModelBinder(typeof(FormattedDecimalBinder));

        return null;
    }
}
  1. 在Program.cs中注册绑定器提供者:
builder.Services.AddControllers(options =>
{
    options.ModelBinderProviders.Insert(0, new FormattedDecimalBinderProvider());
});

表单提交Amount字段时,绑定器会先清理格式字符串并转换为decimal?,之后再执行数据验证(包括Precision特性的验证)。

方案二:自定义类型转换器

通过TypeConverter实现字符串到decimal?的转换,步骤如下:

  1. 创建自定义类型转换器:
public class FormattedDecimalConverter : TypeConverter
{
    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 strValue)
        {
            if (string.IsNullOrWhiteSpace(strValue))
                return null;

            var cleanedValue = strValue.Replace("$", "").Replace(",", "");
            if (decimal.TryParse(cleanedValue, NumberStyles.Currency, CultureInfo.InvariantCulture, out var result))
                return result;
        }

        return base.ConvertFrom(context, culture, value);
    }
}
  1. 在TestClass的Amount属性上添加TypeConverter特性:
public class TestClass
{
    [Precision(18,2)]
    [TypeConverter(typeof(FormattedDecimalConverter))]
    public decimal? Amount { get; set; }
}

这种方式会在模型绑定阶段自动调用转换器处理字符串,同样能在验证前完成转换。

注意事项

  • 两种方案都可根据实际需求调整格式清理逻辑(比如支持其他货币符号、不同的千分位分隔符)
  • 如果需要支持多语言,可根据当前请求的CultureInfo调整解析逻辑,而非固定使用InvariantCulture

内容的提问来源于stack exchange,提问作者Topik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 03:46:04