/// <summary> /// Creates a <span> tag with appropriate validation information used by client side AND server side code.<br/> /// WFUtilities.FieldValidationErrorClass is applied if validation fails on a postback. This is used with an Html.<control>For() element.<br/> /// The property whose validation state is checked is derived from a strongly-typed lambda. /// </summary> /// <param name="ErrorMessage">(Optional) Override any ErrorMessage provided by resources/xml/validators with this property.</param> /// <param name="expression">An expression that identifies the property whose value will be rendered.<br/> /// ie: m => m.FirstName will render the 'FirstName' property.</param> /// <param name="htmlProperties">An anonymous object whose properties are applied to the element.<br/> /// ie: new { Class = "cssClass", onchange = "jsFunction()" } </param> /// <returns></returns> public string ValidationMessageFor <TProperty>(Expression <Func <TModel, TProperty> > expression, string ErrorMessage, object htmlProperties) { WFModelMetaProperty metaprop = null; ModelMetaData mmd = ModelMetaData.FromLambdaExpression(expression, _Model); HtmlTag span = new HtmlTag("span", new { id = mmd.PropertyName + "_validationMessage", name = mmd.PropertyName + "_validationMessage" }); string lcName = mmd.PropertyName.ToLower(); for (int i = 0; i < _MetaData.Properties.Count; i++) { if (_MetaData.Properties[i].MarkupName.ToLower() == lcName) { metaprop = _MetaData.Properties[i]; break; } } if (metaprop != null) { if (metaprop.HasError) { span.MergeObjectProperties(htmlProperties); span.AddClass(WFUtilities.FieldValidationErrorClass); if (String.IsNullOrEmpty(ErrorMessage)) { span.InnerText = metaprop.Errors.FirstOrDefault() ?? ""; } else { span.InnerText = ErrorMessage; } return(span.Render()); } } span.MergeObjectProperties(htmlProperties); span.AddClass(WFUtilities.FieldValidationValidClass); span = PreProcess(span, _MetaData, TagTypes.ValidationMessage, metaprop != null ? metaprop.MarkupName : mmd.PropertyName, metaprop != null ? metaprop.PropertyName : mmd.PropertyName, _Model); return(span.Render()); }
/// <summary> /// Creates a <span> tag with appropriate validation information used by client side AND server side code. /// WFUtilities.FieldValidationErrorClass is applied if validation fails on a postback. This is used with an Html.<control>For() element. /// </summary> /// <param name="model">The model itself.</param> /// <param name="markupName">The markup name of the Html.<control>For() element.</param> /// <param name="propertyName">Must be the property name on the model object.</param> /// <param name="ErrorMessage">Override the error message (use with care)</param> /// <param name="htmlProperties">An anonymous object whose properties are applied to the element.<br/> /// ie: new { Class = "cssClass", onchange = "jsFunction()" } </param> /// <returns>Returns a span with WFUtilities.FieldValidationErrorClass or WFUtilities.FieldValidationValidClass as the class.</returns> public string ValidationMessageFor(object model, string markupName, string propertyName, string ErrorMessage, object htmlProperties) { WFModelMetaProperty metaprop = null; HtmlTag span = new HtmlTag("span", new { id = markupName + "_validationMessage", name = markupName + "_validationMessage" }); string lcName = propertyName.ToLower(); for (int i = 0; i < _MetaData.Properties.Count; i++) { //if (_MetaData.Properties[i].ModelObject == model && _MetaData.Properties[i].PropertyName.ToLower() == lcName) if (_MetaData.Properties[i].MarkupName.ToLower() == lcName) { metaprop = _MetaData.Properties[i]; break; } } if (metaprop != null) { if (metaprop.HasError) { span.MergeObjectProperties(htmlProperties); span.AddClass(WFUtilities.FieldValidationErrorClass); if (String.IsNullOrEmpty(ErrorMessage)) { span.InnerText = metaprop.Errors.FirstOrDefault() ?? ""; } else { span.InnerText = ErrorMessage; } return(span.Render()); } } span.MergeObjectProperties(htmlProperties); span.AddClass(WFUtilities.FieldValidationValidClass); span = PreProcess(span, _MetaData, TagTypes.ValidationMessage, markupName, propertyName, model); return(span.Render()); }
/// <summary> /// Returns the raw text of any generated server-side validation error for this property.<br/> /// This is useful if you want to override the default functionality that generates a <span> tag for validation error messages. /// </summary> /// <param name="expression">An expression that identifies the property whose value will be rendered.<br/> /// ie: m => m.FirstName will render the 'FirstName' property.</param> /// <returns></returns> public string TextValidationMessageFor <TProperty>(Expression <Func <TModel, TProperty> > expression) { WFModelMetaProperty metaprop = null; ModelMetaData mmd = ModelMetaData.FromLambdaExpression(expression, _Model); string lcName = mmd.PropertyName.ToLower(); for (int i = 0; i < _MetaData.Properties.Count; i++) { if (_MetaData.Properties[i].MarkupName.ToLower() == lcName) { metaprop = _MetaData.Properties[i]; break; } } if (metaprop != null) { if (metaprop.HasError) { return(metaprop.Errors.FirstOrDefault() ?? ""); } } return(""); }
/// <summary> /// Root TryValidateModel() method. Returns false if any validation errors are found. /// </summary> /// <param name="model">A pointer to the current model object</param> /// <param name="prefix">Optional. A prefix to search and filter values from the value provider.</param> /// <param name="values">A class implementing IWFValueProvider (examples include WFObjectValueProvider and WFHttpContextValueProvider)</param> /// <param name="metadata">Optional. Required to collect error data or show error markup on a page. The current WFModelMetaData object.</param> /// <param name="ruleProvider">A class implementing IWFRuleProvider (examples include WFTypeRuleProvider and WFXmlRuleSetRuleProvider).<br/> /// This object provides the rules (ie: DataAnnotations) that needed to be validated, and which properties to validate them against.<br/> /// All other properties are ignored.</param> /// <returns>Returns false if any validation errors were found.</returns> public static bool TryValidateModel(object model, string prefix, IWFValueProvider values, WFModelMetaData metadata, IWFRuleProvider ruleProvider) { bool validated = true; //Make sure we have metadata metadata = metadata == null ? metadata = new WFModelMetaData() : metadata; metadata.Errors = new List <string>(); //Create a rule provider if one was not provided. WFTypeRuleProvider will handle [MetadataType] ruleProvider = ruleProvider == null ? new WFTypeRuleProvider(model) : ruleProvider; validated = validateModelAttributes(model, ruleProvider.GetClassValidationAttributes(), metadata.Errors, ruleProvider.ModelDisplayName); if (metadata.Errors.Count > 0) { validated = false; } foreach (PropertyInfo pi in ruleProvider.GetProperties()) { if (values.ContainsKey(prefix + pi.Name)) { WFModelMetaProperty metaprop = null; foreach (ValidationAttribute attr in ruleProvider.GetPropertyValidationAttributes(pi.Name)) { if (attr as IWFRequireValueProviderContext != null) { ((IWFRequireValueProviderContext)attr).SetValueProvider(values); } string displayName = ruleProvider.GetDisplayNameForProperty(pi.Name); bool isValid = false; if (attr.GetType() == typeof(RangeAttribute)) { try { isValid = attr.IsValid(values.KeyValue(prefix + pi.Name)); } catch (Exception ex) { if (ex.GetType() == typeof(FormatException)) { isValid = false; } else { throw ex; } } } else { isValid = attr.IsValid(values.KeyValue(prefix + pi.Name)); } if (!isValid) { validated = false; metadata.Errors.Add(attr.FormatErrorMessage(displayName)); if (metaprop == null) // Try to find it ... { foreach (WFModelMetaProperty mx in metadata.Properties) { if (mx.ModelObject == model && pi.Name.ToLower() == mx.PropertyName.ToLower()) { metaprop = mx; break; } } } if (metaprop == null) // Make a new one ... { metaprop = new WFModelMetaProperty(); metaprop.ModelObject = model; metaprop.PropertyName = pi.Name; metaprop.DisplayName = displayName; metaprop.MarkupName = prefix + pi.Name; metaprop.ValidationAttributes.Add(attr); metadata.Properties.Add(metaprop); } metaprop.HasError = true; metaprop.Errors.Add(attr.FormatErrorMessage(displayName)); } } } } return(validated); }
/// <summary> /// Find or create a WFModelMetaProperty for the DataAnnotationValidatorControl. /// The WFModelMetaProperty will be added to the WFModelMetaData object. /// </summary> /// <param name="dvc">The DataAnnotationValidatorControl whose property needs to be added to metadata.</param> /// <param name="metadata">The existing metadata to search through.</param> /// <returns></returns> public static WFModelMetaProperty GetMetaPropertyFromValidator(Control rootControl, DataAnnotationValidatorControl dvc, WFModelMetaData metadata) { Type sourceType = dvc.SourceType; Control controlValidating = WebControlUtilities.FindControlRecursive(rootControl, dvc.ControlToValidate); WFModelMetaProperty metaproperty = metadata.Properties.FirstOrDefault(m => m.MarkupName == controlValidating.UniqueID); if (metaproperty == null) { metaproperty = new WFModelMetaProperty(); metadata.Properties.Add(metaproperty); } metaproperty.PropertyName = dvc.PropertyName; metaproperty.MarkupName = controlValidating.UniqueID; if (String.IsNullOrEmpty(dvc.SourceTypeString)) { if (sourceType == null && String.IsNullOrEmpty(dvc.XmlRuleSetName) && dvc.Page as IWFGetValidationRulesForPage == null) { throw new Exception("The SourceType and SourceTypeString properties are null/empty on one of the validator controls.\r\nPopulate either property.\r\nie: control.SourceType = typeof(Widget); OR in markup SourceTypeString=\"Assembly.Classes.Widget, Assembly\""); } else if (sourceType == null && !String.IsNullOrEmpty(dvc.XmlRuleSetName)) { sourceType = WFUtilities.GetRuleSetForName(dvc.XmlRuleSetName).ModelType; } else if (sourceType == null && String.IsNullOrEmpty(dvc.XmlRuleSetName)) { sourceType = ((IWFGetValidationRulesForPage)dvc.Page).GetValidationClassType(); } } else { try { sourceType = Type.GetType(dvc.SourceTypeString, true, true); } catch (Exception ex) { throw new Exception("Couldn't resolve type " + dvc.SourceTypeString + ". You may need to specify the fully qualified assembly name."); } } PropertyInfo prop = WFUtilities.GetTargetProperty(dvc.PropertyName, sourceType); if (String.IsNullOrEmpty(dvc.XmlRuleSetName)) { foreach (var attr in prop.GetCustomAttributes(typeof(ValidationAttribute), true).OfType <ValidationAttribute>()) { var displayNameAttr = prop.GetCustomAttributes(typeof(DisplayNameAttribute), true).OfType <DisplayNameAttribute>().FirstOrDefault(); string displayName = displayNameAttr == null ? prop.Name : displayNameAttr.DisplayName; if (attr as IWFRequireValueProviderContext != null) { ((IWFRequireValueProviderContext)attr).SetValueProvider(new WFPageControlsValueProvider(dvc.Page, "")); } metaproperty.DisplayName = displayName; metaproperty.ValidationAttributes.Add(attr); if (!attr.IsValid(GetControlValue(controlValidating))) { metaproperty.HasError = true; if (metaproperty.Errors == null) { metaproperty.Errors = new List <string>(); } metaproperty.Errors.Add(attr.FormatErrorMessage(displayName)); } } } else { XmlDataAnnotationsRuleSet ruleset = WFUtilities.GetRuleSetForType(sourceType, dvc.XmlRuleSetName); metaproperty.DisplayName = dvc.PropertyName; try { //It's OK to have a DataAnnotationValidatorControl for a property that has no validation rules //defined in the XML. XmlDataAnnotationsRuleSetProperty property = ruleset.Properties.FirstOrDefault(p => p.PropertyName == dvc.PropertyName); if (property != null) { foreach (var validator in property.Validators) { ValidationAttribute attr = WFUtilities.GetValidatorInstanceForXmlDataAnnotationsValidator(validator); if (attr as IWFRequireValueProviderContext != null) { ((IWFRequireValueProviderContext)attr).SetValueProvider(new WFPageControlsValueProvider(dvc.Page, "")); } foreach (var key in validator.ValidatorAttributes.Keys) { PropertyInfo pi = attr.GetType().GetProperty(key); if (pi != null) { pi.SetValue(attr, Convert.ChangeType(validator.ValidatorAttributes[key], pi.PropertyType), null); } } metaproperty.ValidationAttributes.Add(attr); if (!attr.IsValid(GetControlValue(controlValidating))) { metaproperty.HasError = true; if (metaproperty.Errors == null) { metaproperty.Errors = new List <string>(); } metaproperty.Errors.Add(validator.ErrorMessage); } } } } catch (Exception ex) { throw new Exception("Error trying to validate " + dvc.PropertyName + ", innerexception may have more details...\r\nMake sure ErrorMessage isn't specified in more than one place.", ex); } } return(metaproperty); }