Aspnet Core Decimal binding does not work on non-English culture

I have a basic aspnet application that works with non-English configuration (Spanish):

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") } }); ......... } 

In English, a decimal has a decimal part separated by a period, but in Spanish, a comma is used:

  • 10256.35 Russian
  • 10256.35 Spanish

I have this action in the controller:

  [HttpPost] public decimal Test(decimal val) { return val; } 

If I use a postman and send json to this action, like this {val: 15.30}, then val in the action returns 0 (binding does not work due to culture). If I send json like this {val: 15,30}, then in action I get 15.30 I have a problem, I need an action to accept decimal places with commas, because this is a format that comes from entering text type in application forms . But I also need to accept a decimal with a dot that comes from a request in json format. It is not possible to specify decimal / float in json that takes a comma (sending it as a string is not an option). How can i do this??? I make myself crazy with that.

Thanks!!

+9
json c # asp.net-mvc asp.net-core localization
source share
2 answers

Decimal binding in ASP.NET core 1.0.0 is apparently not culturally invariant by default. Model binding depends on the server culture.

You can change this behavior using custom model bindings, as suggested by Stephen Muke. Here is mine based on binding user models in ASP.Net Core 1.0 (final initial version)

 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); } } 

And in Startup.cs:

 services.AddMvc(config => { config.ModelBinderProviders.Insert(0, new InvariantDecimalModelBinderProvider()); }); 
+12
source share

ASP.NET Core 2.2 offers a solution for globalization. You need to add some settings to Startup.cs in the ConfigureServices and Configure methods. Check out this documentation: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization?view=aspnetcore-2.2.

0
source share

All Articles