Пример #1
0
        public void TryValidateModel_TestAJAXLikeValidation()
        {
            TestWidget                  model            = new TestWidget();
            Type                        modelType        = model.GetType();
            List <string>               errors           = null;
            WFModelMetaData             metadata         = new WFModelMetaData();
            WFModelMetaData             metadataExpected = new WFModelMetaData();
            bool                        actual;
            Dictionary <string, string> values = new Dictionary <string, string>();

            values.Add("model_RequiredName", "reqname");
            values.Add("model_MaxLengthName", "toolongofaname");
            values.Add("model_Sprockets", "4");    //bad sprocket value
            values.Add("model_Email", "bademail"); //bad email
            values.Add("model_Price", "999");      //bad price
            // NoErrorMessage property is NOT added and should NOT be present

            actual = WFUtilities.TryValidateModel(model, "model_", new WFDictionaryValueProvider(values), metadata, new WFTypeRuleProvider(modelType));
            errors = metadata.Errors;
            Assert.AreEqual(errors.Count, 4);

            Assert.AreEqual(errors[0], "Max length 10 characters");
            Assert.AreEqual(errors[1], "Invalid number of sprockets.");
            Assert.AreEqual(errors[2], "Widget must have valid e-mail");
            //Generated error message on custom annotation
            Assert.AreEqual(errors[3], "Invalid price");

            Assert.AreEqual(actual, false);
        }
Пример #2
0
        /// <summary>
        /// This method should only be called by Html.&lt;control&gt;For() methods.
        /// It registers metadata for model properties if they do not exist for controls on the form and informs the control if there is an error.
        /// </summary>
        /// <param name="metadata"></param>
        /// <param name="Model"></param>
        /// <param name="tag"></param>
        /// <param name="markupName"></param>
        /// <param name="expressionBody"></param>
        /// <returns></returns>
        public HtmlTag PreRenderProcess(HtmlTag tag, ref WFModelMetaData metadata, TagTypes tagType, string markupName, PropertyInfo targetProperty, object model)
        {
            //Ignore tag types that are not tied to a property
            if (!validationTypes.Contains(tagType))
            {
                return(tag);
            }

            if (model == null || String.IsNullOrEmpty(markupName) || tag == null || metadata == null)
            {
                return(tag);
            }
            WFModelMetaProperty metaprop = null;
            string lcName = markupName.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)
            {
                metaprop = CreateMetaProperty(markupName, targetProperty, metadata, metaprop, model, HttpContext.Current);
                metadata.Properties.Add(metaprop);
            }
            if (metaprop.HasError)
            {
                tag.AddClass(WFUtilities.InputValidationErrorClass);
            }
            return(tag);
        }
Пример #3
0
        public void TryValidateModel_TestAgainstModelSuccess()
        {
            TestWidget      model            = new TestWidget();
            Type            modelType        = model.GetType();
            WFModelMetaData metadata         = new WFModelMetaData();
            WFModelMetaData metadataExpected = new WFModelMetaData();
            bool            actual;

            model.Email          = "*****@*****.**";
            model.MaxLengthName  = "goodname";
            model.RequiredName   = "reqname"; //Required
            model.Sprockets      = 6;         //Good sprocket count
            model.Price          = 0.99d;     //Good price
            model.NoErrorMessage = "reqmsg";  //Required - no error message defined

            actual = WFUtilities.TryValidateModel(model, "", new WFObjectValueProvider(model, ""), metadata, new WFTypeRuleProvider(modelType));

            //No Errors
            Assert.AreEqual(metadata.Errors.Count, 0);

            //Properties are not collected when an error does not exist
            //The reason is because there is no page to collect them for
            Assert.AreEqual(metadata.Properties.Count, 0);

            Assert.AreEqual(actual, true);
        }
Пример #4
0
        public void TryValidateModel_TestAgainstModelClassAttribute()
        {
            ClassAttributeTestWidget model   = new ClassAttributeTestWidget();
            Type            modelType        = model.GetType();
            WFModelMetaData metadata         = new WFModelMetaData();
            WFModelMetaData metadataExpected = new WFModelMetaData();
            bool            actual;

            model.Email           = "*****@*****.**";
            model.MaxLengthName   = "goodname";
            model.RequiredName    = "reqname"; //Required
            model.Sprockets       = 6;         //Good sprocket count
            model.Price           = 0.99d;     //Good price
            model.NoErrorMessage  = "reqmsg";  //Required - no error message defined
            model.Password        = "******";
            model.ConfirmPassword = "******";
            actual = WFUtilities.TryValidateModel(model, "", new WFObjectValueProvider(model, ""), metadata, new WFTypeRuleProvider(modelType));

            //There should be one error from the model attribute
            Assert.AreEqual(metadata.Errors.Count, 1);

            //Properties are not collected when an error does not exist
            //The reason is because there is no page to collect them for
            Assert.AreEqual(metadata.Properties.Count, 0);

            Assert.AreEqual(actual, false);
        }
Пример #5
0
 protected void Page_Load(object sender, EventArgs e)
 {
     Customer        = new Customer();
     CustomerAddress = new CustomerAddress();
     MetaData        = new WFModelMetaData();
     if (Page.IsPostBack)
     {
         WFPageUtilities.UpdateModel(Request, Customer);
         WFPageUtilities.UpdateModel(Request, CustomerAddress);
         WFPageUtilities.TryValidateModel(MetaData, typeof(CustomerAddress), HttpContext.Current);
         WFPageUtilities.TryValidateModel(MetaData, typeof(Customer), HttpContext.Current);
     }
 }
Пример #6
0
        public void RegisterXMLValidationConfiguration_TestClassLevelValidators()
        {
            WFUtilities.RegisterXMLValidationConfiguration(Environment.CurrentDirectory + "\\Validator3.config");
            TestParticipantClass tpc = new TestParticipantClass();

            tpc.Password        = "******";
            tpc.ConfirmPassword = "******";
            WFModelMetaData metadata = new WFModelMetaData();

            WFUtilities.TryValidateModel(tpc, "", new WFObjectValueProvider(tpc, ""), metadata, new WFXmlRuleSetRuleProvider("ClassLevelAttributes"));

            Assert.AreEqual("Password fields must match.", metadata.Errors[0]);
        }
Пример #7
0
        /// <summary>
        /// This method is used internally to find or create meta properties in validation data.
        /// </summary>
        /// <param name="metadata">The metadata object.</param>
        /// <param name="markupName">The name of the property in markup.</param>
        /// <param name="model">The model object in memory the property belongs to.</param>
        /// <param name="reflectName">The reflected property name.</param>
        /// <param name="context">The current HTTP context.</param>
        /// <returns>Returns a WFModelMetaProperty class.</returns>
        public WFModelMetaProperty GetMetaProperty(WFModelMetaData metadata, string markupName, object model, string reflectName, HttpContext context)
        {
            Type                tx            = model.GetType();
            PropertyInfo        foundProperty = null;
            WFModelMetaProperty metaprop      = null;

            foreach (PropertyInfo pi in tx.GetProperties())
            {
                if (pi.Name == reflectName)
                {
                    foundProperty = pi;
                    metaprop      = CreateMetaProperty(markupName, pi, metadata, metaprop, model, context);
                }
            }
            return(metaprop);
        }
Пример #8
0
        public void TryValidateModel_TestProxyClassValidation()
        {
            FriendlyClass fc = new FriendlyClass();

            fc.LastName = "onereallybiglongstringthatkeepsgoing"; // break validation
            List <string>   errors      = null;
            WFModelMetaData metadata    = new WFModelMetaData();
            bool            didValidate = WFUtilities.TryValidateModel(fc, "", new WFObjectValueProvider(fc, ""), metadata, new WFTypeRuleProvider(typeof(FriendlyClass)));

            errors = metadata.Errors;
            Assert.AreEqual(false, didValidate);
            Assert.AreEqual(2, errors.Count);
            Assert.AreEqual("The FirstName field is required.", errors[0]);
            Assert.AreEqual("The field LastName must be a string with a maximum length of 10.", errors[1]);
            Assert.AreEqual(2, metadata.Properties.Count);
        }
Пример #9
0
        public void TryValidateModel_ErrorMessageTests()
        {
            string resourceErrorMessage = Resources.FirstName_ErrorMessage_Test1;

            TestParticipantClass tpc = new TestParticipantClass();

            WFModelMetaData metadata = new WFModelMetaData();

            WFUtilities.TryValidateModel(tpc, "", new WFObjectValueProvider(tpc, ""), metadata, new WFTypeRuleProvider(typeof(ProxyMessageFromValidator)));
            Assert.AreEqual("The FirstName field is required.", metadata.Errors[0]);
            metadata = new WFModelMetaData();
            WFUtilities.TryValidateModel(tpc, "", new WFObjectValueProvider(tpc, ""), metadata, new WFTypeRuleProvider(typeof(ProxyMessageFromConstant)));
            Assert.AreEqual("This is a constant error.", metadata.Errors[0]);
            metadata = new WFModelMetaData();
            WFUtilities.TryValidateModel(tpc, "", new WFObjectValueProvider(tpc, ""), metadata, new WFTypeRuleProvider(typeof(ProxyMessageFromResource)));
            Assert.AreEqual("This value from resource.", metadata.Errors[0]);
            metadata = new WFModelMetaData();
        }
Пример #10
0
        public HtmlTag PreRenderProcess(HtmlTag tag, ref WFModelMetaData metadata, TagTypes tagType, string propertyName, System.Reflection.PropertyInfo targetProperty, object model)
        {
            if (tagType == TagTypes.Span ||
                tagType == TagTypes.TextArea ||
                tagType == TagTypes.Label ||
                tagType == TagTypes.ValidationMessage ||
                tagType == TagTypes.ValidationItem)
            {
                if (!String.IsNullOrEmpty(tag.InnerText))
                {
                    tag.InnerText = HttpUtility.HtmlEncode(tag.InnerText);
                }
            }
            else if (new TagTypes[] {
                TagTypes.Checkbox,
                TagTypes.Hidden,
                TagTypes.InputBox,
                TagTypes.RadioButton,
            }.Contains(tagType))
            {
                if (!String.IsNullOrEmpty(tag.Attr("value")))
                {
                    tag.Attr("value", HttpUtility.HtmlEncode(tag.Attr("value")));
                }
            }
            else if (tagType == TagTypes.Select)
            {
                foreach (HtmlTag child in tag.Children)
                {
                    if (!String.IsNullOrEmpty(child.HTMLTagName) &&
                        child.HTMLTagName.ToLower() == "option")
                    {
                        //<option value="encode">encode</option>
                        child.InnerText = HttpUtility.HtmlEncode(child.InnerText);
                        if (!String.IsNullOrEmpty(child.Attr("value")))
                        {
                            child.Attr("value", HttpUtility.HtmlEncode(child.Attr("value")));
                        }
                    }
                }
            }

            return(tag);
        }
Пример #11
0
        public void TryValidateModel_TestAgainstModel()
        {
            TestWidget      model            = new TestWidget();
            Type            modelType        = model.GetType();
            List <string>   errors           = null;
            List <string>   errorsExpected   = new List <string>();
            WFModelMetaData metadata         = new WFModelMetaData();
            WFModelMetaData metadataExpected = new WFModelMetaData();
            bool            expected         = false;
            bool            actual;

            model.Email          = "bademail";
            model.MaxLengthName  = "toolongofaname";
            model.RequiredName   = "";  //Required
            model.Sprockets      = 4;   //Invalid sprocket count
            model.Price          = 999; //Invalid price
            model.NoErrorMessage = "";  //Required - no error message defined

            actual = WFUtilities.TryValidateModel(model, "", new WFObjectValueProvider(model, ""), metadata, new WFTypeRuleProvider(modelType));
            errors = metadata.Errors;

            Assert.AreEqual(errors.Count, 6);
            //Generated error messages on standard annotations
            Assert.AreEqual(errors[0], "Widget name required");
            Assert.AreEqual(errors[1], "Max length 10 characters");
            Assert.AreEqual(errors[2], "Invalid number of sprockets.");
            Assert.AreEqual(errors[3], "Widget must have valid e-mail");
            //Generated error message on custom annotation
            Assert.AreEqual(errors[4], "Invalid price");
            //Auto-generated error message
            Assert.AreEqual(errors[5], "The NoErrorMessage field is required.");

            Assert.AreEqual(metadata.Properties.Count, 6);
            Assert.AreEqual(metadata.Properties[0].PropertyName, "RequiredName");
            Assert.AreEqual(metadata.Properties[1].PropertyName, "MaxLengthName");
            Assert.AreEqual(metadata.Properties[2].PropertyName, "Sprockets");
            Assert.AreEqual(metadata.Properties[3].PropertyName, "Email");
            Assert.AreEqual(metadata.Properties[4].PropertyName, "Price");
            Assert.AreEqual(metadata.Properties[5].PropertyName, "NoErrorMessage");

            Assert.AreEqual(actual, false);
        }
Пример #12
0
        public HtmlTag PreRenderProcess(HtmlTag tag, ref WFModelMetaData metadata, TagTypes tagType, string markupName, string reflectName, object Model)
        {
            //Ignore tag types that are not tied to a property
            if (!validationTypes.Contains(tagType))
            {
                return(tag);
            }

            if (reflectName == "")
            {
                reflectName = markupName;
            }
            if (Model == null || String.IsNullOrEmpty(markupName) || tag == null || metadata == null)
            {
                return(tag);
            }
            WFModelMetaProperty metaprop = null;
            string lcName = markupName.ToLower();

            for (int i = 0; i < metadata.Properties.Count; i++)
            {
                //if (metadata.Properties[i].ModelObject == Model && metadata.Properties[i].MarkupName.ToLower() == lcName)
                if (metadata.Properties[i].MarkupName.ToLower() == lcName)
                {
                    metaprop = metadata.Properties[i];
                    break;
                }
            }
            if (metaprop == null)
            {
                //Create a meta property if it does not exist
                metaprop = GetMetaProperty(metadata, markupName, Model, reflectName, null);
                metadata.Properties.Add(metaprop);
            }
            if (metaprop.HasError)
            {
                tag.AddClass(WFUtilities.InputValidationErrorClass);
            }
            return(tag);
        }
Пример #13
0
        protected override void RenderContents(HtmlTextWriter output)
        {
            WFModelMetaData metadata = new WFModelMetaData();

            foreach (DataAnnotationValidatorControl dvc in WebControlUtilities.FindValidators(this.Page))
            {
                WFModelMetaProperty metaprop = WebControlUtilities.GetMetaPropertyFromValidator(this.Page, dvc, metadata);
                metaprop.OverriddenSpanID = dvc.UniqueID;
                if (!String.IsNullOrEmpty(dvc.Text))
                {
                    metaprop.OverriddenErrorMessage = dvc.Text;
                }
                metadata.Properties.Add(metaprop);
            }
            if (Unobtrusive)
            {
                output.Write(WFScriptGenerator.SetupClientUnobtrusiveValidationScriptHtmlTag().Render());
            }
            else
            {
                output.Write(WFScriptGenerator.SetupClientValidationScriptHtmlTag().Render());
                string targetid = "";
                if (String.IsNullOrEmpty(TargetFormClientID))
                {
                    targetid = this.Page.Form.ClientID;
                }
                else
                {
                    targetid = TargetFormClientID;
                }
                output.Write(new HtmlTag("script", new { type = "text/javascript", language = "javascript" })
                {
                    InnerText = WFScriptGenerator.EnableClientValidationScript(metadata, targetid)
                }.Render());
            }
        }
Пример #14
0
        /// <summary>
        /// Create a meta property from the specified PropertyInfo object, run validation on it against the current value and return it.<br/>
        /// If a WFModelMetaProperty is supplied, it will be validated/modified and then returned.
        /// </summary>
        /// <param name="markupName">The HTML markup name of the control rendering the property.<param>
        /// <param name="pi">The PropertyInfo object to retrieve DataAnnotations from.</param>
        /// <param name="metadata">The metadata for the model.</param>
        /// <param name="metaprop">The metadata for this particular property. (optional)</param>
        /// <param name="model">The particular model instance that owns this property.</param>
        /// <param name="context">The HttpContext supplying the value to validate against.</param>
        /// <returns></returns>
        private WFModelMetaProperty CreateMetaProperty(string markupName, PropertyInfo pi, WFModelMetaData metadata, WFModelMetaProperty metaprop, object model, HttpContext context)
        {
            object[] attribs         = pi.GetCustomAttributes(false);
            var      displayNameAttr = pi.GetCustomAttributes(typeof(DisplayNameAttribute), true).OfType <DisplayNameAttribute>().FirstOrDefault();
            string   displayName     = displayNameAttr == null ? pi.Name : displayNameAttr.DisplayName;

            foreach (object o in attribs)
            {
                Type oType = o.GetType();
                if (oType.IsSubclassOf(typeof(ValidationAttribute)))
                {
                    var oVal = (ValidationAttribute)o;
                    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   = markupName;
                    metaprop.ValidationAttributes.Add(oVal);

                    //if (context != null && !oVal.IsValid(context.Request[markupName])) {
                    //    metaprop.HasError = true;
                    //    metaprop.Errors.Add(oVal.FormatErrorMessage(displayName));
                    //}
                }
            }

            if (metaprop == null && pi != null)   //No attributes were found for this property

            {
                metaprop              = new WFModelMetaProperty();
                metaprop.ModelObject  = model;
                metaprop.PropertyName = pi.Name;
                metaprop.DisplayName  = pi.Name; //No attributes, so no displayname
                metaprop.MarkupName   = markupName;
            }

            return(metaprop);
        }
Пример #15
0
        public void RegisterXMLValidationConfiguration_TestXMLErrorMessage()
        {
            WFUtilities.RegisterXMLValidationConfiguration(Environment.CurrentDirectory + "\\Validator2.config");

            string resourceErrorMessage = Resources.FirstName_ErrorMessage_Test1;

            TestParticipantClass tpc = new TestParticipantClass();

            WFModelMetaData metadata = new WFModelMetaData();


            //============================= WEB FORMS SERVER CONTROL VALIDATION =================================
            Page p = new Page();

            p.Controls.Add(new TextBox()
            {
                ID = "FirstName"
            });
            p.Controls.Add(new DataAnnotationValidatorControl()
            {
                PropertyName      = "FirstName",
                ControlToValidate = "FirstName",
                XmlRuleSetName    = "MessageFromValidator",
                ErrorMessage      = "This message from control itself."
            });

            p.Validators.Add(p.Controls[1] as IValidator);


            (p.Controls[1] as BaseValidator).Validate();
            Assert.AreEqual("This message from control itself.", (p.Controls[1] as DataAnnotationValidatorControl).ErrorMessage);

            p = new Page();
            p.Controls.Add(new TextBox()
            {
                ID = "FirstName"
            });
            p.Controls.Add(new DataAnnotationValidatorControl()
            {
                PropertyName      = "FirstName",
                ControlToValidate = "FirstName",
                XmlRuleSetName    = "MessageFromXML",
            });

            p.Validators.Add(p.Controls[1] as IValidator);


            (p.Controls[1] as BaseValidator).Validate();
            Assert.AreEqual("The First Name field cannot be empty.", (p.Controls[1] as DataAnnotationValidatorControl).ErrorMessage);

            p = new Page();
            p.Controls.Add(new TextBox()
            {
                ID = "FirstName"
            });
            p.Controls.Add(new DataAnnotationValidatorControl()
            {
                PropertyName      = "FirstName",
                ControlToValidate = "FirstName",
                XmlRuleSetName    = "MessageFromResource",
            });

            p.Validators.Add(p.Controls[1] as IValidator);


            (p.Controls[1] as BaseValidator).Validate();
            Assert.AreEqual("This value from resource.", (p.Controls[1] as DataAnnotationValidatorControl).ErrorMessage);

            //====================== TryValidateModel ==============================

            WFUtilities.TryValidateModel(tpc, "", new WFObjectValueProvider(tpc, ""), metadata, new WFXmlRuleSetRuleProvider("MessageFromValidator"));
            Assert.AreEqual("The FirstName field is required.", metadata.Errors[0]);
            metadata = new WFModelMetaData();
            WFUtilities.TryValidateModel(tpc, "", new WFObjectValueProvider(tpc, ""), metadata, new WFXmlRuleSetRuleProvider("MessageFromXML"));
            Assert.AreEqual("The First Name field cannot be empty.", metadata.Errors[0]);
            metadata = new WFModelMetaData();
            WFUtilities.TryValidateModel(tpc, "", new WFObjectValueProvider(tpc, ""), metadata, new WFXmlRuleSetRuleProvider("MessageFromResource"));
            Assert.AreEqual("This value from resource.", metadata.Errors[0]);
            metadata = new WFModelMetaData();
        }
Пример #16
0
        /// <summary>
        /// Build and return script and JSON objects to enable client validation.
        /// This should be called from WFPageBase or WFUserControlBase
        /// </summary>
        /// <param name="metadata"></param>
        /// <returns></returns>
        public static string EnableClientValidationScript(WFModelMetaData metadata, string formId)
        {
            StringBuilder sb = new StringBuilder();

            sb.Append("if(!window.wfuClientValidationMetadata) { window.wfuClientValidationMetadata = []; }\r\n");
            sb.Append("window.wfuClientValidationMetadata.push(");

            List <JSONObject> fields = new List <JSONObject>();

            foreach (WFModelMetaProperty prop in metadata.Properties)
            {
                JSONObject field = new JSONObject();
                field.Attr("FieldName", prop.MarkupName);
                field.Attr("ReplaceValidationMessageContents", true);

                //Remove $'s which jQuery doesn't like in ID's
                string spanID = "";
                if (!String.IsNullOrEmpty(prop.OverriddenSpanID))
                {
                    spanID = prop.OverriddenSpanID;
                }
                else
                {
                    spanID = prop.MarkupName + "_validationMessage";
                }
                spanID = spanID.Replace("$", @"\\$");
                field.Attr("ValidationMessageId", spanID);

                List <JSONObject> validationRules = new List <JSONObject>();
                foreach (object oVal in prop.ValidationAttributes)
                {
                    ValidationAttribute val      = oVal as ValidationAttribute;
                    JSONObject          valRule  = new JSONObject();
                    JSONObject          valParms = new JSONObject();
                    Type valType = oVal.GetType();
                    if (!String.IsNullOrEmpty(prop.OverriddenErrorMessage))
                    {
                        valRule.Attr("ErrorMessage", prop.OverriddenErrorMessage);
                    }
                    else
                    {
                        valRule.Attr("ErrorMessage", val.FormatErrorMessage(prop.DisplayName));
                    }

                    if (valType == typeof(StringLengthAttribute) || valType.IsSubclassOf(typeof(StringLengthAttribute)))
                    {
                        valParms.Attr("maximumLength", ((StringLengthAttribute)oVal).MaximumLength);
                        valParms.Attr("minimumLength", 0);
                        valRule.Attr("ValidationType", "stringLength");
                        valRule.Attr("ValidationParameters", valParms);
                    }
                    else if (valType == typeof(RequiredAttribute) || valType.IsSubclassOf(typeof(RequiredAttribute)))
                    {
                        valRule.Attr("ValidationType", "required");
                        valRule.Attr("ValidationParameters", new JSONObjectEmpty());
                    }
                    else if (valType == typeof(RangeAttribute) || valType.IsSubclassOf(typeof(RangeAttribute)))
                    {
                        valParms.Attr("minimum", ((RangeAttribute)oVal).Minimum);
                        valParms.Attr("maximum", ((RangeAttribute)oVal).Maximum);
                        valRule.Attr("ValidationType", "range");
                        valRule.Attr("ValidationParameters", valParms);

                        //Create an additional 'number' validation
                        JSONObject numRule  = new JSONObject();
                        JSONObject numParms = new JSONObject();
                        numRule.Attr("ErrorMessage", "The field " + prop.DisplayName + " must be a number.");
                        numRule.Attr("ValidationParameters", new JSONObjectEmpty());
                        numRule.Attr("ValidationType", "number");
                        validationRules.Add(numRule);
                    }
                    else if (valType == typeof(RegularExpressionAttribute) || valType.IsSubclassOf((typeof(RegularExpressionAttribute))))
                    {
                        valRule.Attr("ValidationType", "regularExpression");
                        valRule.Attr("ValidationParameters", new JSONObject(new {
                            pattern = ((RegularExpressionAttribute)oVal).Pattern
                                      .Replace("\\", "\\\\")
                                      .Replace("\"", "\\\"")
                        }));
                    }
                    else   //Custom Validator
                    {
                        if (val as IWFClientValidatable != null)
                        {
                            IWFClientValidatable valAttr = (IWFClientValidatable)val;
                            var cvrs = valAttr.GetClientValidationRules();
                            if (cvrs != null)
                            {
                                bool firstRule = true;
                                foreach (var cvr in cvrs)
                                {
                                    if (firstRule)
                                    {
                                        valRule.Attr("ValidationType", cvr.ValidationType);
                                        if (cvr.ValidationParameters != null)
                                        {
                                            foreach (KeyValuePair <string, object> kvp in cvr.ValidationParameters)
                                            {
                                                valParms.Attr(kvp.Key, kvp.Value);
                                            }
                                        }
                                        valRule.Attr("ValidationParameters", valParms);
                                        firstRule = false;
                                    }
                                    else
                                    {
                                        JSONObject vrx      = new JSONObject();
                                        JSONObject vrxParms = new JSONObject();
                                        vrx.Attr("ErrorMessage", cvr.ErrorMessage);
                                        vrx.Attr("ValidationType", cvr.ValidationType);
                                        if (cvr.ValidationParameters != null)
                                        {
                                            foreach (KeyValuePair <string, object> kvp in cvr.ValidationParameters)
                                            {
                                                vrxParms.Attr(kvp.Key, kvp.Value);
                                            }
                                        }
                                        vrx.Attr("ValidationParameters", vrxParms);
                                        validationRules.Add(vrx);
                                    }
                                }
                            }
                        }
                    }
                    validationRules.Add(valRule);
                }
                field.Attr("ValidationRules", validationRules);
                fields.Add(field);
            }
            JSONObject jo = new JSONObject(new { Fields = fields, FormId = formId, ReplaceValidationSummary = false });

            sb.Append(jo.Render());

            sb.Append(");");
            return(sb.ToString());
        }