13

I have, let's say, this simple class:

public class User
{
  [Required(AllowEmptyStrings = false, ErrorMessage="EmailIsRequired"]
  public string EmailAddress { get; set; }
}

I know how to use Validator.TryValidateProperty and Validator.TryValidateObject in the System.ComponentModel.DataAnnotations namespace. In order for this to work, you need an actual instance of the object you want to validate.

But now, I want to validate a certain value without an instance of the User class, like:

TryValidateValue(typeof(User), "EmailAddress", "test@test.com");

The goal is that I want to test a value before actually having to instantiate the object itself (the reason is that I only allow valid domain entities to be created). So in fact I want to use validation attributes on classes instead of instances.

Any ideas how that could be done?

Thanks!

EDIT: meanwhile I decided not to use data annotations, but instead use http://fluentvalidation.codeplex.com so that validation is moved outside of the entities. This way validation can be triggered from within the entities as well as my command handlers. The validation itself looks more readable too, thanks to the fluent notation.

L-Four
  • 13,345
  • 9
  • 65
  • 109
  • You mentioned that you are trying to avoid instantiating domain objects if they are invalid, but what is the impact of instantiating it? It is possible that your object is doing too many things, and you should be splitting up its responsibilities if simply calling the constructor is going to mess anything up. – Merlyn Morgan-Graham Oct 28 '11 at 08:32
  • The domain entity is checking all fields in its constructor, if any of them doesn't validate, an exception is thrown, so the object cannot be created. But now, in my command handler, for contextual validation I need to validate an email address, but I don't need the object itself. So I was wondering: why can't i reuse this email validation without needing an instance of this object. I could also remove validation completely out of the entity, but then I can't use data annotations I guess... – L-Four Oct 28 '11 at 08:45
  • Is there a way to create custom derived annotations? You could then share the implementation of the validation between the annotation, and for this command handler. That would be sort of a hack, but I personally believe annotations aren't a complete or perfectly factored architectural solution to domain constraint validation (they can't handle cross-property constraints, and if applied to a class, don't support rich logic), so you'd only be doing the best with what you've got. – Merlyn Morgan-Graham Oct 28 '11 at 08:51
  • Yes, I would be using them only for simple validation logic of course. I believe that cross property validation is also possible (but not yet out of the box)... – L-Four Oct 28 '11 at 08:59

1 Answers1

21

Here's an example of how you could use the TryValidateValue method:

public class User
{
    [Required(AllowEmptyStrings = false, ErrorMessage = "EmailIsRequired")]
    public string EmailAddress { get; set; }
}

class Program
{
    static void Main()
    {
        var value = "test@test.com";

        var context = new ValidationContext(value, null, null);        
        var results = new List<ValidationResult>();
        var attributes = typeof(User)
            .GetProperty("EmailAddress")
            .GetCustomAttributes(false)
            .OfType<ValidationAttribute>()
            .ToArray();

        if (!Validator.TryValidateValue(value, context, results, attributes))
        {
            foreach (var result in results)
            {
                Console.WriteLine(result.ErrorMessage);
            }
        }
        else
        {
            Console.WriteLine("{0} is valid", value);
        }
    }
}
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928