Development With A Dot

Blog on development in general, and specifically on .NET

Sponsors

News

My Friends

My Links

Permanent Posts

Portuguese Communities

Data Annotations Property Validator for ASP.NET

Entity Framework, LINQ to SQL and ASP.NET MVC support Microsoft's new validation API, which you can find on System.ComponentModel.DataAnnotations. It basically consists on attribute classes, inherited from System.ComponentModel.DataAnnotations.ValidationAttribute. It is very easy to define your own, although Enterprise Library, xVal and Spring.NET validations are considerably power powerfull.

I wanted to have a custom ASP.NET validator that would validate the value of a form control against the validation attributes defined for a given property of a class, in a way similar to the Web Client Software Factory's PropertyProxyValidator, like you can read in this post. This is what I came up with: class DataAnnotationsValidator!

Here is the code:

public class DataAnnotationsValidator : BaseValidator

{

    protected override void OnInit(EventArgs e)

    {

        if ((this.Enabled == true) && (this.Visible == true))

        {

            this.Page.RegisterRequiresControlState(this);

        }

        base.OnInit(e);

    }

    protected override void LoadControlState(Object savedState)

    {

        Object [] state = savedState as Object [];

        base.LoadControlState(state [ 0 ]);

        this.DisplayMode = (ValidationSummaryDisplayMode) state [ 1 ];

        this.PropertyName = (String) state [ 2 ];

        this.SourceTypeName = (String) state [ 3 ];

    }

    protected override Object SaveControlState()

    {

        Object [] state = new Object [ 4 ];

        state [ 0 ] = base.SaveControlState();

        state [ 1 ] = this.DisplayMode;

        state [ 2 ] = this.PropertyName;

        state [ 3 ] = this.SourceTypeName;

        return (state);

    }

    protected override Boolean EvaluateIsValid()

    {

        if ((String.IsNullOrEmpty(this.SourceTypeName) == true) || (String.IsNullOrEmpty(this.PropertyName) == true))

        {

            return (true);

        }

        Type type = Type.GetType(this.SourceTypeName, false);

        if (type != null)

        {

            PropertyInfo prop = type.GetProperty(this.PropertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty);

            if (prop != null)

            {

                ValidationAttribute [] attrs = prop.GetCustomAttributes(typeof(ValidationAttribute), true) as ValidationAttribute [];

                List<ValidationException> errors = new List<ValidationException>();

                String value = this.GetControlValidationValue(this.ControlToValidate);

                if (attrs.Length == 0)

                {

                    MetadataTypeAttribute [] metadata = type.GetCustomAttributes(typeof(MetadataTypeAttribute), true) as MetadataTypeAttribute [];

 

                    if (metadata.Length != 0)

                    {

                        prop = metadata[0].MetadataClassType.GetProperty(this.PropertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty);

                        if (prop != null)

                        {

                            attrs = prop.GetCustomAttributes(typeof(ValidationAttribute), true) as ValidationAttribute [];

                        }

                    }

                }

                for (Int32 i = 0; i < attrs.Length; ++i)

                {

                    try

                    {

                        attrs [ i ].Validate(value, prop.Name);

                    }

                    catch (ValidationException ve)

                    {

                        errors.Add(ve);

                    }

                    catch

                    {

                    }

                }

                this.ErrorMessage = this.formatErrorMessage(errors);

                return (errors.Count == 0);

            }

        }

        this.ErrorMessage = String.Empty;

        return (true);

    }

    private String formatErrorMessage(IList<ValidationException> results)

    {

        String str = String.Empty;

        String str2 = String.Empty;

        String str3 = String.Empty;

        String str4 = String.Empty;

        StringBuilder builder = new StringBuilder();

        switch (this.DisplayMode)

        {

            case ValidationSummaryDisplayMode.List:

                str3 = "<br/>";

                break;

            case ValidationSummaryDisplayMode.SingleParagraph:

                str3 = " ";

                str4 = "<br/>";

                break;

            default:

                str = "<ul>";

                str2 = "<li>";

                str3 = "</li>";

                str4 = "</ul>";

                break;

        }

        if (results.Count != 0)

        {

           builder.Append(str);

            foreach (ValidationException result in results)

            {

                builder.Append(str2);

                builder.Append(result.Message);

                builder.Append(str3);

            }

            builder.Append(str4);

        }

        return (builder.ToString());

    }

    [Browsable(true)]

    [DefaultValue(ValidationSummaryDisplayMode.List)]

    public ValidationSummaryDisplayMode DisplayMode

    {

        get;

        set;

    }

    [Browsable(true)]

    [DefaultValue("")]

    public String PropertyName

    {

        get;

        set;

    }

    [Browsable(true)]

    [DefaultValue("")]

    public String SourceTypeName

    {

        get;

        set;

    }

}

As you can see, it is smart enough to try to find the validation attributes on a metadata class defined with a MetadataTypeAttribute attribute, like you would use with generated code, such as Entity Framework's. It also supports all of ValidationSummaryDisplayMode's options.

This is how you would use it:

 

<asp:TextBox runat="server" ID="text" />

<blog:DataAnnotationsValidator runat="server" ControlToValidate="text" SourceTypeName="SomeClass, SomeAssembly" PropertyName="SomeProperty" />

<asp:Button runat="server" Text="Validate" OnClick="OnValidate" />

Suppose the class you want to validate looks like this:

public class SomeClass

    [Required]

    [RegularExpression(@"\d\d\d")]

    public String SomeProperty

    {

        get;

        set;

    }

}

And that's it! Happy validation!

Bookmark and Share

Comments

JazzyJ said:

Awesome, thank you for this.

# April 10, 2010 2:23 PM