1

编辑
在我正在工作的项目中,存在三层:业务、DataAccess 和 DataTransferObjects。在业务层我需要建立一个验证机制,我想使用DataAnnotation.

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

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

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

4

2 回答 2

1

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

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

我假设您正在为数据访问层使用实体框架或类似的 ORM。

您的 MVC 控制器不直接访问域模型。相反,ViewModel(您称它们为数据传输对象)用于为各个视图适当地构造数据。因此,ViewModel 包含从域模型中抽象出来的数据,域验证规则适用于这些数据。

现在,这一切都很好,并且符合预期。如果您希望覆盖特定视图的域验证规则,您可以将其他 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

于 2013-10-04T13:11:33.700 回答
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);
于 2013-10-04T12:46:07.493 回答