Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET Core localization decimal field dot and comma

I have a localized ASP.NET Core Web Application: en-US and it-IT.

On en-US the decimal separator is dot, in it-IT the decimal separator is comma.

I have this ViewModel

public class MyViewModel 
{
    public int Id {get; set; }

    // Omitted

    public decimal? Amount{get; set;}

}

For the decimal field when I render the create/edit page on en-US the html textbox render

1000.00

If I POST the form, the operation complete without errors.

So far so good.

When I render the create/edit page on it-IT the html textbox render

1000,00 (notice the comma)

And IF I try to POST the form, (CLIENT) validation fail with

The field Amount must be a number.

I read about the IModelBinder but I understand is for mapping the viewModel when the form is posted on the server, on my case I'm blocked by the client-side validation.

The better is to use dot when en-US and comma when it-IT, but it's fine using only the dot

like image 528
Max Avatar asked Aug 25 '17 12:08

Max


2 Answers

After digging depth the problem I found two solution:

The comment from Stephen Muecke where explain how to add the required jquery to the input for a validation for comma and dot

A custom InputTagHelper where transform the comma into dot. Here I added only a decimal type but obviously you can add float and double.

[HtmlTargetElement("input", Attributes = ForAttributeName, TagStructure = TagStructure.WithoutEndTag)]
public class InvariantDecimalTagHelper : InputTagHelper
{
    private const string ForAttributeName = "asp-for";

    private IHtmlGenerator _generator;

    [HtmlAttributeName("asp-is-invariant")]
    public bool IsInvariant { set; get; }

    public InvariantDecimalTagHelper(IHtmlGenerator generator) : base(generator)
    {
        _generator = generator;
    }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        base.Process(context, output);

        if (IsInvariant && output.TagName == "input" && For.Model != null && For.Model.GetType() == typeof(decimal))
        {
            decimal value = (decimal)(For.Model);
            var invariantValue = value.ToString(System.Globalization.CultureInfo.InvariantCulture);
            output.Attributes.SetAttribute(new TagHelperAttribute("value", invariantValue));                
        }
    }
}

For use this 2nd solution you simply add asp-is-invariant to your input, like this

 <input asp-for="AmountSw" class="form-control" asp-is-invariant="true" />
like image 98
Max Avatar answered Sep 21 '22 15:09

Max


The conversion fails because ASP.NET tries to convert the value with its current culture (check this link). You need to set the culture in the current thread of the request. The browser will send the languages it is currently using and supportin with Request.UserLanguage.

You can impliment a custom filter, a http module or use the event structure of mvc to set the culture automatically for every request. Check this link for a sample.

like image 42
JoeJoe87577 Avatar answered Sep 22 '22 15:09

JoeJoe87577