Question

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.

Was it helpful?

Solution

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; }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top