web-dev-qa-db-ja.com

mvc3の10進数のエラー-値はフィールドには無効です

[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; }
}
28
furyfish

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());
_
36

あなたはMSが予見していない英語以外の顧客の1人です。バージョンを実行するために追加の努力をする必要があります。同様の問題があり、「9,99」と「9.99」の両方を有効な数字として拒否しました。サーバー側の検証に失敗した場合、およびクライアント側の検証に一度失敗したため、番号が受け入れられないようです。

したがって、検証を一致させる必要があります。

コメントで提案されているように、 http://msdn.Microsoft.com/en-us/library/gg674880(VS.98).aspxhttp:// haacked.com/archive/2010/05/10/globalizing-mvc-validation.aspx および MVC 3 jQuery Validation/globalizing of number/decimal field または-ドイツ語(または単にコード例を見てください) http://www.andreas-reiff.de/2012/06/probleme-mit-mvcmovies-beispiel-validierung-des-preises-mit-dezimalstellen-schlagt-fehl/ =

ところで、音楽と映画の両方のサンプルチュートリアルに同じ問題が存在します。

6
Andreas Reiff

オランダのPCで、英語のオーディエンス向けのWebアプリケーションを開発しているときにこの問題に遭遇しました。

タイプdoubleのモデルプロパティは、このサーバー側検証エラーを生成しました:

値「1.5」はでは無効です。

ブレークポイントで、これらの値をイミディエイトウィンドウで確認しました。

?System.Threading.Thread.CurrentThread.CurrentUICulture

{en-US}

?System.Threading.Thread.CurrentThread.CurrentCulture

{nl-NL}

解決策として(またはおそらく回避策として)、web.configファイルでグローバリゼーション設定を指定できます。

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

もちろん、これはユーザーに英語形式で数値を入力させることを意味しますが、私の場合はそれで十分です。

2
R. Schreurs

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

この問題は、jqueryを無効にして価格を設定し、サーバー側でのみ入力を検証することで解決しました。私はここで答えを見つけました: ASP .NET MVC Disable Client Side Validation at-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>
1
JohanH

@ 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" />

機能した唯一の回避策は、プロパティを10進数のみに戻すことでした。

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

また、テーブルの列を変更してnull値を受け入れないようにしました

それが誰かを助けることを願っています。

1
Rafael Araújo

2019年、この問題はまだ解決されていません。 ASP Core 2.1を使用して、私のUIはフランス語(10進数の区切り文字= '、')であり、10進数があるときはいつでも検証を機能させることができませんでした。

回避策を見つけましたが、理想的ではありません。フランス語ベースのCultureInfoを作成しましたが、小数点記号を変更して、インバリアントカルチャ: '。'と同じにしました。

これがトリックを作り、私の10進数はUSスタイルで表示されます(しかし、私はそれで大丈夫です)、検証は機能します。

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

    }
0
XavierAM