web-dev-qa-db-fra.com

erreur avec décimal dans mvc3 - la valeur n'est pas valide pour le champ

Je suis [Premiers pas avec ASP.NET MVC 3] [1]. Et je ne peux pas ajouter/modifier avec la valeur Price = 9.99 ou 9,99. Il a déclaré: "La valeur '9.99' n'est pas valable pour Price." et "Le champ Prix doit être un nombre."

Comment régler ceci?

Modèle:

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

Manette:

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

Vue:

    @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; }
}
26
furyfish

Je suis juste tombé dessus à nouveau après 2 ans. Je pensais que ASP.NET MVC 5 avait résolu ce problème, mais il semble que ce ne soit pas le cas. Alors, voici comment résoudre le problème ...

Créez une classe appelée DecimalModelBinder comme suit et ajoutez-la à la racine de votre projet, par exemple:

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

Dans Global.asax.cs,, utilisez-le dans Application_Start() comme ceci:

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

Vous êtes l'un des clients non anglophones, ce que MS n'a pas prévu. Vous devrez déployer des efforts supplémentaires pour faire fonctionner votre version. J'ai eu un problème similaire, me refusant à la fois "9,99" et "9,99" comme numéros valides. On dirait qu’une fois la validation côté serveur a échoué et qu’une validation côté client n’a abouti, aucun numéro n’a été accepté.

Il faut donc que la validation soit congruente.

Comme suggéré dans les commentaires, jetez un coup d'œil à http://msdn.Microsoft.com/en-us/library/gg674880(VS.98).aspx Et http://haacked.com/archive/2010/05/10/globalizing-mvc-validation.aspx et MVC 3 jQuery Validation/globalisation du nombre/champ décimal ou - si vous comprenez l'allemand (ou regardez les exemples de code) http://www.andreas-reiff.de/2012/06/probleme-mit-mvcmovies-beispiel-validierung-des-preises- mit-dezimalstellen-schlagt-fehl/

En passant, le même problème existe pour les exemples de tutoriels Musique et Film.

6
Andreas Reiff

J'ai rencontré ce problème lors du développement d'une application Web destinée à un public anglais, sur un ordinateur aux Pays-Bas. 

Une propriété de modèle de type double a généré cette erreur de validation côté serveur: 

La valeur '1.5' n'est pas valide pour.

Sur un point d'arrêt, j'ai vu ces valeurs dans la fenêtre Immediate :

?System.Threading.Thread.CurrentThread.CurrentUICulture

{en-US}

?System.Threading.Thread.CurrentThread.CurrentCulture

{nl-NL}

En tant que solution (ou peut-être une solution de rechange), vous pouvez spécifier les paramètres de globalisation dans le fichier web.config.

<configuration>
  <system.web>
    <globalization culture="en" uiCulture="en" />

Bien sûr, cela signifie que vous obligez vos utilisateurs à entrer des chiffres au format anglais, mais cela me convient parfaitement, dans mon cas.

2
R. Schreurs

J'ai adapté un peu le code de Leniel Macaferi afin que vous puissiez l'utiliser pour tous les types:

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

J'ai résolu ce problème en désactivant jquery pour le prix et ne valide que côté serveur pour cette entrée. J'ai trouvé la réponse ici: ASP .NET MVC Désactive la validation côté client au niveau de chaque champ

<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>
1
JohanH

J'ai essayé @Leniel Macaferi mais cela n'a pas fonctionné pour moi.

ModelState.IsValid n'accepte pas les nombres au format 7.000,00 

Le problème a commencé lorsque j'ai changé le type de propriété de:

[Column("PRICE")]
public decimal Price { get; set; }

à

[Column("PRICE")]
public decimal? Price { get; set; }

J'ai aussi essayé d'inclure la mondialisation sur web.config que j'avais oubliée

<globalization culture="pt-BR" uiCulture="pt-BR" enableClientBasedCulture="true" />

La seule solution de contournement qui a fonctionné a été de rétablir la propriété décimale uniquement:

[Column("PRICE")]
public decimal Price { get; set; }

et également changé la colonne de la table pour ne pas accepter les valeurs NULL

J'espère que ça aide quelqu'un.

1
Rafael Araújo