使用MVC外部的DataAnnotations进行自动模型验证

时间:2014-01-09 08:35:23

标签: c# validation model attributes interception

我正在使用DataAnnotation属性将验证应用于我的模型上的属性,而不是MVC。

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

我已经实现了以下扩展方法来验证模型。

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); });
 }

每次设置不方便的属性时,我都必须调用此Validate()方法:

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

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

我希望当模型状态发生变化时,会在幕后自动调用Validate()方法。有没有人知道如何实现这个目标?

对于奖励积分,有没有人确切知道MVC如何通过DataAnnotations实现此自动验证?

感谢。

1 个答案:

答案 0 :(得分:1)

您可以使用proxies包装类,拦截属性设置器并在每次setter调用后验证对象。对于Castle DynamicProxy,这将是:

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

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

然后,您将使用DynamicProxy而不是operator new创建模型:

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

model.Foo = "bar";

model.Foo = SomeMethod();

MyModel的所有属性必须是虚拟的才能使代理工作:

public class MyModel
{
    public virtual string Foo { get; set; }
}