0

I want to use the .NET StringLength and Range attributes to put constraints on various properties in my class. I wrote the following very simple code:

class AttributePlayground
{
    [StringLength(5)]
    public static String StringLengthTest { get; set; }

    [Range(10, 20)]
    public static int Age { get; set; }
}

static void Main(string[] args)
{
    AttributePlayground.StringLengthTest = "Too long!";
    AttributePlayground.Age = 34;    
}

I expected an error or an exception to fire but all works ok.

All the examples I see on the web about these attributes shows them in the context of MVC but the documentation makes no reference to it.

tereško
  • 58,060
  • 25
  • 98
  • 150
Howiecamp
  • 2,981
  • 6
  • 38
  • 59

2 Answers2

3

As you know attributes in .NET are just metadata that's baked into the assembly at compile time. If there's nothing that will interpret them, well, nothing will happen.

So in the case of ASP.NET MVC for example there's a validator which interprets those attributes, like this:

class AttributePlayground
{
    [StringLength(5)]
    public String StringLengthTest { get; set; }

    [Range(10, 20)]
    public int Age { get; set; }
}

class Program
{
    static void Main()
    {
        var attributePlayground = new AttributePlayground();
        attributePlayground.StringLengthTest = "Too long!";
        attributePlayground.Age = 34;

        var context = new ValidationContext(attributePlayground, null, null);
        var errors = new List<ValidationResult>();
        if (!Validator.TryValidateObject(attributePlayground, context, errors, true))
        {
            foreach (var error in errors)
            {
                Console.WriteLine(error.ErrorMessage);
            }
        }
    }
}

But honestly if you intend to do some more serious and complex validation I would recommend you not using a declarative validation logic which is what Data Annotations are. I would recommend you FluentValidation.NET. It allows you to express much more complex validation rules in a nice manner which would have been otherwise very difficult to achieve with Data Annotations.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • << If there's nothing that will interpret them, well, nothing will happen. >> Ah, I incorrectly assumed that the framework had some built in functionality around this. I understand now. – Howiecamp Mar 29 '12 at 19:54
0

Yes, it is possible. It's an old question but googling got me here and I'll leave an answer for future readers. If you're outside ASP you need to invoke the validators yourself. This is how you can do it:

using System;
using System.Reflection;
using System.ComponentModel.DataAnnotations;

class AttributePlayground
{
    private string _stringLengthTest;
    private int _age;

    [StringLength(5)]
    public string StringLengthTest
    {
        get { return _stringLengthTest; }
        set { _stringLengthTest = value; ValidateProperty("StringLengthTest"); }
    }

    [Range(10, 20)]
    public int Age
    {
        get { return _age; }
        set { _age = value; ValidateProperty("Age"); }
    }

    private void ValidateProperty(string propName)
    {
        PropertyInfo propInfo = this.GetType().GetProperty(propName);
        object[] attributes = propInfo.GetCustomAttributes(true);
        foreach (object attribute in attributes)
        {
            ValidationAttribute vattr = attribute as ValidationAttribute;
            if (vattr != null)
            {
                object propValue = propInfo.GetValue(this, null);
                vattr.Validate(propValue, propInfo.Name);
            }
        }
    }
}

This yields a nice ValidationException whenever the attribute restrictions are hit during property assignment. If you wanted you could make the validation method static and pass this as parameter, which allows to keep it in a central place.

See also this question for how to validate manually with the DataAnnotations.Validator class.

It's not within the scope of the question, but it's also possible to use custom attributes. Here's a short example to restrict inputs to a string with fixed length:

// Introduce the [StringLengthIs(number)] attribute:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple=false)]
sealed public class StringLengthIsAttribute : ValidationAttribute
{
    public int Length { get; private set; }
    public StringLengthIsAttribute(int length)
    {
        ErrorMessage = "The field {0} must be a string with a length of {1}.";
        Length = length;
    }
    public override bool IsValid(object value)
    {
        if (value == null) return false;
        return value.ToString().Length == Length;
    }
    public override string FormatErrorMessage(string name)
    {
        return string.Format(CultureInfo.CurrentCulture,
          ErrorMessageString, name, Length);
    }
}
yacc
  • 2,915
  • 4
  • 19
  • 33