如何获取模型属性的id以与MVC3中的自定义IClientValidatable一起使用

我正在尝试编写一个自定义validation属性,该属性将有条件地要求基于模型的布尔属性的字段。

我有我的属性实现IClientValidatable。 我有要检查的属性的名称,但我不知道如何获取目标属性的客户端ID。

public IEnumerable GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { var clientTarget = ?????; var rule = new ModelClientValidationRule() { ErrorMessage = FormatErrorMessage(metadata.DisplayName ?? metadata.PropertyName), ValidationType = "requiredif" }; rule.ValidationParameters["target"] = clientTarget; yield return rule; } 

javascript:

 $.validator.addMethod("requiredif", function (value, element, target) { //check on value of target }); $.validator.unobtrusive.adapters.addSingleVal("requiredif", "target"); 

如何获取目标属性的客户端ID,以便客户端javascript可以检查值?

我接受了Nathan的优秀答案,添加了一些注释,并将其包装在名为GetHtmlId的扩展方法中,因此现在我可以使用这样的代码来获取同一页面上任何其他元素的HTML ID:

  public virtual IEnumerable GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { var rule = new ModelClientValidationRule { ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()), ValidationType = "requiredif", }; // Find the value on the control we depend on... string depProp = this.GetHtmlId(metadata, context, this.DependentPropertyName); rule.ValidationParameters.Add("dependentproperty", depProp); yield return rule; } 

这是扩展方法:

 using System; using System.Collections.Generic; using System.Web.Mvc; namespace sbs.Lib.Web.ValidationAttributes { public static class IClientValidatableExtensions { ///  Returns the HTML ID of the specified view model property.  ///  Based on: http://stackoverflow.com/a/21018963/1637105  ///  The model metadata.  ///  The view context.  ///  The name of the view model property whose HTML ID is to be returned.  public static string GetHtmlId(this IClientValidatable me, ModelMetadata metadata, ControllerContext context, string propertyName) { var viewContext = context as ViewContext; if (viewContext == null || viewContext.ViewData.TemplateInfo.HtmlFieldPrefix == string.Empty) { return propertyName; } else { // This is tricky. The "Field ID" returned by GetFullHtmlFieldId is the HTML ID // attribute created by the MVC view engine for the property whose validator is // being set up by the caller of this routine. This code removes the property // name from the Field ID, then inserts the specified property name. // Of course, this only works for elements on the same page as the caller of // this routine! string fieldId = viewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(""); fieldId = fieldId.Remove(fieldId.LastIndexOf("_")); return fieldId + "_" + propertyName; } } } } 

这只是用MVC5测试的,但我怀疑它没有从MVC3改变。

这有点难看,但似乎有效。 有两个假设:

  1. MVC框架实际上总是传入一个ViewContext用于GetClientValidationRules(....)ControllerContext参数。 在我的所有测试中都是如此,但我不能保证这100%。
  2. 另一个属性位于相同的模型类级别(例如,不是复杂类型的子属性)

如果这两个假设都成立,则以下似乎有效:

  var viewContext = (ViewContext)context; if(ViewData.TemplateInfo.HtmlFieldPrefix != string.Empty) { string fieldId = viewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(""); fieldId = fieldId.Remove(fieldId.LastIndexOf("_")); fieldId = fieldId + "_" + BooleanPropertyName } else { string fieldId = BooleanPropertyName } 

这对我有用,可能需要一些调整,但你可以得到这个想法:

 public IEnumerable GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { var rule = new ModelClientValidationRule() { ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()), ValidationType = "requiredif", }; string depProp = BuildDependentPropertyId(metadata, context as ViewContext); // find the value on the control we depend on; // if it's a bool, format it javascript style // (the default is True or False!) string targetValue = (this.TargetValue ?? "").ToString(); if (this.TargetValue != null && this.TargetValue.GetType() == typeof(bool)) targetValue = targetValue.ToLower(); rule.ValidationParameters.Add("dependentproperty", depProp); rule.ValidationParameters.Add("targetvalue", targetValue); yield return rule; } private string BuildDependentPropertyId(ModelMetadata metadata, ViewContext viewContext) { return QualifyFieldId(metadata, this.DependentProperty, viewContext); } 

属性属性如:

 [RequiredIf("SelectedPeriod", "DateRange", ErrorMessageResourceName = "FromDateRequired", ErrorMessageResourceType = typeof(Common))] public DateTime? StartDate { get; set; } //dependent property public string SelectedPeriod { get; set; } 

这是如何获得字段ID:

 protected string QualifyFieldId(ModelMetadata metadata, string fieldId, ViewContext viewContext) { // build the ID of the property string depProp = viewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(fieldId); var thisField = metadata.PropertyName + "_"; if (depProp.StartsWith(thisField)) // strip it off again depProp = depProp.Substring(thisField.Length); else if (null != metadata.ContainerType && !string.IsNullOrEmpty(metadata.ContainerType.Name)) { depProp = metadata.ContainerType.Name + "_" + fieldId; } return depProp; } 

看看这篇文章 。 它讨论了服务器端的DataAnnotationvalidation,它还演示了如何通过实现IClientVaildatable并在客户端编写一些jquery来在客户端挂钩这些属性。