Developer FAQ
How to add custom validation?
Answer:
Apart from a wide range of built-in C1 validation options - there is a possibility to add your own custom validation. This article describes how to do it.
First
We’ll look at the sample where the user doesn’t define a parameter used during validation. Let’s look at the email format validation sample:
using System; using System.Text.RegularExpressions; using System.CodeDom; using Composite.Data.Validation; namespace Composite.Validation.CustomValidators { // Microsoft validation attribute public sealed class EmailValidatorAttribute : Microsoft.Practices.EnterpriseLibrary.Validation.Validators.ValueValidatorAttribute { protected override Microsoft.Practices.EnterpriseLibrary.Validation.Validator DoCreateValidator(Type targetType) { return new EmailValidator(); } } public sealed class EmailValidator : Microsoft.Practices.EnterpriseLibrary.Validation.Validator { private readonly string EMAILREGEX = @"^(\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*)$"; public EmailValidator() : base("Email Validation", "Email") { } protected override string DefaultMessageTemplate { get { return "Email Validation"; } } // This method does the actual validation protected override void DoValidate(object objectToValidate, object currentTarget, string key, Microsoft.Practices.EnterpriseLibrary.Validation.ValidationResults validationResults) { string email = (string)objectToValidate; if (!Regex.IsMatch(email, EMAILREGEX)) { LogValidationResult(validationResults, "This is not email", currentTarget, key); } } } public sealed class EmailValidatorPropertyValidatorBuilder : PropertyValidatorBuilder<string> { public override Attribute GetAttribute() { return new EmailValidatorAttribute(); } public override CodeAttributeDeclaration GetCodeAttributeDeclaration() { return new CodeAttributeDeclaration(new CodeTypeReference(typeof(EmailValidatorAttribute))); } } public sealed class EmailValidatorContainer { /// <summary> /// Function to mapped to a C1 function in console /// </summary> /// <returns></returns> public static PropertyValidatorBuilder<string> EmailValidator() { return new EmailValidatorPropertyValidatorBuilder(); } } }Here the validation pattern is defined in
public sealed class EmailValidator
. This is private readonly string EMAILREGEX
, and the method protected override void DoValidate
does the actual validation.
PropertyValidatorBuilder<string>
defines the type of the objects to be validated. In this sample, it is a String
.
Make sure to use the same type in public sealed class EmailValidatorContainer
and public sealed class EmailValidatorPropertyValidatorBuilder
.
Second
The sample below shows the validation of numbers, which should not exceed the value specified by the user:
using System; using System.CodeDom; using Composite.Data.Validation; using Composite.Functions; using Composite.Data; namespace MyCustomValidator { // Microsoft validation attribute public sealed class MyValidatorAttribute : Microsoft.Practices.EnterpriseLibrary.Validation.Validators.ValueValidatorAttribute { public MyValidatorAttribute(int someValue) { this.SomeValue = someValue; } public int SomeValue { get; set; } protected override Microsoft.Practices.EnterpriseLibrary.Validation.Validator DoCreateValidator(Type targetType) { return new MyValidator(SomeValue); } } // Microsoft validation public sealed class MyValidator : Microsoft.Practices.EnterpriseLibrary.Validation.Validator { public int SomeValue { get; set; } public MyValidator(int someValue) : base("Some message", "someValue") { SomeValue = someValue; } protected override string DefaultMessageTemplate { get { return "Some message"; } } // This method does the actual validation protected override void DoValidate(object objectToValidate, object currentTarget, string key, Microsoft.Practices.EnterpriseLibrary.Validation.ValidationResults validationResults) { int num = (int)objectToValidate; if (num > SomeValue) { LogValidationResult(validationResults, string.Format("Value should not exceed {0}", SomeValue), currentTarget, key); } } } // Composite validation function return type public sealed class MyValidatorPropertyValidatorBuilder : PropertyValidatorBuilder<int> { public MyValidatorPropertyValidatorBuilder(int someValue) { this.SomeValue = someValue; } public int SomeValue { get; set; } public override Attribute GetAttribute() { return new MyValidatorAttribute(this.SomeValue); } public override CodeAttributeDeclaration GetCodeAttributeDeclaration() { CodeAttributeDeclaration codeAttributeDeclaration = new CodeAttributeDeclaration(new CodeTypeReference(typeof(MyValidatorAttribute))); codeAttributeDeclaration.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(this.SomeValue))); return codeAttributeDeclaration; } } // Container class for method based function provider public sealed class MyValidatorContainer { [Function(Description="Validates that an integer should not exceed the specified value")] [FunctionParameter(Name="someValue", Label="MaxValue", Help="Description of Parameter")] public static PropertyValidatorBuilder<int> MyValidator(int someValue) { return new MyValidatorPropertyValidatorBuilder(someValue); } } }
In this sample we have to get a parameter from user.
It is done by adding a property to public sealed class MyValidatorAttribute
:
public MyValidatorAttribute(int someValue) { this.SomeValue = someValue; } public int SomeValue { get; set; }
and attributes to public sealed class MyValidatorContainer
:
[Function(Description="Validates that an integer should not exceed the specified value")] [FunctionParameter(Name="someValue", Label="MaxValue", Help="Description of Parameter")] public static PropertyValidatorBuilder<int> MyValidator(int someValue) { return new MyValidatorPropertyValidatorBuilder(someValue); }
(Please note the use of the attributes Function
and FunctionParameter
. These are available in Composite C1 v. 3.2 or later. For Composite C1 v. 3.1 or earlier, use FunctionParameterDescription
like this: [FunctionParameterDescription("someValue", "MaxValue", "Description of Parameter")]
.)
Using validators
To add one of this validations to your C1 UI do the following:
- Add references to Composite.dll and Microsoft.Practices.EnterpriseLibrary.Validation.dll.
- Compile one of these samples
- Copy it to the /Bin directory.
- In the C1 Console, go to "Functions" and add an external C# function specifying in the Type field:
- for the first sample:
Composite.Validation.CustomValidators.EmailValidatorContainer
- for the second sample:
MyCustomValidator.MyValidatorContainer
- for the first sample:
Now it will be available for Validation Rules:
- Create a new data type.
- Add a field of this type:
- for the first sample: string
- for the second sample: integer
- Use “Edit Validation rules” on the field. The newly added validation will be available in the corresponding namespace.
Important Notes
- Custom validators will not work if located in App_Code folder.