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

ASP.NET Core 8中GET请求逗号作为小数分隔符绑定失效问题

ASP.NET Core 8 中GET请求小数模型绑定的文化配置问题

我有一个设置了sv-SE文化的ASP.NET Core 8网站,网站内有一个常规表单用于提交小数输入。小数以逗号作为分隔符显示正常(例如1,00等价于1),POST请求时模型绑定工作正常,但GET请求时,模型绑定会将1,00转换为100。GET请求中,URL编码后的1,00为1%2C00。

问题本质

  • 正常工作:/SomeController/SomeAction?test=1.00
  • 无法工作:/SomeController/SomeAction?test=1,00
  • 无法工作:/SomeController/SomeAction?test=1%2C00

我该如何配置网站文化,使其始终将逗号视为小数分隔符?是否有可行的配置方式,还是必须为decimal类型实现自定义模型绑定?

已尝试的配置

在Program.cs最开始处设置文化的代码:

var cultureInfo = (CultureInfo)CultureInfo.GetCultureInfo("sv-SE").Clone();
CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;
Thread.CurrentThread.CurrentCulture = cultureInfo;
Thread.CurrentThread.CurrentUICulture = cultureInfo;

还尝试过以下设置,但无效果:

CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator = ",";

动作方法签名:

public async Task<IActionResult> SomeAction(decimal? test)

解决方案

问题核心在于ASP.NET Core的模型绑定行为:POST请求的表单数据绑定会使用当前请求的文化,但GET请求的查询字符串绑定默认使用InvariantCulture,而非你设置的sv-SE文化。

方案1:配置请求本地化与MVC模型绑定选项

这是最贴合框架设计的解决方式,通过配置让查询字符串绑定遵循当前请求文化:

// 配置支持的文化
var supportedCultures = new[] { new CultureInfo("sv-SE") };
builder.Services.Configure<RequestLocalizationOptions>(options =>
{
    options.DefaultRequestCulture = new RequestCulture("sv-SE");
    options.SupportedCultures = supportedCultures;
    options.SupportedUICultures = supportedCultures;
    // 保留默认的文化提供器,可根据需求调整顺序
    options.RequestCultureProviders = new List<IRequestCultureProvider>
    {
        new QueryStringRequestCultureProvider(),
        new CookieRequestCultureProvider()
    };
});

// 配置MVC模型绑定使用请求文化
builder.Services.AddControllersWithViews(options =>
{
    // 替换查询字符串值提供器,强制使用当前请求文化
    options.ValueProviderFactories.RemoveType<QueryStringValueProviderFactory>();
    options.ValueProviderFactories.Add(new QueryStringValueProviderFactory
    {
        Culture = RequestCultureProvider.DefaultCulture
    });
});

// 启用请求本地化中间件(注意要放在UseRouting之前)
app.UseRequestLocalization();

方案2:实现自定义decimal模型绑定器

如果上述配置仍无法解决问题,可以为decimal类型编写自定义绑定器,强制用sv-SE文化解析值:

public class DecimalModelBinder : 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 value = valueProviderResult.FirstValue;

        if (string.IsNullOrEmpty(value))
            return Task.CompletedTask;

        // 使用sv-SE文化解析小数
        if (decimal.TryParse(value, NumberStyles.Any, new CultureInfo("sv-SE"), out var result))
        {
            bindingContext.Result = ModelBindingResult.Success(result);
        }
        else
        {
            bindingContext.ModelState.TryAddModelError(
                bindingContext.ModelName, $"值 '{value}' 不是有效的小数格式。");
        }

        return Task.CompletedTask;
    }
}

// 注册自定义绑定器
builder.Services.AddControllersWithViews(options =>
{
    options.ModelBinderProviders.Insert(0, new BinderTypeModelBinderProvider(typeof(decimal), new DecimalModelBinder()));
    options.ModelBinderProviders.Insert(0, new BinderTypeModelBinderProvider(typeof(decimal?), new DecimalModelBinder()));
});

总结

优先使用方案1配置框架默认行为,这是更简洁、符合ASP.NET Core设计规范的方式;若仍有特殊场景需求,再考虑方案2的自定义绑定器。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 09:06:19