Как установить десятичные разделители в ASP.NET контроллеры MVC?

Я работаю с NerdDinner приложение пытается научить себя ASP.NET MVC. Однако я столкнулся с проблемой глобализации, где мой сервер представляет числа с плавающей запятой с запятой в качестве десятичного разделителя, но виртуальная карта Земли требует их с точками, что вызывает некоторые проблемы.

Я уже решил проблема с отображением JavaScript в моих представлениях, но если я сейчас попытаюсь опубликовать отредактированную запись обеда с точками как десятичные разделители контроллер выходит из строя (throwing InvalidOperationException) при обновлении модели (в UpdateModel() метод). Я чувствую, что должен установить правильную культуру где-то в контроллере, я попробовал это в

4 ответов


Я только что вернулся к проблеме в реальном проекте и, наконец, нашел рабочее решение. Правильное решение-иметь пользовательскую модель связующего для типа decimaldecimal? Если вы используете их):

using System.Globalization;
using System.Web.Mvc;

public class DecimalModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext,
                                     ModelBindingContext bindingContext)
    {
        object result = null;

        // Don't do this here!
        // It might do bindingContext.ModelState.AddModelError
        // and there is no RemoveModelError!
        // 
        // result = base.BindModel(controllerContext, bindingContext);

        string modelName = bindingContext.ModelName;
        string attemptedValue =
            bindingContext.ValueProvider.GetValue(modelName).AttemptedValue;

        // Depending on CultureInfo, the NumberDecimalSeparator can be "," or "."
        // Both "." and "," should be accepted, but aren't.
        string wantedSeperator = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator;
        string alternateSeperator = (wantedSeperator == "," ? "." : ",");

        if (attemptedValue.IndexOf(wantedSeperator) == -1
            && attemptedValue.IndexOf(alternateSeperator) != -1)
        {
            attemptedValue =
                attemptedValue.Replace(alternateSeperator, wantedSeperator);
        }

        try
        {
            if (bindingContext.ModelMetadata.IsNullableValueType
                && string.IsNullOrWhiteSpace(attemptedValue))
            {
                return null;
            }

            result = decimal.Parse(attemptedValue, NumberStyles.Any);
        }
        catch (FormatException e)
        {
            bindingContext.ModelState.AddModelError(modelName, e);
        }

        return result;
    }
}

затем в глобальные.асакс.cs в Application_Start ():

ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());
ModelBinders.Binders.Add(typeof(decimal?), new DecimalModelBinder());

обратите внимание, что код не мой, я нашел его в блоге здесь. Я просто отредактировал несколько строк и добавляю связующее для определенного типа данных, а не заменяю папка по умолчанию.


установите это в своей сети.config

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

вы, кажется, используете сервер, который настроен с языком, который использует запятые вместо десятичных знаков. Вы можете настроить культуру на ту, которая использует запятую таким образом, что ваше приложение разработано, например en-US.


можете ли вы разобрать текст, используя инвариантную культуру-извините, у меня нет кода NerdDinner в fornt меня, но если вы передаете в десятичных дробях, чем разбор должен быть в порядке, если вы скажете ему использовать инвариантную культуру. Е. Г.

 float i = float.Parse("0.1", CultureInfo.InvariantCulture);

редактировать. Кстати, я подозреваю, что это ошибка в коде NerdDinner, как и ваша предыдущая проблема.


У меня другой взгляд на это, вам может понравиться. Что мне не нравится в принятом ответе, так это то, что он не проверяет других персонажей. Я знаю, что будет случай, когда символ валюты будет в поле, потому что мой пользователь не знает лучше. Так что да, я могу проверить javascript, чтобы удалить его, но что, если по какой-то причине javascript не включен? Тогда могут пройти дополнительные персонажи. Или если кто-то пытается спамить вас, передавая неизвестные символы... кто знает! Поэтому я решил использовать регулярное выражение. Это немного медленнее, крошечная доля медленнее - для моего случая это было 1,000,000 итерации регулярного выражения заняло чуть менее 3 секунд, в то время как около 1 секунды, чтобы сделать замену строки на коме и период. Но, поскольку я не знаю, какие персонажи могут пройти, тогда я счастлив за этот малейший из хитов производительности.

public class DecimalModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext,
                                     ModelBindingContext bindingContext)
    {
        string modelName = bindingContext.ModelName;
        string attemptedValue =
            bindingContext.ValueProvider.GetValue(modelName).AttemptedValue;

        if (bindingContext.ModelMetadata.IsNullableValueType
                && string.IsNullOrWhiteSpace(attemptedValue))
        {
            return null;
        }

        if (string.IsNullOrWhiteSpace(attemptedValue))
        {
            return decimal.Zero;
        }

        decimal value = decimal.Zero;
        Regex digitsOnly = new Regex(@"[^\d]", RegexOptions.Compiled);
        var numbersOnly = digitsOnly.Replace(attemptedValue, "");
        if (!string.IsNullOrWhiteSpace(numbersOnly))
        {
            var numbers = Convert.ToDecimal(numbersOnly);
            value = (numbers / 100m);

            return value;
        }
        else
        {
            if (bindingContext.ModelMetadata.IsNullableValueType)
            {
                return null;
            }

        }

        return value;
    }
}

в принципе, удалить все символы, которые не являются цифрами, для строки, которая не является пустой. Преобразовать в десятичное число. Делим на 100. Возвращаться результат.

работает для меня.