问题
I\'m following [Getting started with ASP.NET MVC 3][1]. And I can\'t add/edit with value of Price = 9.99 or 9,99. It said: \"The value \'9.99\' is not valid for Price.\" and \"The field Price must be a number.\"
How to fix this?
Model:
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; }
}
Controller:
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);
}
}
}
View:
@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:
I just stumbled on this again after 2 years. I thought ASP.NET MVC 5 had solved this but looks like it's not the case. So here goes how to solve the problem...
Create a class called DecimalModelBinder like the following and add it to the root of your project for example:
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;
}
}
}
Inside Global.asax.cs, make use of it in Application_Start() like this:
ModelBinders.Binders.Add(typeof(decimal?), new DecimalModelBinder());
回答2:
You are one of the non-English customers, which MS has not foreseen. You will need to put some extra effort into making your version run. I had a similar problem, denying me both "9,99" and "9.99" as valid numbers. It seems like once server-side validation failed, and once client-side validation, causing no number to be accepted.
So you have to make the validation congruent.
Like suggested in the comments, have a look at http://msdn.microsoft.com/en-us/library/gg674880(VS.98).aspx and http://haacked.com/archive/2010/05/10/globalizing-mvc-validation.aspx and MVC 3 jQuery Validation/globalizing of number/decimal field or - should you understand German (or just look at the code examples) http://www.andreas-reiff.de/2012/06/probleme-mit-mvcmovies-beispiel-validierung-des-preises-mit-dezimalstellen-schlagt-fehl/
BTW, same problem exists for both the Music and Movie example tutorials.
回答3:
I encountered this issue when developing a web application for an English audience, on a Pc in The Netherlands.
A model property of type double, generated this server-side validation error:
The value '1.5' is not valid for .
On an breakpoint, I saw these values in the Immediate Window:
?System.Threading.Thread.CurrentThread.CurrentUICulture
{en-US}
?System.Threading.Thread.CurrentThread.CurrentCulture
{nl-NL}
As a solution (or maybe a work-around), you can specify the globalization settings in the web.config file.
<configuration>
<system.web>
<globalization culture="en" uiCulture="en" />
Of course this means that you force your users to enter numbers in English formatting, but that is just fine, in my case.
回答4:
I've adapted the code from Leniel Macaferi a little bit so you can use it for any type:
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;
}
}
回答5:
I've tried @Leniel Macaferi but it didn't work for me.
ModelState.IsValid didn't accept numbers formatted like 7.000,00
The problem started when I changed the property type from:
[Column("PRICE")]
public decimal Price { get; set; }
to
[Column("PRICE")]
public decimal? Price { get; set; }
I've also tried to include the globalization on web.config that I had forgotten
<globalization culture="pt-BR" uiCulture="pt-BR" enableClientBasedCulture="true" />
The only workaround that worked was change back the property to decimal only:
[Column("PRICE")]
public decimal Price { get; set; }
and also changed the table column to NOT accept null values
Hope it helps somebody.
回答6:
You can add:
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 (tested on MVC 5.1). It works without changing UICulture for me.
回答7:
I solved this problem by disabled jquery for price and only validate on server side for that input. I found the answer here: ASP .NET MVC Disable Client Side Validation at Per-Field Level
<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>
回答8:
In 2019, this problem is still not solved. Using ASP Core 2.1, my UI is in French (decimal separator= ',') and I couldn't get the validation to work anytime I had a decimal number.
I found a workaround, not ideal though: I created a french-based CultureInfo but I changed the decimal separator to be the same as in Invariant Culture : '.'.
This made the trick, my decimal numbers are now displayed US style (but I am ok with it) and validation works.
// 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;
}
回答9:
Just comment this link for the script:
<%--<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>--%>
来源:https://stackoverflow.com/questions/11822480/error-with-decimal-in-mvc3-the-value-is-not-valid-for-field