IDateErrorInfo
IDateErrorInfo由MVC框架支持(微軟的教程可以發現here)。默認模型聯編程序將負責通過將html表單元素綁定到模型來重新創建模型對象。如果模型聯編程序檢測到模型實現了接口,那麼它將使用接口方法來驗證模型中的每個屬性,或者將模型作爲一個整體進行驗證。有關更多信息,請參閱教程。
如果你想使用此方法,然後使用客戶端驗證(引用史蒂夫·桑德森)「最直接的方式,以充分利用額外的驗證規則是手動生成視圖所需要的屬性」:
<p>
@Html.TextBoxFor(m.ClientName, new { data_val = "true", data_val_email = "Enter a valid email address", data_val_required = "Please enter your name"})
@Html.ValidationMessageFor(m => m.ClientName)
</p>
這可以用來觸發任何已定義的客戶端驗證。請參閱下面的示例以瞭解如何定義客戶端驗證。
明確驗證
正如你所說,你可以明確地驗證在動作模型。例如:
public ViewResult Register(MyModel theModel)
{
if (theModel.PropertyB < theModel.PropertyA)
ModelState.AddModelError("", "PropertyA must not be less then PropertyB");
if (ModelState.IsValid)
{
//save values
//go to next page
}
else
{
return View();
}
}
在視圖你會然後需要使用@Html.ValidationSummary
顯示錯誤消息作爲上述代碼將增加一個模型電平誤差,而不是一個屬性電平誤差。
要指定你可以寫一個屬性級別的錯誤:
ModelState.AddModelError("PropertyA", "PropertyA must not be less then PropertyB");
然後在視圖中使用:
@Html.ValidationMessageFor(m => m.PropertyA);
顯示錯誤消息。
此外,任何客戶端驗證都需要通過在視圖中通過定義屬性手動鏈接到客戶端驗證來鏈接。
定義模型驗證屬性
如果我理解正確的問題,您要驗證它包含一個單值和集合,其中在集合的屬性是要總結的模型。
對於我將給出的例子,視圖將向用戶呈現最大值字段和5個值字段。最大值字段將是模型中的單個值,其中5個值字段將成爲集合的一部分。驗證將確保值字段的總和不大於最大值字段。驗證將被定義爲模型上的一個屬性,該屬性也將很好地鏈接到JavaScript客戶端的閾值。
的觀點:
@model MvcApplication1.Models.ValueModel
<h2>Person Ages</h2>
@using (@Html.BeginForm())
{
<p>Please enter the maximum total that will be allowed for all values</p>
@Html.EditorFor(m => m.MaximumTotalValueAllowed)
@Html.ValidationMessageFor(m => m.MaximumTotalValueAllowed)
int numberOfValues = 5;
<p>Please enter @numberOfValues different values.</p>
for (int i=0; i<numberOfValues; i++)
{
<p>@Html.EditorFor(m => m.Values[i])</p>
}
<input type="submit" value="submit"/>
}
,因爲我不想過於複雜的例子我還沒有添加任何驗證對值字段。
模型:
public class ValueModel
{
[Required(ErrorMessage="Please enter the maximum total value")]
[Numeric] //using DataAnnotationExtensions
[ValuesMustNotExceedTotal]
public string MaximumTotalValueAllowed { get; set; }
public List<string> Values { get; set; }
}
以下動作:
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(ValueModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
else
{
return RedirectToAction("complete"); //or whatever action you wish to define.
}
}
自定義屬性:
在模型定義的[ValuesMustNotExceedTotal]
屬性可以通過重寫來定義Valida tionAttribute類:
public class ValuesMustNotExceedTotalAttribute : ValidationAttribute
{
private int maxTotalValueAllowed;
private int valueTotal;
public ValuesMustNotExceedTotalAttribute()
{
ErrorMessage = "The total of all values ({0}) is greater than the maximum value of {1}";
}
public override string FormatErrorMessage(string name)
{
return string.Format(ErrorMessageString, valueTotal, maxTotalValueAllowed);
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
PropertyInfo maxTotalValueAllowedInfo = validationContext.ObjectType.GetProperty("MaximumTotalValueAllowed");
PropertyInfo valuesInfo = validationContext.ObjectType.GetProperty("Values");
if (maxTotalValueAllowedInfo == null || valuesInfo == null)
{
return new ValidationResult("MaximumTotalValueAllowed or Values is undefined in the model.");
}
var maxTotalValueAllowedPropertyValue = maxTotalValueAllowedInfo.GetValue(validationContext.ObjectInstance, null);
var valuesPropertyValue = valuesInfo.GetValue(validationContext.ObjectInstance, null);
if (maxTotalValueAllowedPropertyValue != null && valuesPropertyValue != null)
{
bool maxTotalValueParsed = Int32.TryParse(maxTotalValueAllowedPropertyValue.ToString(), out maxTotalValueAllowed);
int dummyValue;
valueTotal = ((List<string>)valuesPropertyValue).Sum(x => Int32.TryParse(x, out dummyValue) ? Int32.Parse(x) : 0);
if (maxTotalValueParsed && valueTotal > maxTotalValueAllowed)
{
return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
}
}
//if the maximum value is not supplied or could not be parsed then we still return that the validation was successful.
//why? because this attribute is only responsible for validating that the total of the values is less than the maximum.
//we use a [Required] attribute on the model to ensure that the field is required and a [Numeric] attribute
//on the model to ensure that the fields are input as numeric (supplying appropriate error messages for each).
return null;
}
}
添加客戶端驗證到自定義屬性:
要客戶端驗證到這個屬性就需要實現IClientValidatable接口:
public class ValuesMustNotExceedTotalAttribute : ValidationAttribute, IClientValidatable
{
//...code as above...
//this will be called when creating the form html to set the correct property values for the form elements
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule {
ValidationType = "valuesmustnotexceedtotal", //the name of the client side javascript validation (must be lowercase)
ErrorMessage = "The total of all values is greater than the maximum value." //I have provided an alternative error message as i'm not sure how you would alter the {0} and {1} in javascript.
};
yield return rule;
//note: if you set the validation type above to "required" or "email" then it would use the default javascript routines (by those names) to validate client side rather than the one we define
}
}
如果您將在此時運行該應用程序並查看定義屬性的字段的源html,您將看到以下內容:
<input class="text-box single-line" data-val="true" data-val-number="The MaximumTotalValueAllowed field is not a valid number." data-val-required="Please enter the maximum total value" data-val-valuesmustnotexceedtotal="The total of all values is greater than the maximum value." id="MaximumTotalValueAllowed" name="MaximumTotalValueAllowed" type="text" value="" />
特別要注意驗證屬性data-val-valuesmustnotexceedtotal
。這就是我們的客戶端驗證如何鏈接到驗證屬性。
添加客戶端驗證:
要添加您需要在視圖的標籤添加類似以下庫引用客戶端驗證:
<script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
您還需要確保客戶端驗證在web.config中打開,但我認爲這應該是默認情況下:
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
剩下的就是在視圖中定義客戶端驗證。注意,這裏添加的驗證在視圖中定義,但如果它是在一個庫,然後自定義屬性(也許不是這個)定義可以添加其他車型其他觀點:
<script type="text/javascript">
jQuery.validator.unobtrusive.adapters.add('valuesmustnotexceedtotal', [], function (options) {
options.rules['valuesmustnotexceedtotal'] = '';
options.messages['valuesmustnotexceedtotal'] = options.message;
});
//note: this will only be fired when the user leaves the maximum value field or when the user clicks the submit button.
//i'm not sure how you would trigger the validation to fire if the user leaves the value fields although i'm sure its possible.
jQuery.validator.addMethod('valuesmustnotexceedtotal', function (value, element, params) {
sumValues = 0;
//determine if any of the value fields are present and calculate the sum of the fields
for (i = 0; i <= 4; i++) {
fieldValue = parseInt($('#Values_' + i + '_').val());
if (!isNaN(fieldValue)) {
sumValues = sumValues + fieldValue;
valueFound = true;
}
}
maximumValue = parseInt(value);
//(if value has been supplied and is numeric) and (any of the fields are present and are numeric)
if (!isNaN(maximumValue) && valueFound) {
//perform validation
if (sumValues > maximumValue)
{
return false;
}
}
return true;
}, '');
</script>
這應該是它。我確信可以在這裏和那裏做出一些改進,如果我誤解了這個問題,你應該能夠根據需要調整驗證。但我相信這種驗證似乎是大多數開發人員編寫自定義屬性的方式,包括更復雜的客戶端驗證。
希望這會有所幫助。如果您對上述問題有任何疑問或建議,請告知我們。
Explicit可能不支持ClientSide驗證。但是,自定義的一個是相當不錯的,但我仍然認爲這個解決方案對於一個特定的問題有點過於通用。 –
@Ingo Vals - 我想我以前的回答誤解了你的問題。我已經更新了答案,希望這是一個更有用的解決方案。希望能幫助到你。 – Dangerous