0

I have the following MVC ViewModel:

public class Payment
{
    [Required]
    [Range(5, 1000)]
    public decimal RebillAmount { get; set; }
}

When I have switched the application language to French Canadian using:

var cultureInfo = new CultureInfo("fr-CA");

Thread.CurrentThread.CurrentCulture = cultureInfo;
Thread.CurrentThread.CurrentUICulture = cultureInfo;

Then submit a decimal with 300,00 in the input field, the value for the decimal is converted to 30000 when retrieving the value in my controller?

For example:

public ActionResult Save(Payment model)
{
    decimal amount = model.RebillAmount; // <- Returns 30000, not 300.00
}

What am I doing wrong?

EDIT:

The culture is set manually for testing (as shown above), but it's actually configurable by each user using a session variable.

Steve Bauman
  • 8,165
  • 7
  • 40
  • 56

2 Answers2

3

You'll need to write a Custom Model Binder to do this.

public class DecimalModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext,
        ModelBindingContext bindingContext)
    {
        ValueProviderResult valueResult = bindingContext.ValueProvider
            .GetValue(bindingContext.ModelName);
        ModelState modelState = new ModelState { Value = valueResult };
        object actualValue = null;
        try
        {
            actualValue = Convert.ToDecimal(valueResult.AttemptedValue,
                CultureInfo.CurrentCulture);
        }
        catch (FormatException e)
        {
            modelState.Errors.Add(e);
        }

        bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
        return actualValue;
    }
}

In your Global.asax file, add the following to your Application_Start Method

ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());
Hossein
  • 3,083
  • 3
  • 16
  • 33
  • Awesome thanks! Though it's still being returned as 30000 when inputting 300,00, but I've uncovered a part of the issue. It seems the `CultureInfo.CurrentCulture` is being set **after** this model binder runs. The language is being switched inside the controller method `OnActionExecuting`, where should I switch the language so it persists *before* this model binder runs? – Steve Bauman Aug 16 '18 at 20:54
  • Maybe in an `ActionFilterAttribute`? – Steve Bauman Aug 16 '18 at 20:56
  • 1
    @SteveBauman check this please https://stackoverflow.com/questions/9980104/mvc-3-client-side-validation-model-binding-decimal-value-and-culture-different?answertab=votes#tab-top – Hossein Aug 16 '18 at 21:13
0

I faced a similar problem with latitude and longitude data, the commas dissapeared due to client formats, I solved doing this:

Startup configuration

        IList<CultureInfo> supportedCultures = new[]
        {
            new CultureInfo("en-US"),
        };

        IList<CultureInfo> supportedCulturesUI = new[]
        {
            new CultureInfo("es-EC"),
        };

        app.UseRequestLocalization(new RequestLocalizationOptions
        {
            DefaultRequestCulture = new RequestCulture("en-US"),
            // Formatting numbers, dates, etc.
            SupportedCultures = supportedCultures,
            // UI strings that we have localized.
            SupportedUICultures = supportedCulturesUI
        });

POCO Class

[Column(TypeName = "decimal(18, 6)")]
[DisplayFormat(DataFormatString = "{0:0.000000}", ApplyFormatInEditMode = true)]
public virtual decimal baLatitude { get; set; }

The latitude and longitude data were captured by the google maps api and written in hidden controls in the view

<div class="is-hidden">
    <input asp-for="baLatitude">
</div>
Douglas Acosta
  • 73
  • 1
  • 4
  • 7