0

I am using DataAnnotation Attributes to apply validation to properties on my model, outside of MVC.

public class MyModel
{
    [Required]
    [CustomValidation]
    public string Foo { get; set; }
}

I have implemented the following extension method to validate the model.

public static void Validate(this object source)
{
    if (source == null)
        throw new ArgumentNullException("source");

    var results = new List<ValidationResult>();
    bool IsValid = Validator.TryValidateObject(source, new ValidationContext(source, null, null), results, true);
    if (!IsValid)
        results.ForEach(r => { throw new ArgumentOutOfRangeException(r.ErrorMessage); });
 }

I have to call this Validate() method every time I set a property which is not convenient:

MyModel model = new MyModel();
model.Foo = "bar";
model.Validate();

model.Foo = SomeMethod();
model.Validate();

I would like that the Validate() method be called automatically behind the scenes when the state of the model changes. Does anyone have any idead on how to achieve this?

For bonus points, does anyone know exactly how MVC achieve this automatic validation via DataAnnotations?

Thanks.

Sam Leach
  • 12,746
  • 9
  • 45
  • 73
  • What makes you believe that MVC does this automatically? Or do you mean the client-side validation? That is accomplished using client-side code (JavaScript), which is generated from the annotations. – Maarten Jan 09 '14 at 08:45
  • And why the `results.ForEach(r => { throw new ... });` ? Since only a single exception will be thrown. – Maarten Jan 09 '14 at 08:46
  • Okay, irrespective of what MVC does. How can I achieve the validation API that I desire (automatic)? – Sam Leach Jan 09 '14 at 08:55
  • "In fact, ASP.net MVC will automatically verify these as part of its model binding." https://www.stum.de/2013/06/17/are-data-annotations-a-sign-of-bad-design/ – Sam Leach Jan 09 '14 at 09:01
  • True, but MVC does not validate after each property change, as you explicitly state in your example. MVC will validate the model as a whole. – Maarten Jan 09 '14 at 10:21

1 Answers1

1

You can wrap your classes with proxies, intercept property setters and validate object after each setter invocation. For Castle DynamicProxy this would be:

public class ValidationInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        invocation.Proceed();

        if (invocation.Method.IsSpecialName && invocation.Method.Name.StartsWith("set_"))
        {
            invocation.InvocationTarget.Validate();
        }
    }
}

Then you would create models with DynamicProxy instead of operator new:

ProxyGenerator proxyGenerator = new ProxyGenerator();
MyModel model = proxyGenerator.CreateClassProxy<MyModel>(new ValidationInterceptor());

model.Foo = "bar";

model.Foo = SomeMethod();

It's important that all properties of MyModel must be virtual in order for proxy to work:

public class MyModel
{
    public virtual string Foo { get; set; }
}
Lifeless
  • 215
  • 1
  • 5