Как установить десятичные разделители в ASP.NET контроллеры MVC?
Я работаю с NerdDinner приложение пытается научить себя ASP.NET MVC. Однако я столкнулся с проблемой глобализации, где мой сервер представляет числа с плавающей запятой с запятой в качестве десятичного разделителя, но виртуальная карта Земли требует их с точками, что вызывает некоторые проблемы.
Я уже решил проблема с отображением JavaScript в моих представлениях, но если я сейчас попытаюсь опубликовать отредактированную запись обеда с точками как десятичные разделители контроллер выходит из строя (throwing InvalidOperationException
) при обновлении модели (в UpdateModel()
метод). Я чувствую, что должен установить правильную культуру где-то в контроллере, я попробовал это в
4 ответов
Я только что вернулся к проблеме в реальном проекте и, наконец, нашел рабочее решение. Правильное решение-иметь пользовательскую модель связующего для типа decimal
(и decimal?
Если вы используете их):
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. Возвращаться результат.
работает для меня.