Dmytro
Dmytro

Reputation: 17176

Edit decimal model properties in C# ASP .Net MVC

I have Simple model with one decimal property:

public class Model {
    public decimal Quantity { get;set; }
}

In my view I have:

@Html.TextBoxFor(m => m.Quantity)
@Html.ValidationMessageFor(m => m.Quantity)

The thing is that when I try to post value with decimal part (like 1.5, 2.5 etc.) I get validation errors on client or server sides depending which NumberDecimalSeparator I use. If I post 1,5 I get client side validation error (the data-val-number one) or if I post 1.5 I get server side model validation error - "The value '1.5' is not valid for Quantity.". I tried to set NumberDecimalSeparator manually on Application_Start() in Global.asax but it didn't help.

var currentCulture = (CultureInfo)CultureInfo.CurrentCulture.Clone();
currentCulture.NumberFormat.NumberDecimalSeparator = ".";

Thread.CurrentThread.CurrentCulture = currentCulture;
Thread.CurrentThread.CurrentUICulture = currentCulture;

When I manually added some values to the database and tried to edit them, the value in TextBox is displayed with dot ".", but when I try to save another value with the dot I get server side validation error. What could be the reasons? Why didn't manual culture info update work?

// EDITS: My approach with changing currentCulture.NumberFormat.NumberDecimalSeparator works but only if I do it each time on Application_BeginRequest():

protected override void Application_BeginRequest(object sender, System.EventArgs e)
{
       var currentCulture = (CultureInfo)CultureInfo.CurrentCulture.Clone();
       currentCulture.NumberFormat.NumberDecimalSeparator = ".";
       currentCulture.NumberFormat.NumberGroupSeparator = " ";
       currentCulture.NumberFormat.CurrencyDecimalSeparator = ".";

       Thread.CurrentThread.CurrentCulture = currentCulture;
       Thread.CurrentThread.CurrentUICulture = currentCulture;
       base.Application_BeginRequest(sender, e);
}

Why doesn't it work on application start?

Upvotes: 3

Views: 2614

Answers (2)

Thijs
Thijs

Reputation: 3055

There is an excellent blogpost about this issue. I answered this already to a similar question.

The approach I used is to extend the jQuery validator. It is based on this blogpost. I setted the culture in the metadata to BE-nl. Since this is a pure Dutch website, I don't do any checks further on.

$(function () {
    // Look in metatag what culture we want
    // and set this as culture for the client side.
    var data = $("meta[name='accept-language']").attr("content");
    Globalize.culture(data.toString());

    // Don't validate on keyup event because it will mess up
    // the cursor when replacing values in a textbox.
    $('form').each(function () {
    var validator = $(this).data('validator');
    if (validator) {
        validator.settings.onkeyup = false;
    }
});

// Belgianize/sanitize the numbers inserted
// 1 000 000    =>      1000000
// 1.00         =>      1,00
$.validator.methods.number = function (value, element) {
    var s = value.replace(/\ /g, '').split('.').join(',');

    if (s.split(',').length < 3) {
        var number = Globalize.parseFloat(s);
        if (!isNaN(number)) {
            $(element).val(s);
            return this.optional(element) || true;
        }
    }

    return this.optional(element) || false;
}; }); 

I think I used this jQuery library for the globalization

Upvotes: 1

Aleksandr Ivanov
Aleksandr Ivanov

Reputation: 2786

I think it's logical that it's not working in Application_Start because you set culture per thread.

You can set culture globally in your web.config:

<configuration>
    <system.web>
        <globalization uiCulture="en-GB" culture="en-GB" />
    </system.web>
</configuration>

But if you want (as in your example) to have Russian culture but with different decimal separator, then I think Application_BeginRequest() might be a good candidate. According to documentation:

Occurs as the first event in the HTTP pipeline chain of execution when ASP.NET responds to a request.

But you need to be careful, because this event is fired on literally every request.

I solved the similar problem not so long ago. In my case user had a possibility to switch between cultures. So every user culture was saved in database and because of that we used Initialize method of controller instead of Application_BeginRequest(). Then we set all the rules for client validation based on current thread culture.

I think such functionality can be also moved to filter like in this answer.

Upvotes: 3

Related Questions