Data FAQ

How to add custom validation?

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();
        }
    }
}


Download the source

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);
        }
    }
}

Download the source

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; }

Download the source

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);
}

Download the source

(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:

  1. Add references to Composite.dll and Microsoft.Practices.EnterpriseLibrary.Validation.dll.
  2. Compile one of these samples
  3. Copy it to the /Bin directory.
  4. 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

Now it will be available for Validation Rules:

  1. Create a new data type.
  2. Add a field of this type:
    • for the first sample: string
    • for the second sample: integer
  3. Use “Edit Validation rules” on the field. The newly added validation will be available in the corresponding namespace.

Important Notes

  1. Custom validators will not work if located in App_Code  folder.