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

Ошибка с десятичным значением в 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; }
}
4b9b3361

Ответ 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>--%>