Aspnet核心十进制绑定不适用于非英语文化

sne*_*kke 10 c# asp.net-mvc json localization asp.net-core

我有一个运行非英语配置(西班牙语)的aspnet核心应用程序:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        ......
        app.UseRequestLocalization(new RequestLocalizationOptions
        {
            DefaultRequestCulture = new RequestCulture(new CultureInfo("es-AR"))
            ,SupportedCultures = new List<CultureInfo>
            {
                new CultureInfo("es-AR")
            }
            ,SupportedUICultures = new List<CultureInfo>
            {
                new CultureInfo("es")
            }
        });

        .........
    }
Run Code Online (Sandbox Code Playgroud)

在英语中,十进制数的小数部分用点分隔,但在西班牙语中使用逗号:

  • 10256.35英语
  • 10256,35西班牙语

我在控制器中有这个动作:

 [HttpPost]
 public decimal Test(decimal val)
 {
     return val;
 }
Run Code Online (Sandbox Code Playgroud)

如果我使用邮递员并向该行动发送一个类似于{val:15.30}的json,则该动作中的val将返回0(由于文化而绑定不起作用).如果我发送像这样的json {val:15,30}然后在我回忆的动作中15.30我遇到的问题是,我需要动作接受带逗号的小数,因为这是来自输入类型文本的格式应用程序的表单.但我还需要接受带有来自json格式请求的点的十进制数.无法在json中指定接受逗号的十进制/浮点数(将其作为字符串发送不是一个选项).我怎样才能做到这一点???我为此疯狂.

谢谢!!

Luc*_*ier 13

显然,ASP.NET核心1.0.0中的十进制绑定默认情况下不是文化不变量.模型绑定取决于服务器文化.

您可以使用Stephen Muecke建议的自定义模型绑定更改此行为.这是我的基于ASP.Net Core 1.0(RTM)中的自定义模型绑定

public class InvariantDecimalModelBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        if (context == null) throw new ArgumentNullException(nameof(context));

        if (!context.Metadata.IsComplexType && (context.Metadata.ModelType == typeof(decimal) || context.Metadata.ModelType == typeof(decimal?)))
        {
            return new InvariantDecimalModelBinder(context.Metadata.ModelType);
        }

        return null;
    }
}

public class InvariantDecimalModelBinder : IModelBinder
{
    private readonly SimpleTypeModelBinder _baseBinder;

    public InvariantDecimalModelBinder(Type modelType)
    {
        _baseBinder = new SimpleTypeModelBinder(modelType);
    }

    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null) throw new ArgumentNullException(nameof(bindingContext));

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

        if (valueProviderResult != ValueProviderResult.None)
        {
            bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);

            var valueAsString = valueProviderResult.FirstValue;
            decimal result;

            // Use invariant culture
            if (decimal.TryParse(valueAsString, NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out result))
            {
                bindingContext.Result = ModelBindingResult.Success(result);
                return Task.CompletedTask;
            }
        }

        // If we haven't handled it, then we'll let the base SimpleTypeModelBinder handle it
        return _baseBinder.BindModelAsync(bindingContext);
    }
}
Run Code Online (Sandbox Code Playgroud)

在Startup.cs中:

services.AddMvc(config =>
{
    config.ModelBinderProviders.Insert(0, new InvariantDecimalModelBinderProvider());
});
Run Code Online (Sandbox Code Playgroud)

  • 请注意其他人,此复制/粘贴将停止绑定负数。为了避免在decimal.TryParse中添加numberStyles.AllowLeadingSign样式。非常感谢 (2认同)