Ошибка с десятичным значением в mvc3 - значение недействительно для поля
Я следую [Начало работы с ASP.NET MVC 3] [1]. И я не могу добавлять/редактировать со значением Price = 9.99 или 9,99. Он сказал: "Значение" 9.99 "недействительно для цены". и "Поле Цена должно быть числом".
Как это исправить?
Модель:
public class Movie
{
public int ID { get; set; }
public string Title { get; set; }
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
public decimal Price { get; set; }
}
public class MovieDbContext : DbContext
{
public DbSet<Movie> Movies { get; set; }
}
Контроллер:
public class MovieController : Controller
{
private MovieDbContext db = new MovieDbContext();
//
// GET: /Movie/
public ViewResult Index()
{
var movie = from m in db.Movies
where m.ReleaseDate > new DateTime(1984, 6, 1)
select m;
return View(movie.ToList());
}
//
// GET: /Movie/Details/5
public ViewResult Details(int id)
{
Movie movie = db.Movies.Find(id);
return View(movie);
}
//
// GET: /Movie/Create
public ActionResult Create()
{
return View();
}
//
// POST: /Movie/Create
[HttpPost]
public ActionResult Create(Movie movie)
{
if (ModelState.IsValid)
{
db.Movies.Add(movie);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(movie);
}
//
// GET: /Movie/Edit/5
public ActionResult Edit(int id)
{
Movie movie = db.Movies.Find(id);
return View(movie);
}
//
// POST: /Movie/Edit/5
[HttpPost]
public ActionResult Edit(Movie movie)
{
if (ModelState.IsValid)
{
db.Entry(movie).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(movie);
}
//
// GET: /Movie/Delete/5
public ActionResult Delete(int id)
{
Movie movie = db.Movies.Find(id);
return View(movie);
}
//
// POST: /Movie/Delete/5
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
Movie movie = db.Movies.Find(id);
db.Movies.Remove(movie);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
}
Вид:
@model MvcMovies.Models.Movie
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"> </script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>Movie</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Title)
@Html.ValidationMessageFor(model => model.Title)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.ReleaseDate)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.ReleaseDate)
@Html.ValidationMessageFor(model => model.ReleaseDate)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Genre)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Genre)
@Html.ValidationMessageFor(model => model.Genre)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Price)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Price)
@Html.ValidationMessageFor(model => model.Price)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
public DbSet<Movie> Movies { get; set; }
}
Ответы
Ответ 1
Я только что наткнулся на это снова через 2 года. Я думал, что ASP.NET MVC 5 решил это, но похоже, что это не так. Итак, вот как решить проблему...
Создайте класс с именем DecimalModelBinder
следующим образом и добавьте его в корень вашего проекта, например:
using System;
using System.Globalization;
using System.Web.Mvc;
namespace YourNamespace
{
public class DecimalModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
ValueProviderResult valueResult = bindingContext.ValueProvider
.GetValue(bindingContext.ModelName);
ModelState modelState = new ModelState { Value = valueResult };
object actualValue = null;
if(valueResult.AttemptedValue != string.Empty)
{
try
{
actualValue = Convert.ToDecimal(valueResult.AttemptedValue, CultureInfo.CurrentCulture);
}
catch(FormatException e)
{
modelState.Errors.Add(e);
}
}
bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
return actualValue;
}
}
}
Внутри Global.asax.cs,
используйте его в Application_Start()
следующим образом:
ModelBinders.Binders.Add(typeof(decimal?), new DecimalModelBinder());
Ответ 2
Вы один из клиентов, не являющихся англичанами, которых MS не предвидел. Вам нужно будет приложить дополнительные усилия для запуска вашей версии. У меня была аналогичная проблема, и я отрицал, что "9,99" и "9.99" являются действительными числами. Кажется, что как только проверка на стороне сервера завершилась неудачно, и после проверки на стороне клиента, в результате чего число не будет принято.
Итак, вы должны сделать проверку правильной.
Как и в комментариях, взгляните на
http://msdn.microsoft.com/en-us/library/gg674880(VS.98).aspx
а также
http://haacked.com/archive/2010/05/10/globalizing-mvc-validation.aspx
а также
MVC 3 jQuery Проверка/глобализация числа/десятичного поля
или - если вы понимаете немецкий (или просто смотрите примеры кода)
http://www.andreas-reiff.de/2012/06/probleme-mit-mvcmovies-beispiel-validierung-des-preises-mit-dezimalstellen-schlagt-fehl/
BTW, такая же проблема существует и для учебных пособий по музыке и фильму.
Ответ 3
Я столкнулся с этой проблемой при разработке веб-приложения для английской аудитории на ПК в Нидерландах.
Свойство модели типа double, генерировало эту ошибку проверки на стороне сервера:
Значение "1.5" недопустимо для.
В точке останова я видел эти значения в окне Immediate:
?System.Threading.Thread.CurrentThread.CurrentUICulture
{EN-US}
?System.Threading.Thread.CurrentThread.CurrentCulture
{п-NL}
В качестве решения (или, возможно, для работы) вы можете указать параметры глобализации в файле web.config.
<configuration>
<system.web>
<globalization culture="en" uiCulture="en" />
Конечно, это означает, что вы заставляете своих пользователей вводить цифры в форматирование на английском языке, но в моем случае это нормально.
Ответ 4
Я решил эту проблему, отключив jquery по цене и только подтверждая на стороне сервера для этого ввода. Я нашел ответ здесь:
ASP.NET MVC Отключить проверку на стороне клиента на уровне поля
<div class="col-md-10">
@{ Html.EnableClientValidation(false); }
@Html.EditorFor(model => model.DecimalValue, new { htmlAttributes = new { @class = "form-control" } })
@{ Html.EnableClientValidation(true); }
@Html.ValidationMessageFor(model => model.DecimalValue, "", new { @class = "text-danger" })
</div>
Ответ 5
Я немного адаптировал код от Leniel Macaferi, чтобы вы могли использовать его для любого типа:
public class RequestModelBinder<TBinding> : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
ValueProviderResult valueResult = bindingContext.ValueProvider
.GetValue(bindingContext.ModelName);
ModelState modelState = new ModelState { Value = valueResult };
object actualValue = null;
if (valueResult.AttemptedValue != string.Empty)
{
try
{
// values really should be invariant
actualValue = Convert.ChangeType(valueResult.AttemptedValue, typeof(TBinding), CultureInfo.CurrentCulture);
}
catch (FormatException e)
{
modelState.Errors.Add(e);
}
}
bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
return actualValue;
}
}
Ответ 6
Я пробовал @Leniel Macaferi, но это не сработало для меня.
ModelState.IsValid не принимает числа, отформатированные как 7.000,00
Проблема началась, когда я изменил тип свойства:
[Column("PRICE")]
public decimal Price { get; set; }
к
[Column("PRICE")]
public decimal? Price { get; set; }
Я также попытался включить глобализацию в web.config, которую я забыл
<globalization culture="pt-BR" uiCulture="pt-BR" enableClientBasedCulture="true" />
Единственным обходным решением, которое работало, было изменение свойства только десятичным:
[Column("PRICE")]
public decimal Price { get; set; }
а также изменил столбец таблицы, чтобы НЕ принимать значения null
Надеюсь, это поможет кому-то.
Ответ 7
В 2019 году эта проблема до сих пор не решена. Используя ASP Core 2.1, мой пользовательский интерфейс написан на французском языке (десятичный разделитель = ','), и я не мог заставить работать проверку всякий раз, когда у меня было десятичное число.
Я нашел обходной путь, хотя и не идеальный: я создал французский CultureInfo, но я изменил десятичный разделитель так, чтобы он был таким же, как в Invariant Culture: '.'.
Это сделало трюк, мои десятичные числа теперь отображаются в американском стиле (но я в порядке) и проверка работает.
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
//Culture specific problems
var cultureInfo = new CultureInfo("fr-FR");
cultureInfo.NumberFormat.NumberDecimalSeparator = ".";
System.Threading.Thread.CurrentThread.CurrentUICulture = cultureInfo;
}
Ответ 8
Вы можете добавить:
protected void Application_BeginRequest()
{
var currentCulture = (CultureInfo)CultureInfo.CurrentCulture.Clone();
currentCulture.NumberFormat.NumberDecimalSeparator = ".";
currentCulture.NumberFormat.NumberGroupSeparator = " ";
currentCulture.NumberFormat.CurrencyDecimalSeparator = ".";
Thread.CurrentThread.CurrentCulture = currentCulture;
//Thread.CurrentThread.CurrentUICulture = currentCulture;
}
To Global.asax
(проверено на MVC 5.1). Он работает без изменения UICulture для меня.
Ответ 9
Просто прокомментируйте эту ссылку для script:
<%--<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>--%>