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.

有帮助吗?

解决方案

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; }
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top