2011-08-04 74 views
1

我有一個StartMate和一個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方法的單元測試中正常工作。如果我在Controller中的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。除非有人知道如何在虛擬機上啓用ValidationAttributes,即使存在屬性錯誤.... –

+0

對於任何訪問此功能的人,都有一些強制驗證運行的好選擇。請參閱http:// stackoverflow。COM /問題/ 6431478 /如何對力MVC到驗證,ivalidatableobject –

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;並再次運行它應該會看到只有標題錯誤出現。 –