System.ComponentModel.DataAnnotations中的自定义验证层

时间:2013-09-12 15:27:19

标签: c# .net asp.net-mvc asp.net-mvc-3 asp.net-mvc-4

被修改
在我正在工作的项目中,存在三个部分:Business,DataAccess和DataTransferObjects。在业务层中,我需要构建一个验证机制,我想使用DataAnnotation

在Asp.net MVC标准应用程序中,Controller类负责验证,您可以通过ModelState属性访问和编辑验证。

我需要在不使用DataAnnotation类的情况下验证标有Controller的DataTransferObject。相反,我需要在业务层中使用我的自定义类。

到目前为止,我理解所有专注于验证的DataAnnotations都继承自ValidationAttribute。如何动态验证类并将错误消息放在Dictionary<string,string>中? (像Controller.ModelState验证模型并构建错误字典消息)。

2 个答案:

答案 0 :(得分:1)

您可以尝试这样的事情

using System.ComponentModel.DataAnnotations;

public static class MyValidatorExtensions
{
    public static bool Validate(this object obj, out List<ValidationResult> results)
    {
        ValidationContext context = new ValidationContext(obj, null, null);
        results = new List<ValidationResult>();

        return Validator.TryValidateObject(obj, context, results, true);
    }
}

现在,您可以将其称为每个对象的扩展方法。

var validationErrors = new List<ValidationResult>();
bool valid = new Person().Validate(out validationErrors);

答案 1 :(得分:1)

根据您对应用程序的描述,它似乎是一个相当标准的应用程序,您不应该按照预期的方式使用DataAnnotations。我将在这里做一些关于应用程序结构的假设(填写缺失的细节),并解释我认为你可以使用DataAnnotations进行业务验证。

我假设Business层由反映您的应用程序域的对象模型组成。域模型中的每个对象都公开了实现业务规则的属性和可能的​​方法。这是您要在其中编写验证代码的应用程序层,实际上它是域验证规则的适当位置。

我假设您正在为数据访问层使用Entity Framework或类似的ORM。

您的MVC控制器不直接访问域模型。相反,ViewModels(您称之为数据传输对象)用于为各个视图适当地构造数据。因此,ViewModels包含从域模型中提取的数据,域验证规则适用于该模型。

现在,这一切都很好,并且按照预期。如果要覆盖特定视图的域验证规则,可以将其他DataAnnotations添加到ViewModel中的属性,但这不是必需的。但是,虽然客户端验证将由MVC针对视图模型属性执行,但它不适用于底层域对象。

因此,使用ModelState.IsValid方法在这种情况下不起作用。要对域模型执行验证,可以在尝试保存对象后捕获DbEntityValidationException

[HttpPost]
public ActionResult Edit(int id, BlogView view)
{
    try
    {
        Blog blog = Mapper.Map(view);      //map view model to domain object using eg. Automapper
        db.Entry(blog).State = EntityState.Modified;
        db.SaveChanges();
       return RedirectToAction("Index");
    }
    catch(DbEntityValidationException ex)
    {
        var error = ex.EntityValidationErrors.First().ValidationErrors.First();
        this.ModelState.AddModelError(error.PropertyName, error.ErrorMessage);
        return View();
    }
}

如果您不想依赖EntityFramework抛出的异常,可以使用DbContext.GetValidationErrors()方法明确触发验证:

foreach (var validationResults in db.GetValidationErrors())
{
    foreach (var error in validationResults.ValidationErrors)
    {
        Debug.WriteLine("Entity Property: {0}, Error {1}",
                          error.PropertyName,error.ErrorMessage);
    }
}

或者,您的域对象可以实现IValidatableObject接口,并使用其Validate()方法:

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    if (Title == BloggerName)
    {
        yield return new ValidationResult
         ("Blog Title cannot match Blogger Name", new[] { "Title", “BloggerName” });
    }
}

有关详细信息,请参阅http://msdn.microsoft.com/en-gb/data/gg193959.aspx