我有一个带有StartDate和EndDate的ViewModel。显然,我需要验证StartDate< = EndDate。
我创建了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 :(得分: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>
}
答案 1 :(得分:1)
问题似乎是,如果类属性中存在任何模型错误,则不会处理类ValidationAttribute。只有在类中的ValidationAttributes都满足后才会处理它。
出于您的目的,如果您将[ValidProgramDisplayStartDate(ErrorMessage="The program start display date cannot be after the program display end date.")]
从装饰类移动到装饰您的Id属性,那么即使存在其他模型错误,您也将获得服务器端验证。
counsellorben