2011-08-04 8 views
1

私はStartDateとEndDateを持つViewModelを持っています。明らかに、StartDate < = EndDateを検証する必要があります。MVC3サーバーの検証が実行されない

私はStartDateBeforeEndDate検証属性を作成し、それをのViewModelクラスを飾ら:

public class ValidProgramDisplayStartDateAttribute : ValidationAttribute 
{ 
    public override bool IsValid(object value) 
    { 
     ProgramCreateOrEditViewModel vm = value as ProgramCreateOrEditViewModel; 
     if (vm == null) return true; //not our problem 

     if (!vm.EndDisplay.HasValue) return true; 
      //if you don't set an end date, you can't be invalid 

     return vm.StartDisplay <= vm.EndDisplay; 
    } 
} 

...

[ValidProgramDisplayStartDate(ErrorMessage="The program start display date cannot be after the program display end date.")] 
public class ProgramCreateOrEditViewModel 
{ 

    [Required(ErrorMessage = "A program title is required.")] 
    [StringLength(255, ErrorMessage = "The program title cannot exceed 255 characters.")] 
    public virtual string Title { get; set; } 

    private DateTime _startDisplayDate = DateTime.Now; 

    [Display(Name = "Display Start Date")] 
    [Required(ErrorMessage = "A start display date is required")] 
    [DataType(DataType.Date)] 
    public virtual DateTime StartDisplay { get { return _startDisplayDate; } set { _startDisplayDate = value; } } 

    [Display(Name="Display End Date")] 
    [DataType(DataType.Date)] 
    public virtual DateTime? EndDisplay { get; set; } 

...more properties omitted... 
} 

タイトルが正しく検証し、その検証メッセージのように、検証概要に表示されますIsValidのブレークポイントは決して起動せず、無効なペアリングを指定すると検証エラーは表示されません。

ValidationAttributeは、ViewModelオブジェクトを作成し、日付を取り込み、ValidationAttributeオブジェクトを作成し、そのIsValidメソッドを呼び出すユニットテストで正しく機能します。コントローラのPOSTアクションにブレークポイントを設定し、Visual Studioの直後のウィンドウを使用してValidationAttributeを構築し、受け取ったViewModelを渡すと正しく動作します。

私は実際にこの段階でクライアント側の検証について気にしません。それは「いいですが、誰が時間を持っているの?」の下に提出されていますか?しかし、サーバー側の検証は不可欠です。

ビュー:

@model MyProject.Web.Mvc.Controllers.ViewModels.ProgramCreateOrEditViewModel 
@using MvcContrib.FluentHtml 
@{ 
    ViewBag.Title = "Index"; 
} 

<h2>Index</h2> 
@using (Html.BeginForm()) 
{ 

<fieldset class="program"><legend>Program</legend> 
    @if (!ViewData.ModelState.IsValid) 
    { 
     <p class="error">Please correct all errors listed below. The program cannot be saved while errors remain.</p> 
     @Html.ValidationSummary(false) 
    } 
    @Html.HiddenFor(m => m.Id) 
    <h3> 
     @Html.LabelFor(m => m.Title) 
     @Html.TextBoxFor(m => m.Title)</h3> 
    <div id="accordion"> 
     <h3><a href="#">Dates:</a></h3> 
     <div class="section"> 
      Dates related to <em>displaying</em> the program on our site:<br /> 
      @Html.LabelFor(m => m.StartDisplay) 
      @Html.EditorFor(m => m.StartDisplay, new { _class = "date" }) 
      @Html.LabelFor(m => m.EndDisplay) 
      @Html.EditorFor(m => m.EndDisplay, new { _class = "date enddisplay" }) 
     </div> 
    ... more form fields omitted ... 
    </div> 
    <p> 
     <input type="submit" value="Save" /></p> 
</fieldset> 
} 

そして最後に、エディタテンプレート:

@model DateTime? 
@Html.TextBox("", Model.HasValue ? Model.Value.ToString("MM/dd/yyyy") : String.Empty, new { @class = "date" }) 
+0

UnobtrusiveJavaScriptが必要な場合は有効になっていることを確認しましたか? – stack72

+0

私はこの道を見下ろすのに気にしていませんでしたが、私は完全にサーバー側を心配しています。JavaScriptがサーバー側の検証に影響を与えている場合は、今日はさらにカフェインが必要になります。 :) –

答えて

1

問題は、クラスのプロパティのいずれかのモデルのエラーがある場合、クラスValidationAttributeが処理されないことであるように思われます。クラス内のValidationAttributesがすべて満たされた後にのみ処理されます。

[ValidProgramDisplayStartDate(ErrorMessage="The program start display date cannot be after the program display end date.")]をクラスの装飾からIDプロパティの装飾に移動すると、他のモデルのエラーがあっても、サーバー側の検証が行われます。

counsellorben

+0

それは正しいと思われ、ひどく迷惑です。 validationcontextにアクセスしてViewModelを取得するために、属性クラスを変更する必要があります。プロパティーのエラーがあっても誰かがVM上のValidationAttributesを作成する方法を知っていない限り、... –

+0

これを訪問している人には、検証を実行するためのいくつかの良いオプションがあります。 http:// stackoverflowを参照してください。com/questions/6431478/how-to-force-mvc-to-validate-ivalidatableオブジェクト –

1

は奇妙な、次のコードは、私のために素晴らしい仕事。

コントローラー:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     return View(new ProgramCreateOrEditViewModel 
     { 
      StartDisplay = DateTime.Now, 
      EndDisplay = DateTime.Now.AddDays(-1), 
      Title = "foo bar" 
     }); 
    } 

    [HttpPost] 
    public ActionResult Index(ProgramCreateOrEditViewModel model) 
    { 
     return View(model); 
    } 
} 

ビュー:

@model ProgramCreateOrEditViewModel 

@using (Html.BeginForm()) 
{ 
    <fieldset class="program"> 
     <legend>Program</legend> 

     @if (!ViewData.ModelState.IsValid) 
     { 
      <p class="error">Please correct all errors listed below. The program cannot be saved while errors remain.</p> 
      @Html.ValidationSummary(false) 
     } 

     <h3> 
      @Html.LabelFor(m => m.Title) 
      @Html.TextBoxFor(m => m.Title) 
     </h3> 
     <div id="accordion"> 
      <h3><a href="#">Dates:</a></h3> 
      <div class="section"> 
       Dates related to <em>displaying</em> the program on our site:<br /> 
       @Html.LabelFor(m => m.StartDisplay) 
       @Html.EditorFor(m => m.StartDisplay, new { _class = "date" }) 
       @Html.LabelFor(m => m.EndDisplay) 
       @Html.EditorFor(m => m.EndDisplay, new { _class = "date enddisplay" }) 
      </div> 
     </div> 
     <p><input type="submit" value="Save" /></p> 
    </fieldset> 
} 
+0

後で@counselorbenによって指摘されたように、これはプロパティレベルの検証エラーがないために機能します。あなたの例をTitle = String.Emptyに変更した場合、再度実行すると、タイトルエラーだけが表示されるはずです。 –

関連する問題