被修改
在我正在工作的项目中,存在三个部分:Business,DataAccess和DataTransferObjects。在业务层中,我需要构建一个验证机制,我想使用DataAnnotation
。
在Asp.net MVC标准应用程序中,Controller
类负责验证,您可以通过ModelState
属性访问和编辑验证。
我需要在不使用DataAnnotation
类的情况下验证标有Controller
的DataTransferObject。相反,我需要在业务层中使用我的自定义类。
到目前为止,我理解所有专注于验证的DataAnnotations都继承自ValidationAttribute
。如何动态验证类并将错误消息放在Dictionary<string,string>
中? (像Controller.ModelState
验证模型并构建错误字典消息)。
答案 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。