Подтвердить что ты не робот

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

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

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

4b9b3361

Ответ 1

Я только что просмотрел проблему в реальном проекте и, наконец, нашел рабочее решение. Правильное решение состоит в том, чтобы иметь настраиваемое связующее устройство для типа 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;
    }
}

Затем в Global.asax.cs в Application_Start():

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

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

Ответ 2

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

<globalization uiCulture="en" culture="en-US" />

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

Ответ 3

Можете ли вы разобрать текст, используя инвариантную культуру - извините, у меня нет кода NerdDinner для меня, но если вы проходите в десятичных запятых, разделенных точками, чем разбор должен быть ОК, если вы говорите ему использовать инвариантная культура. Например.

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

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

Ответ 4

У меня другое дело, вам может понравиться. То, что мне не нравится в принятом ответе, это не проверка других символов. Я знаю, что будет случай, когда символ валюты будет в поле, потому что мой пользователь не знает лучше. Так что да, я могу проверить 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. Результат возврата.

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