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

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

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" />

Method 2

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.

Method 3

I tried the custom validator that was mentioned above but it wasn’t working. I got it to work like this:

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

    private readonly IHtmlGenerator _generator;
    private readonly InputTagHelper _inputTagHelper;

    [HtmlAttributeNotBound]
    [ViewContext]
    public Microsoft.AspNetCore.Mvc.Rendering.ViewContext ViewContext { get; set; }
    [HtmlAttributeName("asp-for-invariant")]
    public ModelExpression For { get; set; }
    [HtmlAttributeName("asp-format")]
    public string Format { get; set; }
    [HtmlAttributeName("type")]
    public string InputTypeName { get; set; }
    public string Name { get; set; }
    public string Value { get; set; }

    public InvariantDecimalTagHelper(IHtmlGenerator generator)
    {
        _generator = generator;
        _inputTagHelper = new InputTagHelper(_generator);
    }

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

        _inputTagHelper.Value = Value;
        _inputTagHelper.Name = Name;
        _inputTagHelper.InputTypeName = InputTypeName;
        _inputTagHelper.Format = Format;
        _inputTagHelper.For = For;
        _inputTagHelper.ViewContext = ViewContext;

        _inputTagHelper.Process(context, output);

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

In ViewImports :

 @addTagHelper *, Project

In View :

 <input asp-for-invariant="numberProp"/>

Method 4

Comma and dot problem depend on culture and pc language so i solved problem with js like follow

   Amount: { editable: true, type: "number"},


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x