Introduction

One month ago I have been working on an asp.net project that I still working on and I came a cross a point where I wanted to have a centralized Validation Summary and Multi-Validation Groups, of course with no hesitations I added a centralized validation summary and started to do my validation ... but unfortunately I wasn't lucky enough for that to work !!!

The Problem !!!  

At the beginning I thought I am doing something wrong, my scenario was more than basic and very EXPECTED to occur, two set of controls, each one with a validation group, and one validation summary,  I do my validation on the server side using Page.Validate(ValidationGroupName) for each one as follows: 

        Page.Validate("ValidationGroup1");
        Page.Validate("ValidationGroup2");
        if (Page.IsValid)
        {
            //Do Something when validation successes 
        }
        else
        {
            //Do something else when validation fails
        } 

The funny thing is that if I wanted to show Validation Messages from both ValidationGroup1  and ValidationGroup2  I have to have TWO validation summaries, the first one is set to use the ValidationGroup1 and the other one is set to use the ValidationGroup2, in other words for each validation group you have or going to occur in that page you have to have validation summaries

Now that made me angry enough to have my own validation summary. 

The Investigation 

To solve this problem I started with the Internet, searching for an article, a post or a blog that have the solution to such basic scenario which is occurring for years now! Unbelievably I couldn't find a descent solution ! and I mean it ! the best thing I found is something that involve creating duplicate validators at runtime and add them to the host page, I know it sounds crazy but seriously that was the best solution !! 

So I started to investigate the ASP.NET Validation Summary control it self, I took a sneak peak to its source code to figure out why it's not supporting more than one validation group and I found the below:  

    internal string[] GetErrorMessages(out bool inError)
    {
        string[] strArray = null;
        inError = false;
        int num = 0;
        ValidatorCollection validators = this.Page.GetValidators(this.ValidationGroup);
        for (int i = 0; i < validators.Count; i++)
        {
            IValidator validator = validators[i];
            if (!validator.IsValid)
            {
                inError = true;
                if (validator.ErrorMessage.Length != 0)
                {
                    num++;
                }
            }
        }
        if (num != 0)
        {
            strArray = new string[num];
            int index = 0;
            for (int j = 0; j < validators.Count; j++)
            {
                IValidator validator2 = validators[j];
                if ((!validator2.IsValid && (validator2.ErrorMessage != null)) && (validator2.ErrorMessage.Length != 0))
                {
                    strArray[index] = string.Copy(validator2.ErrorMessage);
                    index++;
                }
            }
        }
        return strArray;
    }

Note the Italic bolded line of code; the validation summary uses its host page to get the validators with the same validation group as that of the validation summary !! therefore there is no way it gets more than one validation group to be supported ! of course the GetValidators(ValidationGroupName)  method doesn't treat null or empty validation group as a special case, its another case as if you have specified a validation group, so only one validation group will be retrieving its validators.  

The Solution 

To solve this issue at first I thought of having a Custom Control that behaves exactly as the Current ASP.NET Validation Summary with extra feature of enabling to support any validation group on the hosting page. 

First I have simply added a new Enumeration ValidationGroupMode

/// <summary>
/// The way the validation summary shall behave toward validation groups.
/// </summary>
public enum ValidationGroupMode
{
    /// <summary>
    /// Only one validation group will be registered to the validation summary.(This will make this validation summary act just like the asp.net validation summary.)
    /// </summary>
    SingleValidationGroup = 0,
    /// <summary>
    /// All validation groups will be registered in the validation summary.
    /// </summary>
    AllValidationGroups = 1
} 

Secondly I tweaked the GetErrorMessages method to become as follows: 

internal string[] GetErrorMessages(out bool inError)
    {
        string[] strArray = null;
        inError = false;
        int num = 0;
        ValidatorCollection validators
            = this.ValidationGroupMode == ValidationGroupMode.AllValidationGroups ? this.Page.Validators : this.Page.GetValidators(this.ValidationGroup);
        for (int i = 0; i < validators.Count; i++)
        {
            IValidator validator = validators[i];
            if (!validator.IsValid)
            {
                inError = true;
                if (validator.ErrorMessage.Length != 0)
                {
                    num++;
                }
            }
        }
        if (num != 0)
        {
            strArray = new string[num];
            int index = 0;
            for (int j = 0; j < validators.Count; j++)
            {
                IValidator validator2 = validators[j];
                if ((!validator2.IsValid && (validator2.ErrorMessage != null)) && (validator2.ErrorMessage.Length != 0))
                {
                    strArray[index] = string.Copy(validator2.ErrorMessage);
                    index++;
                }
            }
        }
        return strArray;
    } 
		 

Simply in case I wanted to have all validation groups to share the same validation summary I got all validators on the page using this.Page.Validators.  

Last Words 

I hope this article was useful, and I am attaching the code for the Custom Validation Summary, I made sure its compatible with Framework 2.0 and above.   

History 

V 1.0 Created the Article.