asp.net-mvc mvc3 中的十进制错误 - 该值对字段无效

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11822480/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 02:09:16  来源:igfitidea点击:

error with decimal in mvc3 - the value is not valid for field

asp.net-mvcasp.net-mvc-3razordecimalmodel-binding

提问by furyfish

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."

我正在关注 [ASP.NET MVC 3 入门][1]。而且我无法添加/编辑 Price = 9.99 或 9,99 的值。它说:“价值‘9.99’对价格无效。” 和“价格字段必须是一个数字。”

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; }
}

回答by Leniel Maccaferri

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...

2年后,我再次偶然发现了这一点。我认为 ASP.NET MVC 5 已经解决了这个问题,但看起来并非如此。所以这里是如何解决这个问题......

Create a class called DecimalModelBinderlike the following and add it to the root of your project for example:

创建一个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;
        }
    }
}

Inside Global.asax.cs,make use of it in Application_Start()like this:

在里面像这样Global.asax.cs,使用它Application_Start()

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

回答by Andreas Reiff

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.

您是 MS 没有预见到的非英语客户之一。您需要付出一些额外的努力来运行您的版本。我遇到了类似的问题,拒绝将“9,99”和“9.99”作为有效数字。好像一次服务器端验证失败,一次客户端验证,导致没有数字被接受。

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).aspxand http://haacked.com/archive/2010/05/10/globalizing-mvc-validation.aspxand MVC 3 jQuery Validation/globalizing of number/decimal fieldor - 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/

就像评论中建议的那样,请查看 http://msdn.microsoft.com/en-us/library/gg674880(VS.98).aspxhttp://haacked.com/archive/2010/05/10 /globalizing-mvc-validation.aspxMVC 3 jQuery Validation/globalizing of number/decimal fieldor - 如果你懂德语(或者只看代码示例) 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.

顺便说一句,音乐和电影示例教程都存在同样的问题。

回答by R. Schreurs

I encountered this issue when developing a web application for an English audience, on a Pc in The Netherlands.

我在荷兰的一台 PC 上为英语受众开发 Web 应用程序时遇到了这个问题。

A model property of type double, generated this server-side validation error:

double 类型的模型属性生成了此服务器端验证错误:

The value '1.5' is not valid for .

值“1.5”对 无效。

On an breakpoint, I saw these values in the Immediate Window:

在断点上,我在Immediate Window 中看到了这些值:

?System.Threading.Thread.CurrentThread.CurrentUICulture

{en-US}

{zh-CN}

?System.Threading.Thread.CurrentThread.CurrentCulture

{nl-NL}

{nl-NL}

As a solution (or maybe a work-around), you can specify the globalization settings in the web.config file.

作为解决方案(或者可能是变通办法),您可以在 web.config 文件中指定全球化设置。

<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.

当然,这意味着您强制您的用户以英文格式输入数字,但就我而言,这很好。

回答by Rafael Araújo

I've tried @Leniel Macaferibut it didn't work for me.

我试过@Leniel Macaferi,但它对我不起作用。

ModelState.IsValid didn't accept numbers formatted like 7.000,00

ModelState.IsValid 不接受格式为 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

我还尝试在 web.config 中包含我忘记的全球化

<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.

希望它可以帮助某人。

回答by XavierAM

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.

2019年,这个问题依然没有解决。使用 ASP Core 2.1,我的 UI 是法语(小数分隔符 = ','),我无法在有十进制数的任何时候进行验证。

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 : '.'.

我找到了一种解决方法,但并不理想:我创建了一个基于法语的 CultureInfo,但我将小数点分隔符更改为与 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;

    }

回答by BineG

I've adapted the code from Leniel Macaferi a little bit so you can use it for any type:

我稍微修改了 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;
    }
}

回答by Dave_cz

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.

Global.asax(在 MVC 5.1 上测试)。它可以在不改变 UICulture 的情况下对我来说有效。

回答by JohanH

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

我通过禁用 jquery 来解决这个问题,并且只在服务器端验证该输入。我在这里找到了答案: 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>

回答by Bobi0204

Just comment this link for the script:

只需评论该脚本的链接:

<%--<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>--%>