2016-06-28 13 views
1

私はASP.NET MVC 5アプリケーションで作業していますが、プロジェクト所有者はnullable型以外の型の検証に起因する「アンダーポスト」問題を懸念しています(http://bradwilson.typepad.com/blog/2010/01/input-validation-vs-model-validation-in-aspnet-mvc.htmlおよびhttp://www.asp.net/web-api/overview/formats-and-model-binding/model-validation-in-aspnet-web-apiに記載されているように)。nullを許可しない型のASP.NET MVC 5モデルの検証(Int32)

私はこの問題をASP.NET MVC 5で再現するためのテストケースを作成しましたが、運がありません。

モデル:

public class ContactModel 
{ 
    [Required] 
    public Int32 data1 { get; set; } 

    public Int32 data2 { get; set; } 
} 

ビュー:

<div class="form-group"> 
    @Html.LabelFor(model => model.data1) 
    <div> 
     @Html.EditorFor(model => model.data1) 
    </div> 
</div> 
<div> 
    @Html.LabelFor(model => model.data2) 
    <div> 
     @Html.EditorFor(model => model.data2) 
    </div> 
</div> 

コントローラー:

public ActionResult Index(Models.ContactModel contact) 
{ 
    if (ModelState.IsValid) 
    { 
     Response.Write("modelstate is valid<br>"); 

     return View(); 
    } 
    else 
    { 
     Response.Write("modelstate is invalid<br>"); 

     return View(); 
    } 
} 

それは思わdata1data2はポストにnullのとき、モデルにおけるそれらの値( contact)は0になります。ただし、ModelState.IsValidは0になります。 真のの代わりに2つの記事に示されています)。

私が持っているもの:

enter image description here

第二の記事は示したもの:

enter image description here

私はASP.NETでどのように機能するかのモデルの検証上の変更に関するすべての情報を見つけることができませんでしたMVCなので、私はテストケースに何か間違っていると思っています。どんな考えや提案も感謝しています。

+2

'(必須の)'属性は 'int'プロパティには必要ありません(カスタムエラーメッセージが必要な場合を除き)。' int'は 'null'になることはありません。 'DefaultModelBinder'は、' int'に 'null'を代入することができず、' ModelState.IsValid = false'をセットするので、エラーを追加します。しかし、それは 'int'のデフォルト値であるので、値は' 0'です –

+0

@StephenMueckeこれは私が最初に考えたものです。しかし、ブラッドウィルソン(私の質問の最初のリンク)の投稿によると:_これのオフショットは、[必須]は、nullable値の型では、フォームが値を含むことを保証するものではありません。値が含まれていない場合、モデル・バインディングはスキップされます。つまり、モデル・バインディングの失敗は発生しません。さらに、[必須]バリデーターが実行されると、値型のデフォルト値(通常は0)を含むモデルから値を照会し、「それはヌルではなく、すべてがすべてここでうまくいきます」。 – Jim

+0

これは間違っており、モデルのバインディングは決してスキップされません。値型であるプロパティや '[Required]'属性を持つ参照型に対して値が送られた場合、 'ModelState.IsValid'は常にfalseになります –

答えて

1

あなたのModelStateが偽である理由は、投稿がモデルの各プロパティからフォーム値を提供しているためです。本質的に、モデルバインディングシステムは、@ Html.EditorForヘルパーを明示的にの両方のプロパティのために書いているので、data1とdata2フィールドの両方の妥当性をチェックしています(実際には過小ポストは起こりません)。

記事のアンダーポストの懸念をうまく再現しました。ビュー内のEditorForヘルパーの1つを削除するだけで、実際には下に置いています。どちらのヘルパーも存在しているので、過ちを打ちのめすことはありません。

ビュー:

<div class="form-group"> 
    @Html.LabelFor(model => model.data1) 
    <div> 
     @Html.EditorFor(model => model.data1) 
     @Html.ValidationMessageFor(model => model.data1) 
     @Html.ValidationMessageFor(model => model.data2) 
    </div> 
</div> 

が@htmlを残していることを確認しますので、ビューには、今、この(私は何が起こっているのビューにフィードバックを得るために両方のプロパティの検証ヘルパーを追加注意してください)のように見えます。 EditorForヘルパーは、data2プロパティに対して完全にオフです。フォームフィールドにゼロを記入してください(ここではフォームフィールドは1つだけです)、あなたの行動に投稿してください。

このシナリオでは、フォームフィールドが1つしか転記されていなくても、ModelStateはtrueに戻ります。誰かが過小評価しても良い結果にはならない!したがって、フォームフィールドがフォームから除外されている場合に、アンダーポストの問題が発生する(わずかに変更された)元のモデルクラスがあります(両方のプロパティが値型であるため、このような状況ではRequired属性は違いを生じません)。

//You could add the Required attribute or not, doesn't matter at this point. 
//The concern here is that the Modelstate will still come back as Valid 
//in the case of a form field being left off of your form (or someone underposts). 
//So to replicate underposting issues, make sure to comment or delete 
//at least one Html.EditorFor helper in the view. 

//[Required] Underposting will occur regardless if this is marked required or not, 
//so be careful if someone does underpost your form. 
public Int32 data1 { get; set; } 

//[Required] 
public Int32 data2 { get; set; } 

ソリューションあなたはunderposting問題を解決したい場合: は単に必要に応じて両方の性質をマークし、そのようなあなたが提供する記事、で述べたように、それらがNULL可能にする:

[Required] 
public Int32? data1 { get; set; } 

[Required] 
public Int32? data2 { get; set; } 

今@ Html.EditorForヘルパーが欠落しているか、フォームフィールドがない場合、ModelState V偽名は偽に戻ってくるでしょうし、あなたは過小評価の問題から保護されています。

+0

ありがとう!これは非常に有望ですね。私は今日これを複製し、それが動作すれば答えをマークしようとします。 – Jim

+0

恐ろしいジム。私はデバッガを介してそれを実行し、すべての動作が必要な動作を確認した。もしあなたがそれに疑問を持っているなら私に知らせてください。ところで、私はあなたの質問に出会ってうれしいです。そのRequired属性は誤解を招く可能性があり、注意しないと突然あなたがデフォルト値に設定されたプロパティを得ることができます。ありがとう、ティム – firecape

関連する問題