我有一个 ViewModel,它有一些 DataAnnotations 验证,然后为了更复杂的验证实现 IValidatableObject 并使用 Validate 方法。
我期待的行为是这样的:首先是所有 DataAnnotations,然后,只有在没有错误的情况下,才使用 Validate 方法。我怎么发现这并不总是正确的。我的 ViewModel(演示版)有三个文件 one string
、 onedecimal
和 one decimal?
。所有三个属性都只有Required 属性。对于string
和 ,decimal?
行为是预期的,但对于decimal
,当为空时,必需的验证失败(到目前为止一切都很好),然后执行 Validate 方法。如果我检查该属性,它的值为零。
这里发生了什么?我错过了什么?
注意:我知道Required 属性是假设检查值是否为空。因此,我希望被告知不要在不可为空的类型中使用 Required 属性(因为它永远不会触发),或者,该属性以某种方式理解 POST 值并注意该字段未填充。在第一种情况下,该属性不应触发,而应触发 Validate 方法。在第二种情况下,属性应该触发并且 Validate 方法不应该触发。但我的结果是:属性触发和 Validate 方法触发。
这是代码(没什么特别的):
控制器:
public ActionResult Index()
{
return View(HomeModel.LoadHome());
}
[HttpPost]
public ActionResult Index(HomeViewModel viewModel)
{
try
{
if (ModelState.IsValid)
{
HomeModel.ProcessHome(viewModel);
return RedirectToAction("Index", "Result");
}
}
catch (ApplicationException ex)
{
ModelState.AddModelError(string.Empty, ex.Message);
}
catch (Exception ex)
{
ModelState.AddModelError(string.Empty, "Internal error.");
}
return View(viewModel);
}
模型:
public static HomeViewModel LoadHome()
{
HomeViewModel viewModel = new HomeViewModel();
viewModel.String = string.Empty;
return viewModel;
}
public static void ProcessHome(HomeViewModel viewModel)
{
// Not relevant code
}
视图模型:
public class HomeViewModel : IValidatableObject
{
[Required(ErrorMessage = "Required {0}")]
[Display(Name = "string")]
public string String { get; set; }
[Required(ErrorMessage = "Required {0}")]
[Display(Name = "decimal")]
public decimal Decimal { get; set; }
[Required(ErrorMessage = "Required {0}")]
[Display(Name = "decimal?")]
public decimal? DecimalNullable { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
yield return new ValidationResult("Error from Validate method");
}
}
看法:
@model MVCTest1.ViewModels.HomeViewModel
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
@using (Html.BeginForm(null, null, FormMethod.Post))
{
<div>
@Html.ValidationSummary()
</div>
<label id="lblNombre" for="Nombre">Nombre:</label>
@Html.TextBoxFor(m => m.Nombre)
<label id="lblDecimal" for="Decimal">Decimal:</label>
@Html.TextBoxFor(m => m.Decimal)
<label id="lblDecimalNullable" for="DecimalNullable">Decimal?:</label>
@Html.TextBoxFor(m => m.DecimalNullable)
<button type="submit" id="aceptar">Aceptar</button>
<button type="submit" id="superAceptar">SuperAceptar</button>
@Html.HiddenFor(m => m.Accion)
}